From 6f1151740487de7bca0d42459937a6a0a1bb415b Mon Sep 17 00:00:00 2001 From: kaleidot725 Date: Tue, 31 Dec 2024 14:16:21 +0900 Subject: [PATCH 1/6] feat: add power button --- build.gradle.kts | 1 + .../kotlin/jp/kaleidot725/adbpad/Main.kt | 45 ++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index ca04fa8..b67ad72 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,6 +37,7 @@ kotlin { implementation(libs.ktor.core) implementation(libs.ktor.client.okhttp) implementation(libs.jSystemThemeDetectorVer) + implementation("com.composables:icons-lucide:1.0.0") } } val jvmTest by getting { diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt index a8ee73e..7979dab 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt @@ -1,13 +1,13 @@ import androidx.compose.animation.Crossfade import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.shape.RoundedCornerShape @@ -37,6 +37,9 @@ import androidx.compose.ui.window.Window import androidx.compose.ui.window.WindowScope import androidx.compose.ui.window.WindowState import androidx.compose.ui.window.application +import com.composables.icons.lucide.Lucide +import com.composables.icons.lucide.Power +import com.composables.icons.lucide.PowerOff import jp.kaleidot725.adbpad.MainCategory import jp.kaleidot725.adbpad.MainState import jp.kaleidot725.adbpad.MainStateHolder @@ -268,7 +271,45 @@ private fun TitleBarView( ) } - Row(Modifier.align(Alignment.CenterEnd).wrapContentSize().padding(4.dp)) { + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp), + modifier = Modifier.align(Alignment.CenterEnd).wrapContentSize().padding(4.dp) + ) { + Box( + modifier = + Modifier + .size(28.dp) + .clip(RoundedCornerShape(4.dp)) + .clickableBackground(isDarker = true) + .clickable { onRefresh() } + .padding(4.dp), + ) { + Icon( + imageVector = Lucide.Power, + tint = MaterialTheme.colors.onBackground, + contentDescription = null, + modifier = Modifier.align(Alignment.Center), + ) + } + + Box( + modifier = + Modifier + .size(28.dp) + .clip(RoundedCornerShape(4.dp)) + .clickableBackground(isDarker = true) + .clickable { onRefresh() } + .padding(4.dp) + , + ) { + Icon( + imageVector = Lucide.PowerOff, + tint = MaterialTheme.colors.onBackground, + contentDescription = null, + modifier = Modifier.align(Alignment.Center), + ) + } + var isPress: Boolean by remember { mutableStateOf(false) } val degrees: Float by animateFloatAsState(if (isPress) -90f else 0f) Box( From 30e2f182c71f517fe89da96370fc855ea9696c12 Mon Sep 17 00:00:00 2001 From: kaleidot725 Date: Wed, 1 Jan 2025 13:19:53 +0900 Subject: [PATCH 2/6] feat: add device command features --- .idea/artifacts/adbpad_jvm_1_3_0.xml | 4 +- .../kotlin/jp/kaleidot725/adbpad/Main.kt | 127 +++++++++--------- .../adbpad/ui/component/CommandIconButton.kt | 57 ++++++++ .../adbpad/ui/component/CommandIconDivider.kt | 43 ++++++ 4 files changed, 168 insertions(+), 63 deletions(-) create mode 100644 src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconButton.kt create mode 100644 src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconDivider.kt diff --git a/.idea/artifacts/adbpad_jvm_1_3_0.xml b/.idea/artifacts/adbpad_jvm_1_3_0.xml index e7e1f78..fc6df59 100644 --- a/.idea/artifacts/adbpad_jvm_1_3_0.xml +++ b/.idea/artifacts/adbpad_jvm_1_3_0.xml @@ -1,8 +1,6 @@ $PROJECT_DIR$/build/libs - - - + \ No newline at end of file diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt index 7979dab..ac341a5 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt @@ -1,22 +1,17 @@ import androidx.compose.animation.Crossfade import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.layout.wrapContentWidth -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Colors -import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.RestartAlt import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState @@ -27,8 +22,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.rotate import androidx.compose.ui.input.pointer.PointerEventType import androidx.compose.ui.input.pointer.onPointerEvent import androidx.compose.ui.res.painterResource @@ -37,9 +30,16 @@ import androidx.compose.ui.window.Window import androidx.compose.ui.window.WindowScope import androidx.compose.ui.window.WindowState import androidx.compose.ui.window.application +import com.composables.icons.lucide.Camera +import com.composables.icons.lucide.Circle import com.composables.icons.lucide.Lucide import com.composables.icons.lucide.Power import com.composables.icons.lucide.PowerOff +import com.composables.icons.lucide.RefreshCcw +import com.composables.icons.lucide.Square +import com.composables.icons.lucide.Triangle +import com.composables.icons.lucide.Volume1 +import com.composables.icons.lucide.Volume2 import jp.kaleidot725.adbpad.MainCategory import jp.kaleidot725.adbpad.MainState import jp.kaleidot725.adbpad.MainStateHolder @@ -51,7 +51,8 @@ import jp.kaleidot725.adbpad.domain.model.language.Language import jp.kaleidot725.adbpad.domain.model.setting.WindowSize import jp.kaleidot725.adbpad.domain.model.setting.getWindowSize import jp.kaleidot725.adbpad.repository.di.repositoryModule -import jp.kaleidot725.adbpad.ui.common.resource.clickableBackground +import jp.kaleidot725.adbpad.ui.component.CommandIconButton +import jp.kaleidot725.adbpad.ui.component.CommandIconDivider import jp.kaleidot725.adbpad.ui.component.NavigationRail import jp.kaleidot725.adbpad.ui.di.stateHolderModule import jp.kaleidot725.adbpad.ui.screen.CommandScreen @@ -259,7 +260,7 @@ private fun TitleBarView( ) { Surface( color = MaterialTheme.colors.background, - modifier = Modifier.fillMaxWidth(), + modifier = Modifier.fillMaxWidth().height(40.dp), ) { Box { Row(Modifier.align(Alignment.CenterStart).wrapContentSize()) { @@ -275,60 +276,66 @@ private fun TitleBarView( horizontalArrangement = Arrangement.spacedBy(4.dp), modifier = Modifier.align(Alignment.CenterEnd).wrapContentSize().padding(4.dp) ) { - Box( - modifier = - Modifier - .size(28.dp) - .clip(RoundedCornerShape(4.dp)) - .clickableBackground(isDarker = true) - .clickable { onRefresh() } - .padding(4.dp), - ) { - Icon( - imageVector = Lucide.Power, - tint = MaterialTheme.colors.onBackground, - contentDescription = null, - modifier = Modifier.align(Alignment.Center), - ) - } + CommandIconButton( + image = Lucide.Power, + onClick = {}, + padding = 2.dp + ) - Box( - modifier = - Modifier - .size(28.dp) - .clip(RoundedCornerShape(4.dp)) - .clickableBackground(isDarker = true) - .clickable { onRefresh() } - .padding(4.dp) - , - ) { - Icon( - imageVector = Lucide.PowerOff, - tint = MaterialTheme.colors.onBackground, - contentDescription = null, - modifier = Modifier.align(Alignment.Center), - ) - } + CommandIconButton( + image = Lucide.PowerOff, + onClick = {}, + padding = 2.dp + ) + + CommandIconButton( + image = Lucide.Volume2, + onClick = {} + ) + + CommandIconButton( + image = Lucide.Volume1, + onClick = {} + ) + + CommandIconButton( + image = Lucide.Camera, + onClick = {}, + padding = 2.dp + ) + + CommandIconButton( + image = Lucide.Triangle, + degrees = -90f, + onClick = {}, + padding = 2.dp + ) + + CommandIconButton( + image = Lucide.Circle, + onClick = {}, + padding = 2.dp + ) + + CommandIconButton( + image = Lucide.Square, + onClick = {}, + padding = 2.dp + ) + + CommandIconDivider() var isPress: Boolean by remember { mutableStateOf(false) } val degrees: Float by animateFloatAsState(if (isPress) -90f else 0f) - Box( - modifier = - Modifier - .size(28.dp) - .clip(RoundedCornerShape(4.dp)) - .clickableBackground(isDarker = true) - .onPointerEvent(PointerEventType.Press) { isPress = true } - .onPointerEvent(PointerEventType.Release) { isPress = false } - .clickable { onRefresh() }, - ) { - Icon( - imageVector = Icons.Default.RestartAlt, - tint = MaterialTheme.colors.onBackground, - contentDescription = null, - modifier = Modifier.rotate(degrees).align(Alignment.Center), - ) - } + CommandIconButton( + modifier = Modifier + .onPointerEvent(PointerEventType.Press) { isPress = true } + .onPointerEvent(PointerEventType.Release) { isPress = false }, + image = Lucide.RefreshCcw, + degrees = degrees, + onClick = { onRefresh() }, + padding = 2.dp + ) } } } diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconButton.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconButton.kt new file mode 100644 index 0000000..5be7aa9 --- /dev/null +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconButton.kt @@ -0,0 +1,57 @@ +package jp.kaleidot725.adbpad.ui.component + +import androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.composables.icons.lucide.Lucide +import com.composables.icons.lucide.Power +import jp.kaleidot725.adbpad.ui.common.resource.clickableBackground +import org.checkerframework.checker.units.qual.degrees + +@Composable +fun CommandIconButton( + modifier: Modifier = Modifier, + image: ImageVector, + onClick: () -> Unit, + degrees: Float = 0f, + padding: Dp = 0.dp +) { + Box( + modifier = + modifier + .size(28.dp) + .clip(RoundedCornerShape(4.dp)) + .clickableBackground(isDarker = true) + .clickable { onClick() } + .padding(4.dp + padding), + ) { + Icon( + imageVector = image, + tint = MaterialTheme.colors.onBackground, + contentDescription = null, + modifier = Modifier.align(Alignment.Center).rotate(degrees), + ) + } +} + +@Preview +@Composable +private fun Preview() { + CommandIconButton( + image = Lucide.Power, + onClick = {} + ) +} \ No newline at end of file diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconDivider.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconDivider.kt new file mode 100644 index 0000000..2123308 --- /dev/null +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconDivider.kt @@ -0,0 +1,43 @@ +package jp.kaleidot725.adbpad.ui.component + +import androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Divider +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.unit.dp +import com.composables.icons.lucide.Lucide +import com.composables.icons.lucide.Power +import jp.kaleidot725.adbpad.ui.common.resource.clickableBackground +import org.checkerframework.checker.units.qual.degrees + +@Composable +fun CommandIconDivider( + modifier: Modifier = Modifier, +) { + Divider( + modifier = modifier + .width(9.dp) + .fillMaxHeight() + .padding(vertical = 6.dp, horizontal = 4.dp) + .background(MaterialTheme.colors.onBackground) + ) +} + +@Preview +@Composable +private fun Preview() { + CommandIconDivider() +} \ No newline at end of file From d59e3c57ddda65766dc3562a1b2c3a1d8ee7d70e Mon Sep 17 00:00:00 2001 From: kaleidot725 Date: Wed, 1 Jan 2025 22:04:03 +0900 Subject: [PATCH 3/6] feat: create top section state holder --- .../kotlin/jp/kaleidot725/adbpad/Main.kt | 128 +---------------- .../jp/kaleidot725/adbpad/MainStateHolder.kt | 45 +----- .../adbpad/ui/di/StateHolderModule.kt | 13 +- .../adbpad/ui/section/TopSection.kt | 130 ++++++++++++++++++ .../kaleidot725/adbpad/ui/section/TopState.kt | 8 ++ .../adbpad/ui/section/TopStateHolder.kt | 84 +++++++++++ 6 files changed, 242 insertions(+), 166 deletions(-) create mode 100644 src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopSection.kt create mode 100644 src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopState.kt create mode 100644 src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopStateHolder.kt diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt index ac341a5..a1b82e4 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt @@ -1,14 +1,5 @@ import androidx.compose.animation.Crossfade -import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.wrapContentSize -import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.material.Colors import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface @@ -18,51 +9,32 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier -import androidx.compose.ui.input.pointer.PointerEventType -import androidx.compose.ui.input.pointer.onPointerEvent import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Window import androidx.compose.ui.window.WindowScope import androidx.compose.ui.window.WindowState import androidx.compose.ui.window.application -import com.composables.icons.lucide.Camera -import com.composables.icons.lucide.Circle -import com.composables.icons.lucide.Lucide -import com.composables.icons.lucide.Power -import com.composables.icons.lucide.PowerOff -import com.composables.icons.lucide.RefreshCcw -import com.composables.icons.lucide.Square -import com.composables.icons.lucide.Triangle -import com.composables.icons.lucide.Volume1 -import com.composables.icons.lucide.Volume2 import jp.kaleidot725.adbpad.MainCategory -import jp.kaleidot725.adbpad.MainState import jp.kaleidot725.adbpad.MainStateHolder import jp.kaleidot725.adbpad.domain.di.domainModule import jp.kaleidot725.adbpad.domain.model.Dialog import jp.kaleidot725.adbpad.domain.model.UserColor -import jp.kaleidot725.adbpad.domain.model.device.Device import jp.kaleidot725.adbpad.domain.model.language.Language import jp.kaleidot725.adbpad.domain.model.setting.WindowSize import jp.kaleidot725.adbpad.domain.model.setting.getWindowSize import jp.kaleidot725.adbpad.repository.di.repositoryModule -import jp.kaleidot725.adbpad.ui.component.CommandIconButton -import jp.kaleidot725.adbpad.ui.component.CommandIconDivider import jp.kaleidot725.adbpad.ui.component.NavigationRail import jp.kaleidot725.adbpad.ui.di.stateHolderModule import jp.kaleidot725.adbpad.ui.screen.CommandScreen import jp.kaleidot725.adbpad.ui.screen.ScreenLayout import jp.kaleidot725.adbpad.ui.screen.error.AdbErrorScreen -import jp.kaleidot725.adbpad.ui.screen.menu.component.DropDownDeviceMenu import jp.kaleidot725.adbpad.ui.screen.screenshot.ScreenshotScreen import jp.kaleidot725.adbpad.ui.screen.setting.SettingScreen import jp.kaleidot725.adbpad.ui.screen.setting.SettingStateHolder import jp.kaleidot725.adbpad.ui.screen.text.TextCommandScreen +import jp.kaleidot725.adbpad.ui.section.TopSection import org.koin.core.context.GlobalContext import org.koin.core.context.startKoin @@ -116,9 +88,11 @@ fun WindowScope.App(mainStateHolder: MainStateHolder) { Surface { ScreenLayout( top = { - TitleBarView( - state = state, - onSelectDevice = mainStateHolder::selectDevice, + val topStateHolder = mainStateHolder.topStateHolder + val topState by topStateHolder.state.collectAsState() + TopSection( + state = topState, + onSelectDevice = topStateHolder::selectDevice, onRefresh = mainStateHolder::refresh, ) }, @@ -251,96 +225,6 @@ fun WindowScope.App(mainStateHolder: MainStateHolder) { } } -@OptIn(ExperimentalComposeUiApi::class) -@Composable -private fun TitleBarView( - state: MainState, - onSelectDevice: (Device) -> Unit, - onRefresh: () -> Unit, -) { - Surface( - color = MaterialTheme.colors.background, - modifier = Modifier.fillMaxWidth().height(40.dp), - ) { - Box { - Row(Modifier.align(Alignment.CenterStart).wrapContentSize()) { - DropDownDeviceMenu( - devices = state.devices, - selectedDevice = state.selectedDevice, - onSelectDevice = onSelectDevice, - modifier = Modifier.wrapContentWidth(), - ) - } - - Row( - horizontalArrangement = Arrangement.spacedBy(4.dp), - modifier = Modifier.align(Alignment.CenterEnd).wrapContentSize().padding(4.dp) - ) { - CommandIconButton( - image = Lucide.Power, - onClick = {}, - padding = 2.dp - ) - - CommandIconButton( - image = Lucide.PowerOff, - onClick = {}, - padding = 2.dp - ) - - CommandIconButton( - image = Lucide.Volume2, - onClick = {} - ) - - CommandIconButton( - image = Lucide.Volume1, - onClick = {} - ) - - CommandIconButton( - image = Lucide.Camera, - onClick = {}, - padding = 2.dp - ) - - CommandIconButton( - image = Lucide.Triangle, - degrees = -90f, - onClick = {}, - padding = 2.dp - ) - - CommandIconButton( - image = Lucide.Circle, - onClick = {}, - padding = 2.dp - ) - - CommandIconButton( - image = Lucide.Square, - onClick = {}, - padding = 2.dp - ) - - CommandIconDivider() - - var isPress: Boolean by remember { mutableStateOf(false) } - val degrees: Float by animateFloatAsState(if (isPress) -90f else 0f) - CommandIconButton( - modifier = Modifier - .onPointerEvent(PointerEventType.Press) { isPress = true } - .onPointerEvent(PointerEventType.Release) { isPress = false }, - image = Lucide.RefreshCcw, - degrees = degrees, - onClick = { onRefresh() }, - padding = 2.dp - ) - } - } - } -} - private val LightColors = Colors( primary = UserColor.Light.PRIMARY, diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/MainStateHolder.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/MainStateHolder.kt index b651b67..27885e0 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/MainStateHolder.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/MainStateHolder.kt @@ -18,6 +18,7 @@ import jp.kaleidot725.adbpad.ui.common.ParentStateHolder import jp.kaleidot725.adbpad.ui.screen.command.CommandStateHolder import jp.kaleidot725.adbpad.ui.screen.screenshot.ScreenshotStateHolder import jp.kaleidot725.adbpad.ui.screen.text.TextCommandStateHolder +import jp.kaleidot725.adbpad.ui.section.TopStateHolder import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -37,15 +38,13 @@ class MainStateHolder( val commandStateHolder: CommandStateHolder, val textCommandStateHolder: TextCommandStateHolder, val screenshotStateHolder: ScreenshotStateHolder, + val topStateHolder: TopStateHolder, private val getWindowSizeUseCase: GetWindowSizeUseCase, private val saveWindowSizeUseCase: SaveWindowSizeUseCase, private val startAdbUseCase: StartAdbUseCase, private val getDarkModeFlowUseCase: GetDarkModeFlowUseCase, private val getLanguageUseCase: GetLanguageUseCase, private val refreshUseCase: RefreshUseCase, - private val updateDevicesUseCase: UpdateDevicesUseCase, - private val getSelectedDeviceFlowUseCase: GetSelectedDeviceFlowUseCase, - private val selectDeviceUseCase: SelectDeviceUseCase, ) : ParentStateHolder { private val coroutineScope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main + Dispatchers.IO) private val language: MutableStateFlow = MutableStateFlow(Language.Type.ENGLISH) @@ -54,24 +53,14 @@ class MainStateHolder( private val dialog: MutableStateFlow = MutableStateFlow(null) private val category: MutableStateFlow = MutableStateFlow(MainCategory.Command) - private var deviceJob: Job? = null - private val _devices: MutableStateFlow> = MutableStateFlow(emptyList()) - private val devices: StateFlow> = _devices.asStateFlow() - - private var selectedDeviceJob: Job? = null - private val _selectedDevice: MutableStateFlow = MutableStateFlow(null) - private val selectedDevice: StateFlow = _selectedDevice.asStateFlow() - val state: StateFlow = - combine(language, isDark, windowSize, dialog, category, devices, selectedDevice) { data -> + combine(language, isDark, windowSize, dialog, category) { data -> MainState( data[0] as Language.Type, data[1] as Boolean?, data[2] as WindowSize, data[3] as Dialog?, data[4] as MainCategory, - data[5] as List, - data[6] as Device?, ) }.stateIn(coroutineScope, SharingStarted.WhileSubscribed(), MainState()) @@ -80,6 +69,7 @@ class MainStateHolder( commandStateHolder, textCommandStateHolder, screenshotStateHolder, + topStateHolder, ) init { @@ -87,7 +77,6 @@ class MainStateHolder( restoreWindowSize() checkAdbServer() syncLanguage() - collectDevices() } override fun setup() { @@ -98,7 +87,6 @@ class MainStateHolder( startSyncDarkMode() checkAdbServer() syncLanguage() - collectDevices() refreshUseCase() children.forEach { it.refresh() } } @@ -119,12 +107,6 @@ class MainStateHolder( this.category.value = category } - fun selectDevice(device: Device) { - coroutineScope.launch { - selectDeviceUseCase(device) - } - } - private var themeFlowJob: Job? = null private fun startSyncDarkMode() { @@ -163,23 +145,4 @@ class MainStateHolder( language.value = type } } - - private fun collectDevices() { - deviceJob?.cancel() - deviceJob = - coroutineScope.launch { - while (isActive) { - _devices.value = updateDevicesUseCase() - delay(1000) - } - } - - selectedDeviceJob?.cancel() - selectedDeviceJob = - coroutineScope.launch { - getSelectedDeviceFlowUseCase().collect { - _selectedDevice.value = it - } - } - } } diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/di/StateHolderModule.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/di/StateHolderModule.kt index f30f43f..474a92a 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/di/StateHolderModule.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/di/StateHolderModule.kt @@ -5,6 +5,7 @@ import jp.kaleidot725.adbpad.ui.screen.command.CommandStateHolder import jp.kaleidot725.adbpad.ui.screen.screenshot.ScreenshotStateHolder import jp.kaleidot725.adbpad.ui.screen.setting.SettingStateHolder import jp.kaleidot725.adbpad.ui.screen.text.TextCommandStateHolder +import jp.kaleidot725.adbpad.ui.section.TopStateHolder import org.koin.dsl.module val stateHolderModule = @@ -51,6 +52,14 @@ val stateHolderModule = ) } + factory { + TopStateHolder( + updateDevicesUseCase = get(), + getSelectedDeviceFlowUseCase = get(), + selectDeviceUseCase = get() + ) + } + factory { MainStateHolder( commandStateHolder = get(), @@ -62,9 +71,7 @@ val stateHolderModule = getDarkModeFlowUseCase = get(), getLanguageUseCase = get(), refreshUseCase = get(), - getSelectedDeviceFlowUseCase = get(), - updateDevicesUseCase = get(), - selectDeviceUseCase = get(), + topStateHolder = get() ) } } diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopSection.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopSection.kt new file mode 100644 index 0000000..882dae8 --- /dev/null +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopSection.kt @@ -0,0 +1,130 @@ +package jp.kaleidot725.adbpad.ui.section + +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.pointer.PointerEventType +import androidx.compose.ui.input.pointer.onPointerEvent +import androidx.compose.ui.unit.dp +import com.composables.icons.lucide.Camera +import com.composables.icons.lucide.Circle +import com.composables.icons.lucide.Lucide +import com.composables.icons.lucide.Power +import com.composables.icons.lucide.PowerOff +import com.composables.icons.lucide.RefreshCcw +import com.composables.icons.lucide.Square +import com.composables.icons.lucide.Triangle +import com.composables.icons.lucide.Volume1 +import com.composables.icons.lucide.Volume2 +import jp.kaleidot725.adbpad.MainState +import jp.kaleidot725.adbpad.domain.model.device.Device +import jp.kaleidot725.adbpad.ui.component.CommandIconButton +import jp.kaleidot725.adbpad.ui.component.CommandIconDivider +import jp.kaleidot725.adbpad.ui.screen.menu.component.DropDownDeviceMenu + +@OptIn(ExperimentalComposeUiApi::class) +@Composable +fun TopSection( + state: TopState, + onSelectDevice: (Device) -> Unit, + onRefresh: () -> Unit, +) { + var isPress: Boolean by remember { mutableStateOf(false) } + val degrees: Float by animateFloatAsState(if (isPress) -90f else 0f) + + Surface( + color = MaterialTheme.colors.background, + modifier = Modifier.fillMaxWidth().height(40.dp), + ) { + Box { + Row(Modifier.align(Alignment.CenterStart).wrapContentSize()) { + DropDownDeviceMenu( + devices = state.devices, + selectedDevice = state.selectedDevice, + onSelectDevice = onSelectDevice, + modifier = Modifier.wrapContentWidth(), + ) + } + + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp), + modifier = Modifier.align(Alignment.CenterEnd).wrapContentSize().padding(4.dp) + ) { + CommandIconButton( + image = Lucide.Power, + onClick = {}, + padding = 2.dp + ) + + CommandIconButton( + image = Lucide.PowerOff, + onClick = {}, + padding = 2.dp + ) + + CommandIconButton( + image = Lucide.Volume2, + onClick = {} + ) + + CommandIconButton( + image = Lucide.Volume1, + onClick = {} + ) + + CommandIconButton( + image = Lucide.Camera, + onClick = {}, + padding = 2.dp + ) + + CommandIconButton( + image = Lucide.Triangle, + degrees = -90f, + onClick = {}, + padding = 2.dp + ) + + CommandIconButton( + image = Lucide.Circle, + onClick = {}, + padding = 2.dp + ) + + CommandIconButton( + image = Lucide.Square, + onClick = {}, + padding = 2.dp + ) + + CommandIconDivider() + + CommandIconButton( + modifier = Modifier + .onPointerEvent(PointerEventType.Press) { isPress = true } + .onPointerEvent(PointerEventType.Release) { isPress = false }, + image = Lucide.RefreshCcw, + degrees = degrees, + onClick = { onRefresh() }, + padding = 2.dp + ) + } + } + } +} diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopState.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopState.kt new file mode 100644 index 0000000..0dd8e55 --- /dev/null +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopState.kt @@ -0,0 +1,8 @@ +package jp.kaleidot725.adbpad.ui.section + +import jp.kaleidot725.adbpad.domain.model.device.Device + +data class TopState( + val devices: List = emptyList(), + val selectedDevice: Device? = null, +) \ No newline at end of file diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopStateHolder.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopStateHolder.kt new file mode 100644 index 0000000..546cd75 --- /dev/null +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopStateHolder.kt @@ -0,0 +1,84 @@ +package jp.kaleidot725.adbpad.ui.section + +import jp.kaleidot725.adbpad.domain.model.device.Device +import jp.kaleidot725.adbpad.domain.usecase.device.GetSelectedDeviceFlowUseCase +import jp.kaleidot725.adbpad.domain.usecase.device.SelectDeviceUseCase +import jp.kaleidot725.adbpad.domain.usecase.device.UpdateDevicesUseCase +import jp.kaleidot725.adbpad.ui.common.ChildStateHolder +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch + +class TopStateHolder( + private val updateDevicesUseCase: UpdateDevicesUseCase, + private val getSelectedDeviceFlowUseCase: GetSelectedDeviceFlowUseCase, + private val selectDeviceUseCase: SelectDeviceUseCase, +) : ChildStateHolder { + private val coroutineScope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main + Dispatchers.IO) + private var deviceJob: Job? = null + private val _devices: MutableStateFlow> = MutableStateFlow(emptyList()) + private val devices: StateFlow> = _devices.asStateFlow() + + private var selectedDeviceJob: Job? = null + private val _selectedDevice: MutableStateFlow = MutableStateFlow(null) + private val selectedDevice: StateFlow = _selectedDevice.asStateFlow() + + override val state: StateFlow = combine(devices, selectedDevice) { devices, selectedDevice -> + TopState( + devices = devices, + selectedDevice = selectedDevice + ) + }.stateIn( + scope = coroutineScope, + started = SharingStarted.WhileSubscribed(), + initialValue = TopState() + ) + + override fun setup() { + collectDevices() + } + + override fun refresh() { + collectDevices() + } + + override fun dispose() { + coroutineScope.cancel() + } + + fun selectDevice(device: Device) { + coroutineScope.launch { + selectDeviceUseCase(device) + } + } + + private fun collectDevices() { + deviceJob?.cancel() + deviceJob = + coroutineScope.launch { + while (isActive) { + _devices.value = updateDevicesUseCase() + delay(1000) + } + } + + selectedDeviceJob?.cancel() + selectedDeviceJob = + coroutineScope.launch { + getSelectedDeviceFlowUseCase().collect { + _selectedDevice.value = it + } + } + } +} From e0ddb18c0cf0549c9dea6ccecde421ed2e7dda5b Mon Sep 17 00:00:00 2001 From: kaleidot725 Date: Thu, 2 Jan 2025 22:24:44 +0900 Subject: [PATCH 4/6] feat: impl device controller command --- .../kotlin/jp/kaleidot725/adbpad/Main.kt | 1 + .../jp/kaleidot725/adbpad/MainStateHolder.kt | 7 --- .../adbpad/domain/di/DomainModule.kt | 4 ++ .../model/command/DeviceControlCommand.kt | 56 +++++++++++++++++++ .../DeviceControlCommandRepository.kt | 14 +++++ .../ExecuteDeviceControlCommandUseCase.kt | 19 +++++++ .../adbpad/repository/di/RepositoryModule.kt | 5 ++ .../DeviceControlCommandRepositoryImpl.kt | 38 +++++++++++++ .../adbpad/ui/component/CommandIconButton.kt | 6 +- .../adbpad/ui/component/CommandIconDivider.kt | 29 +++------- .../adbpad/ui/di/StateHolderModule.kt | 5 +- .../adbpad/ui/section/TopSection.kt | 50 ++++++++--------- .../kaleidot725/adbpad/ui/section/TopState.kt | 2 +- .../adbpad/ui/section/TopStateHolder.kt | 32 ++++++++--- 14 files changed, 198 insertions(+), 70 deletions(-) create mode 100644 src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/command/DeviceControlCommand.kt create mode 100644 src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/repository/DeviceControlCommandRepository.kt create mode 100644 src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/usecase/command/ExecuteDeviceControlCommandUseCase.kt create mode 100644 src/jvmMain/kotlin/jp/kaleidot725/adbpad/repository/impl/DeviceControlCommandRepositoryImpl.kt diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt index a1b82e4..d90bda0 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt @@ -92,6 +92,7 @@ fun WindowScope.App(mainStateHolder: MainStateHolder) { val topState by topStateHolder.state.collectAsState() TopSection( state = topState, + onExecuteCommand = topStateHolder::executeCommand, onSelectDevice = topStateHolder::selectDevice, onRefresh = mainStateHolder::refresh, ) diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/MainStateHolder.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/MainStateHolder.kt index 27885e0..d8a238d 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/MainStateHolder.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/MainStateHolder.kt @@ -1,13 +1,9 @@ package jp.kaleidot725.adbpad import jp.kaleidot725.adbpad.domain.model.Dialog -import jp.kaleidot725.adbpad.domain.model.device.Device import jp.kaleidot725.adbpad.domain.model.language.Language import jp.kaleidot725.adbpad.domain.model.setting.WindowSize import jp.kaleidot725.adbpad.domain.usecase.adb.StartAdbUseCase -import jp.kaleidot725.adbpad.domain.usecase.device.GetSelectedDeviceFlowUseCase -import jp.kaleidot725.adbpad.domain.usecase.device.SelectDeviceUseCase -import jp.kaleidot725.adbpad.domain.usecase.device.UpdateDevicesUseCase import jp.kaleidot725.adbpad.domain.usecase.language.GetLanguageUseCase import jp.kaleidot725.adbpad.domain.usecase.refresh.RefreshUseCase import jp.kaleidot725.adbpad.domain.usecase.theme.GetDarkModeFlowUseCase @@ -23,15 +19,12 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.isActive import kotlinx.coroutines.launch class MainStateHolder( diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/di/DomainModule.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/di/DomainModule.kt index 957a404..dbfe6c0 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/di/DomainModule.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/di/DomainModule.kt @@ -5,6 +5,7 @@ import jp.kaleidot725.adbpad.domain.usecase.adb.StartAdbUseCase import jp.kaleidot725.adbpad.domain.usecase.appearance.GetAppearanceUseCase import jp.kaleidot725.adbpad.domain.usecase.appearance.SaveAppearanceUseCase import jp.kaleidot725.adbpad.domain.usecase.command.ExecuteCommandUseCase +import jp.kaleidot725.adbpad.domain.usecase.command.ExecuteDeviceControlCommandUseCase import jp.kaleidot725.adbpad.domain.usecase.command.GetNormalCommandGroup import jp.kaleidot725.adbpad.domain.usecase.device.GetSelectedDeviceFlowUseCase import jp.kaleidot725.adbpad.domain.usecase.device.SelectDeviceUseCase @@ -40,6 +41,9 @@ val domainModule = factory { ExecuteCommandUseCase(get()) } + factory { + ExecuteDeviceControlCommandUseCase(get()) + } factory { GetNormalCommandGroup(get()) } diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/command/DeviceControlCommand.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/command/DeviceControlCommand.kt new file mode 100644 index 0000000..4a90ee7 --- /dev/null +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/command/DeviceControlCommand.kt @@ -0,0 +1,56 @@ +package jp.kaleidot725.adbpad.domain.model.command + +import com.malinskiy.adam.request.shell.v1.ShellCommandRequest + +interface DeviceControlCommand { + val requests: List + + data object Power : DeviceControlCommand { + override val requests: List = + listOf( + ShellCommandRequest("input keyevent 26"), + ) + } + + data object VolumeUp : DeviceControlCommand { + override val requests: List = + listOf( + ShellCommandRequest("input keyevent 24"), + ) + } + + data object VolumeDown : DeviceControlCommand { + override val requests: List = + listOf( + ShellCommandRequest("input keyevent 25"), + ) + } + + data object VolumeMute : DeviceControlCommand { + override val requests: List = + listOf( + ShellCommandRequest("input keyevent 164"), + ) + } + + data object Back : DeviceControlCommand { + override val requests: List = + listOf( + ShellCommandRequest("input keyevent 4"), + ) + } + + data object Home : DeviceControlCommand { + override val requests: List = + listOf( + ShellCommandRequest("input keyevent 3"), + ) + } + + data object Recents : DeviceControlCommand { + override val requests: List = + listOf( + ShellCommandRequest("input keyevent 187"), + ) + } +} diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/repository/DeviceControlCommandRepository.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/repository/DeviceControlCommandRepository.kt new file mode 100644 index 0000000..6505be7 --- /dev/null +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/repository/DeviceControlCommandRepository.kt @@ -0,0 +1,14 @@ +package jp.kaleidot725.adbpad.domain.repository + +import jp.kaleidot725.adbpad.domain.model.command.DeviceControlCommand +import jp.kaleidot725.adbpad.domain.model.device.Device + +interface DeviceControlCommandRepository { + suspend fun sendCommand( + device: Device, + command: DeviceControlCommand, + onStart: suspend () -> Unit = {}, + onComplete: suspend () -> Unit = {}, + onFailed: suspend () -> Unit = {}, + ) +} diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/usecase/command/ExecuteDeviceControlCommandUseCase.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/usecase/command/ExecuteDeviceControlCommandUseCase.kt new file mode 100644 index 0000000..9ef2a32 --- /dev/null +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/usecase/command/ExecuteDeviceControlCommandUseCase.kt @@ -0,0 +1,19 @@ +package jp.kaleidot725.adbpad.domain.usecase.command + +import jp.kaleidot725.adbpad.domain.model.command.DeviceControlCommand +import jp.kaleidot725.adbpad.domain.model.device.Device +import jp.kaleidot725.adbpad.domain.repository.DeviceControlCommandRepository + +class ExecuteDeviceControlCommandUseCase( + private val deviceControlCommandRepository: DeviceControlCommandRepository, +) { + suspend operator fun invoke( + device: Device, + command: DeviceControlCommand, + ) { + deviceControlCommandRepository.sendCommand( + device = device, + command = command, + ) + } +} diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/repository/di/RepositoryModule.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/repository/di/RepositoryModule.kt index 346379e..37a5996 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/repository/di/RepositoryModule.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/repository/di/RepositoryModule.kt @@ -1,11 +1,13 @@ package jp.kaleidot725.adbpad.repository.di +import jp.kaleidot725.adbpad.domain.repository.DeviceControlCommandRepository import jp.kaleidot725.adbpad.domain.repository.DeviceRepository import jp.kaleidot725.adbpad.domain.repository.KeyCommandRepository import jp.kaleidot725.adbpad.domain.repository.NormalCommandRepository import jp.kaleidot725.adbpad.domain.repository.ScreenshotCommandRepository import jp.kaleidot725.adbpad.domain.repository.SettingRepository import jp.kaleidot725.adbpad.domain.repository.TextCommandRepository +import jp.kaleidot725.adbpad.repository.impl.DeviceControlCommandRepositoryImpl import jp.kaleidot725.adbpad.repository.impl.DeviceRepositoryImpl import jp.kaleidot725.adbpad.repository.impl.KeyCommandRepositoryImpl import jp.kaleidot725.adbpad.repository.impl.NormalCommandRepositoryImpl @@ -38,4 +40,7 @@ val repositoryModule = factory { KeyCommandRepositoryImpl() } + factory { + DeviceControlCommandRepositoryImpl() + } } diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/repository/impl/DeviceControlCommandRepositoryImpl.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/repository/impl/DeviceControlCommandRepositoryImpl.kt new file mode 100644 index 0000000..c35e3af --- /dev/null +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/repository/impl/DeviceControlCommandRepositoryImpl.kt @@ -0,0 +1,38 @@ +package jp.kaleidot725.adbpad.repository.impl + +import com.malinskiy.adam.AndroidDebugBridgeClientFactory +import jp.kaleidot725.adbpad.domain.model.command.DeviceControlCommand +import jp.kaleidot725.adbpad.domain.model.device.Device +import jp.kaleidot725.adbpad.domain.repository.DeviceControlCommandRepository +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class DeviceControlCommandRepositoryImpl : DeviceControlCommandRepository { + private val adbClient = AndroidDebugBridgeClientFactory().build() + + override suspend fun sendCommand( + device: Device, + command: DeviceControlCommand, + onStart: suspend () -> Unit, + onComplete: suspend () -> Unit, + onFailed: suspend () -> Unit, + ) { + withContext(Dispatchers.IO) { + try { + onStart() + + command.requests.forEach { request -> + val result = adbClient.execute(request, device.serial) + if (result.exitCode != 0) { + onFailed() + return@withContext + } + } + + onComplete() + } catch (e: Exception) { + onFailed() + } + } + } +} diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconButton.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconButton.kt index 5be7aa9..73d4739 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconButton.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconButton.kt @@ -27,7 +27,7 @@ fun CommandIconButton( image: ImageVector, onClick: () -> Unit, degrees: Float = 0f, - padding: Dp = 0.dp + padding: Dp = 0.dp, ) { Box( modifier = @@ -52,6 +52,6 @@ fun CommandIconButton( private fun Preview() { CommandIconButton( image = Lucide.Power, - onClick = {} + onClick = {}, ) -} \ No newline at end of file +} diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconDivider.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconDivider.kt index 2123308..f7469ed 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconDivider.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/component/CommandIconDivider.kt @@ -2,37 +2,24 @@ package jp.kaleidot725.adbpad.ui.component import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Divider -import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.rotate import androidx.compose.ui.unit.dp -import com.composables.icons.lucide.Lucide -import com.composables.icons.lucide.Power -import jp.kaleidot725.adbpad.ui.common.resource.clickableBackground -import org.checkerframework.checker.units.qual.degrees @Composable -fun CommandIconDivider( - modifier: Modifier = Modifier, -) { +fun CommandIconDivider(modifier: Modifier = Modifier) { Divider( - modifier = modifier - .width(9.dp) - .fillMaxHeight() - .padding(vertical = 6.dp, horizontal = 4.dp) - .background(MaterialTheme.colors.onBackground) + modifier = + modifier + .width(9.dp) + .fillMaxHeight() + .padding(vertical = 6.dp, horizontal = 4.dp) + .background(MaterialTheme.colors.onBackground), ) } @@ -40,4 +27,4 @@ fun CommandIconDivider( @Composable private fun Preview() { CommandIconDivider() -} \ No newline at end of file +} diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/di/StateHolderModule.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/di/StateHolderModule.kt index 474a92a..c8aa104 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/di/StateHolderModule.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/di/StateHolderModule.kt @@ -56,7 +56,8 @@ val stateHolderModule = TopStateHolder( updateDevicesUseCase = get(), getSelectedDeviceFlowUseCase = get(), - selectDeviceUseCase = get() + selectDeviceUseCase = get(), + executeDeviceControlCommandUseCase = get(), ) } @@ -71,7 +72,7 @@ val stateHolderModule = getDarkModeFlowUseCase = get(), getLanguageUseCase = get(), refreshUseCase = get(), - topStateHolder = get() + topStateHolder = get(), ) } } diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopSection.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopSection.kt index 882dae8..deb2887 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopSection.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopSection.kt @@ -22,17 +22,16 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.input.pointer.PointerEventType import androidx.compose.ui.input.pointer.onPointerEvent import androidx.compose.ui.unit.dp -import com.composables.icons.lucide.Camera import com.composables.icons.lucide.Circle import com.composables.icons.lucide.Lucide import com.composables.icons.lucide.Power -import com.composables.icons.lucide.PowerOff import com.composables.icons.lucide.RefreshCcw import com.composables.icons.lucide.Square import com.composables.icons.lucide.Triangle import com.composables.icons.lucide.Volume1 import com.composables.icons.lucide.Volume2 -import jp.kaleidot725.adbpad.MainState +import com.composables.icons.lucide.VolumeX +import jp.kaleidot725.adbpad.domain.model.command.DeviceControlCommand import jp.kaleidot725.adbpad.domain.model.device.Device import jp.kaleidot725.adbpad.ui.component.CommandIconButton import jp.kaleidot725.adbpad.ui.component.CommandIconDivider @@ -42,6 +41,7 @@ import jp.kaleidot725.adbpad.ui.screen.menu.component.DropDownDeviceMenu @Composable fun TopSection( state: TopState, + onExecuteCommand: (DeviceControlCommand) -> Unit, onSelectDevice: (Device) -> Unit, onRefresh: () -> Unit, ) { @@ -64,65 +64,61 @@ fun TopSection( Row( horizontalArrangement = Arrangement.spacedBy(4.dp), - modifier = Modifier.align(Alignment.CenterEnd).wrapContentSize().padding(4.dp) + modifier = Modifier.align(Alignment.CenterEnd).wrapContentSize().padding(4.dp), ) { CommandIconButton( image = Lucide.Power, - onClick = {}, - padding = 2.dp - ) - - CommandIconButton( - image = Lucide.PowerOff, - onClick = {}, - padding = 2.dp + onClick = { onExecuteCommand(DeviceControlCommand.Power) }, + padding = 2.dp, ) CommandIconButton( image = Lucide.Volume2, - onClick = {} + onClick = { onExecuteCommand(DeviceControlCommand.VolumeUp) }, ) CommandIconButton( image = Lucide.Volume1, - onClick = {} + onClick = { onExecuteCommand(DeviceControlCommand.VolumeDown) }, ) CommandIconButton( - image = Lucide.Camera, - onClick = {}, - padding = 2.dp + image = Lucide.VolumeX, + onClick = { onExecuteCommand(DeviceControlCommand.VolumeMute) }, ) + CommandIconDivider() + CommandIconButton( image = Lucide.Triangle, degrees = -90f, - onClick = {}, - padding = 2.dp + onClick = { onExecuteCommand(DeviceControlCommand.Back) }, + padding = 2.dp, ) CommandIconButton( image = Lucide.Circle, - onClick = {}, - padding = 2.dp + onClick = { onExecuteCommand(DeviceControlCommand.Home) }, + padding = 2.dp, ) CommandIconButton( image = Lucide.Square, - onClick = {}, - padding = 2.dp + onClick = { onExecuteCommand(DeviceControlCommand.Recents) }, + padding = 2.dp, ) CommandIconDivider() CommandIconButton( - modifier = Modifier - .onPointerEvent(PointerEventType.Press) { isPress = true } - .onPointerEvent(PointerEventType.Release) { isPress = false }, + modifier = + Modifier + .onPointerEvent(PointerEventType.Press) { isPress = true } + .onPointerEvent(PointerEventType.Release) { isPress = false }, image = Lucide.RefreshCcw, degrees = degrees, onClick = { onRefresh() }, - padding = 2.dp + padding = 2.dp, ) } } diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopState.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopState.kt index 0dd8e55..3c44d8b 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopState.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopState.kt @@ -5,4 +5,4 @@ import jp.kaleidot725.adbpad.domain.model.device.Device data class TopState( val devices: List = emptyList(), val selectedDevice: Device? = null, -) \ No newline at end of file +) diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopStateHolder.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopStateHolder.kt index 546cd75..c9a0278 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopStateHolder.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/ui/section/TopStateHolder.kt @@ -1,6 +1,8 @@ package jp.kaleidot725.adbpad.ui.section +import jp.kaleidot725.adbpad.domain.model.command.DeviceControlCommand import jp.kaleidot725.adbpad.domain.model.device.Device +import jp.kaleidot725.adbpad.domain.usecase.command.ExecuteDeviceControlCommandUseCase import jp.kaleidot725.adbpad.domain.usecase.device.GetSelectedDeviceFlowUseCase import jp.kaleidot725.adbpad.domain.usecase.device.SelectDeviceUseCase import jp.kaleidot725.adbpad.domain.usecase.device.UpdateDevicesUseCase @@ -24,6 +26,7 @@ class TopStateHolder( private val updateDevicesUseCase: UpdateDevicesUseCase, private val getSelectedDeviceFlowUseCase: GetSelectedDeviceFlowUseCase, private val selectDeviceUseCase: SelectDeviceUseCase, + private val executeDeviceControlCommandUseCase: ExecuteDeviceControlCommandUseCase, ) : ChildStateHolder { private val coroutineScope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main + Dispatchers.IO) private var deviceJob: Job? = null @@ -34,16 +37,17 @@ class TopStateHolder( private val _selectedDevice: MutableStateFlow = MutableStateFlow(null) private val selectedDevice: StateFlow = _selectedDevice.asStateFlow() - override val state: StateFlow = combine(devices, selectedDevice) { devices, selectedDevice -> - TopState( - devices = devices, - selectedDevice = selectedDevice + override val state: StateFlow = + combine(devices, selectedDevice) { devices, selectedDevice -> + TopState( + devices = devices, + selectedDevice = selectedDevice, + ) + }.stateIn( + scope = coroutineScope, + started = SharingStarted.WhileSubscribed(), + initialValue = TopState(), ) - }.stateIn( - scope = coroutineScope, - started = SharingStarted.WhileSubscribed(), - initialValue = TopState() - ) override fun setup() { collectDevices() @@ -63,6 +67,16 @@ class TopStateHolder( } } + fun executeCommand(command: DeviceControlCommand) { + val device = selectedDevice.value ?: return + coroutineScope.launch { + executeDeviceControlCommandUseCase( + device = device, + command = command, + ) + } + } + private fun collectDevices() { deviceJob?.cancel() deviceJob = From 89871e1c1eda2f2a8588a2d4011f36ed951028a6 Mon Sep 17 00:00:00 2001 From: kaleidot725 Date: Fri, 3 Jan 2025 12:50:48 +0900 Subject: [PATCH 5/6] feat: define lucide dependencies version --- .idea/artifacts/adbpad_jvm_1_3_0.xml | 4 +++- build.gradle.kts | 3 +-- gradle/libs.versions.toml | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.idea/artifacts/adbpad_jvm_1_3_0.xml b/.idea/artifacts/adbpad_jvm_1_3_0.xml index fc6df59..e7e1f78 100644 --- a/.idea/artifacts/adbpad_jvm_1_3_0.xml +++ b/.idea/artifacts/adbpad_jvm_1_3_0.xml @@ -1,6 +1,8 @@ $PROJECT_DIR$/build/libs - + + + \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index b67ad72..18e5ebf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -29,15 +29,14 @@ kotlin { implementation(compose.material) implementation(compose.materialIconsExtended) implementation(libs.adam) + implementation(libs.lucide) implementation(libs.kotlin.coroutines) implementation(libs.kotlinx.coroutines.swing) implementation(libs.kotlin.serialization) implementation(libs.koin) - implementation(compose.desktop.currentOs) { exclude(group = "org.jetbrains.compose.material") } implementation(libs.ktor.core) implementation(libs.ktor.client.okhttp) implementation(libs.jSystemThemeDetectorVer) - implementation("com.composables:icons-lucide:1.0.0") } } val jvmTest by getting { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3f1c688..e1cccb0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ junit="5.11.3" koin="4.0.0" system_theme_detector="3.8" ktor = "3.0.1" +lucide = "1.0.0" [libraries] adam = { module = "com.malinskiy.adam:adam", version.ref = "adam" } @@ -20,6 +21,7 @@ koin = { module = "io.insert-koin:koin-core", version.ref = "koin" } jSystemThemeDetectorVer = { module = "com.github.Dansoftowner:jSystemThemeDetector", version.ref = "system_theme_detector" } ktor-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } +lucide = { module = "com.composables:icons-lucide", version.ref = "lucide" } [plugins] multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } From 53a534391e2c07bfa03b54fd427bb4a4f06c10c2 Mon Sep 17 00:00:00 2001 From: kaleidot725 Date: Fri, 3 Jan 2025 13:18:33 +0900 Subject: [PATCH 6/6] feat: add navigation bar command --- .../domain/model/command/NormalCommand.kt | 30 +++++++++++++++++++ .../adbpad/domain/model/language/Language.kt | 12 ++++++++ .../language/resources/ChineseResources.kt | 8 ++++- .../language/resources/EnglishResources.kt | 6 ++++ .../language/resources/JapaneseResources.kt | 6 ++++ .../language/resources/StringResources.kt | 6 ++++ .../impl/NormalCommandRepositoryImpl.kt | 3 ++ 7 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/command/NormalCommand.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/command/NormalCommand.kt index 3f3d365..9c9b50c 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/command/NormalCommand.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/command/NormalCommand.kt @@ -165,4 +165,34 @@ interface NormalCommand { ) override val category: NormalCommandCategory = NormalCommandCategory.UI } + + data class EnableGestureNavigation(override val isRunning: Boolean = false) : NormalCommand { + override val title: String get() = Language.commandEnableGestureNavigationTitle + override val details: String get() = Language.commandEnableGestureNavigationDetails + override val requests: List = + listOf( + ShellCommandRequest("cmd overlay enable com.android.internal.systemui.navbar.gestural"), + ) + override val category: NormalCommandCategory = NormalCommandCategory.UI + } + + data class EnableTwoButtonNavigation(override val isRunning: Boolean = false) : NormalCommand { + override val title: String get() = Language.commandEnableTwoButtonNavigationTitle + override val details: String get() = Language.commandEnableTwoButtonNavigationDetails + override val requests: List = + listOf( + ShellCommandRequest("cmd overlay enable com.android.internal.systemui.navbar.twobutton"), + ) + override val category: NormalCommandCategory = NormalCommandCategory.UI + } + + data class EnableThreeButtonNavigation(override val isRunning: Boolean = false) : NormalCommand { + override val title: String get() = Language.commandEnableThreeButtonNavigationTitle + override val details: String get() = Language.commandEnableThreeButtonNavigationDetails + override val requests: List = + listOf( + ShellCommandRequest("cmd overlay enable com.android.internal.systemui.navbar.threebutton"), + ) + override val category: NormalCommandCategory = NormalCommandCategory.UI + } } diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/Language.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/Language.kt index d0ab7e0..b9bf829 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/Language.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/Language.kt @@ -126,6 +126,18 @@ object Language : StringResources { get() = getCurrentResources().commandScreenPinningOffTitle override val commandScreenPinningOffDetails: String get() = getCurrentResources().commandScreenPinningOffDetails + override val commandEnableThreeButtonNavigationTitle: String + get() = getCurrentResources().commandEnableThreeButtonNavigationTitle + override val commandEnableThreeButtonNavigationDetails: String + get() = getCurrentResources().commandEnableThreeButtonNavigationDetails + override val commandEnableTwoButtonNavigationTitle: String + get() = getCurrentResources().commandEnableTwoButtonNavigationTitle + override val commandEnableTwoButtonNavigationDetails: String + get() = getCurrentResources().commandEnableTwoButtonNavigationDetails + override val commandEnableGestureNavigationTitle: String + get() = getCurrentResources().commandEnableGestureNavigationTitle + override val commandEnableGestureNavigationDetails: String + get() = getCurrentResources().commandEnableGestureNavigationDetails override val textCommandStartEventFormat: String get() = getCurrentResources().textCommandStartEventFormat diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/ChineseResources.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/ChineseResources.kt index c6dffe6..dbf97d7 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/ChineseResources.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/ChineseResources.kt @@ -55,7 +55,7 @@ object ChineseResources : StringResources { override val commandWifiOnDetails = "启用 Wi-Fi 通信。" override val commandWifiOffTitle = "Wi-Fi: 关闭" override val commandWifiOffDetails = "禁用 Wi-Fi 通信。" - override val commandDataOnTitle = "蜂窝网络: 开启" + override val commandDataOnTitle = "蜂窝网ad络: 开启" override val commandDataOnDetails = "启用蜂窝网络通信。" override val commandDataOffTitle = "蜂窝网络: 关闭" override val commandDataOffDetails = "禁用蜂窝网络通信。" @@ -65,6 +65,12 @@ object ChineseResources : StringResources { override val commandWifiAndDataOffDetails = "禁用 Wi-Fi 和蜂窝网络通信。" override val commandScreenPinningOffTitle = "屏幕固定: 关闭" override val commandScreenPinningOffDetails = "禁用屏幕固定功能。" + override val commandEnableThreeButtonNavigationTitle: String = "3 按钮导航 : 开启" + override val commandEnableThreeButtonNavigationDetails: String = "启动三键导航" + override val commandEnableTwoButtonNavigationTitle: String = "2 按钮导航 : 开启" + override val commandEnableTwoButtonNavigationDetails: String = "启动双按钮导航" + override val commandEnableGestureNavigationTitle: String = "手势导航 : 开启" + override val commandEnableGestureNavigationDetails: String = "启动手势导航" override val textCommandStartEventFormat = "开始发送文本 「%s」" override val textCommandEndEventFormat = "结束发送文本 「%s」" diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/EnglishResources.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/EnglishResources.kt index b4ae549..a76d323 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/EnglishResources.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/EnglishResources.kt @@ -65,6 +65,12 @@ object EnglishResources : StringResources { override val commandWifiAndDataOffDetails = "Disable Wi-Fi and cellular communication." override val commandScreenPinningOffTitle = "Screen pinning: OFF" override val commandScreenPinningOffDetails = "Disable screen pinning." + override val commandEnableThreeButtonNavigationTitle: String = "3 buttons navigation : ON" + override val commandEnableThreeButtonNavigationDetails: String = "Enable 3 buttons navigation" + override val commandEnableTwoButtonNavigationTitle: String = "2 buttons navigation : ON" + override val commandEnableTwoButtonNavigationDetails: String = "Enable 2 buttons navigation" + override val commandEnableGestureNavigationTitle: String = "Gesture navigation: ON" + override val commandEnableGestureNavigationDetails: String = "Enable gesture navigation" override val textCommandStartEventFormat = "Start sending text「%s」" override val textCommandEndEventFormat = "End sending text「%s」" diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/JapaneseResources.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/JapaneseResources.kt index 70834de..b139efe 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/JapaneseResources.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/JapaneseResources.kt @@ -65,6 +65,12 @@ object JapaneseResources : StringResources { override val commandWifiAndDataOffDetails = "Wi-Fi通信とモバイル通信の両方を無効化する" override val commandScreenPinningOffTitle = "画面ピン留め: OFF" override val commandScreenPinningOffDetails = "ピン留め中のアプリのピン留めを解除する" + override val commandEnableThreeButtonNavigationTitle: String = "3ボタン ナビゲーション: ON" + override val commandEnableThreeButtonNavigationDetails: String = "3ボタン ナビゲーションを有効化する" + override val commandEnableTwoButtonNavigationTitle: String = "2ボタン ナビゲーション: ON" + override val commandEnableTwoButtonNavigationDetails: String = "2ボタン ナビゲーションを有効化する" + override val commandEnableGestureNavigationTitle: String = "ジェスチャー ナビゲーション: ON" + override val commandEnableGestureNavigationDetails: String = "ジェスチャー ナビゲーションを有効化する" override val textCommandStartEventFormat = "「%s」のテキスト送信を開始しました" override val textCommandEndEventFormat = "「%s」のテキスト送信が完了しました" diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/StringResources.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/StringResources.kt index 4d587e8..3f417ba 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/StringResources.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/model/language/resources/StringResources.kt @@ -64,6 +64,12 @@ interface StringResources { val commandWifiAndDataOffDetails: String val commandScreenPinningOffTitle: String val commandScreenPinningOffDetails: String + val commandEnableThreeButtonNavigationTitle: String + val commandEnableThreeButtonNavigationDetails: String + val commandEnableTwoButtonNavigationTitle: String + val commandEnableTwoButtonNavigationDetails: String + val commandEnableGestureNavigationTitle: String + val commandEnableGestureNavigationDetails: String val textCommandStartEventFormat: String val textCommandEndEventFormat: String diff --git a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/repository/impl/NormalCommandRepositoryImpl.kt b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/repository/impl/NormalCommandRepositoryImpl.kt index 1e81b92..766d508 100644 --- a/src/jvmMain/kotlin/jp/kaleidot725/adbpad/repository/impl/NormalCommandRepositoryImpl.kt +++ b/src/jvmMain/kotlin/jp/kaleidot725/adbpad/repository/impl/NormalCommandRepositoryImpl.kt @@ -31,6 +31,9 @@ class NormalCommandRepositoryImpl : NormalCommandRepository { NormalCommand.WifiAndDataOn(runningCommands.any { it is NormalCommand.WifiAndDataOn }), NormalCommand.WifiAndDataOff(runningCommands.any { it is NormalCommand.WifiAndDataOff }), NormalCommand.ScreenPinningOff(runningCommands.any { it is NormalCommand.ScreenPinningOff }), + NormalCommand.EnableGestureNavigation(runningCommands.any { it is NormalCommand.EnableGestureNavigation }), + NormalCommand.EnableTwoButtonNavigation(runningCommands.any { it is NormalCommand.EnableTwoButtonNavigation }), + NormalCommand.EnableThreeButtonNavigation(runningCommands.any { it is NormalCommand.EnableThreeButtonNavigation }), ) }