Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/rework text sender #140

Merged
merged 19 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .idea/artifacts/adbpad_jvm_1_5_2.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/ktlint-plugin.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ https://github.com/user-attachments/assets/b250bf2b-e61c-4a6d-9872-6d3dcb3339e6

# ⬇️ Install

- Download from [here](https://github.com/kaleidot725/AdbPad/releases/tag/v1.5.2).
- Download from [here](https://github.com/kaleidot725/AdbPad/releases/tag/v2.0.0).
- Setup adb path on Setting.

https://github.com/user-attachments/assets/f5542ace-118d-4165-a138-49d59c7bda8b
Expand Down
4 changes: 1 addition & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ plugins {
}

group = "jp.kaleidot725"
version = "1.5.2"
version = "2.0.0"

kotlin {
jvm()
Expand All @@ -39,8 +39,6 @@ kotlin {
implementation(libs.ktor.client.okhttp)
implementation(libs.jSystemThemeDetectorVer)
implementation(libs.coil)
implementation(libs.hot.reload.core)
implementation(libs.hot.reload.analysis)
}
sourceSets.jvmTest.dependencies {
implementation(libs.junit5)
Expand Down
13 changes: 5 additions & 8 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
[versions]
kotlin="2.1.20-Beta2"
compose_reload_kotlin = "2.1.20-firework.34"
kotlin_coroutines="1.10.1"
kotlin_serialization="1.8.0"
compose_hot_reload = "1.0.0-dev-39"
compose_hot_reload = "1.0.0-alpha01"
compose="1.7.3"
ktlint_plugin="12.1.2"
adam="0.5.10"
Expand All @@ -26,14 +25,12 @@ 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" }
coil = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" }
hot-reload-core = { module = "org.jetbrains.compose:hot-reload-core", version.ref = "compose_hot_reload" }
hot-reload-analysis = { module = "org.jetbrains.compose:hot-reload-analysis", version.ref = "compose_hot_reload" }

[plugins]
multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "compose_reload_kotlin" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "compose_reload_kotlin" }
compose-hot-reload = { id = "org.jetbrains.compose-hot-reload", version.ref = "compose_hot_reload" }
multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
compose-hot-reload = { id = "org.jetbrains.compose.hot-reload", version.ref = "compose_hot_reload" }

compose = { id = "org.jetbrains.compose", version.ref = "compose" }
kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "compose_reload_kotlin" }
kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint_plugin" }
4 changes: 0 additions & 4 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ pluginManagement {
google()
gradlePluginPortal()
mavenCentral()
maven(file("../..//build/repo"))
maven("https://packages.jetbrains.team/maven/p/firework/dev")
}
}

Expand All @@ -13,8 +11,6 @@ dependencyResolutionManagement {
google()
gradlePluginPortal()
mavenCentral()
maven(file("../..//build/repo"))
maven("https://packages.jetbrains.team/maven/p/firework/dev")
maven("https://jitpack.io")
}
}
Expand Down
59 changes: 19 additions & 40 deletions src/jvmMain/kotlin/jp/kaleidot725/adbpad/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ 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.screenshot.ScreenshotAction
import jp.kaleidot725.adbpad.ui.screen.screenshot.ScreenshotScreen
import jp.kaleidot725.adbpad.ui.screen.setting.SettingScreen
import jp.kaleidot725.adbpad.ui.screen.setting.SettingStateHolder
Expand Down Expand Up @@ -81,6 +82,7 @@ fun main() {
fun WindowScope.App(mainStateHolder: MainStateHolder) {
val state by mainStateHolder.state.collectAsState()
val decoratedWindowScope = this
val textSplitPaneState = rememberSplitPaneState()
val screenshotSplitPaneState = rememberSplitPaneState()

DisposableEffect(mainStateHolder) {
Expand Down Expand Up @@ -128,44 +130,19 @@ fun WindowScope.App(mainStateHolder: MainStateHolder) {
}

MainCategory.Text -> {
val inputTextStateHolder = mainStateHolder.textCommandStateHolder
val inputTextState by inputTextStateHolder.state.collectAsState()

val inputTextState by mainStateHolder.textCommandStateHolder.state.collectAsState()
val onAction = mainStateHolder.textCommandStateHolder::onAction
TextCommandScreen(
// InputText
inputText = inputTextState.userInputText,
onTextChange = { text ->
inputTextStateHolder.updateInputText(text)
},
isSendingInputText = inputTextState.isSendingUserInputText,
onSendInputText = {
inputTextStateHolder.sendInputText()
},
canSendInputText = inputTextState.canSendInputText,
canSendTabKey = inputTextState.canSendTabKey,
onSendTabKey = {
inputTextStateHolder.sendTabCommand()
},
onSaveInputText = {
inputTextStateHolder.saveInputText()
},
canSaveInputText = inputTextState.canSaveInputText,
// Commands
commands = inputTextState.commands,
onSendCommand = { text ->
inputTextStateHolder.sendTextCommand(text)
},
canSendCommand = inputTextState.canSendCommand,
isSendingTab = inputTextState.isSendingTab,
onDeleteCommand = { text ->
inputTextStateHolder.deleteInputText(text)
},
state = inputTextState,
onAction = onAction,
splitterState = textSplitPaneState,
)
}

MainCategory.Screenshot -> {
val screenshotStateHolder = mainStateHolder.screenshotStateHolder
val screenshotState by screenshotStateHolder.state.collectAsState()
val onAction = screenshotStateHolder::onAction

ScreenshotScreen(
screenshot = screenshotState.preview,
Expand All @@ -174,28 +151,30 @@ fun WindowScope.App(mainStateHolder: MainStateHolder) {
canCapture = screenshotState.canExecute,
isCapturing = screenshotState.isCapturing,
commands = screenshotState.commands,
searchText = screenshotState.searchText,
onOpenDirectory = {
screenshotStateHolder.openDirectory()
onAction(ScreenshotAction.OpenDirectory)
},
onCopyScreenshot = {
screenshotStateHolder.copyScreenShotToClipboard()
onAction(ScreenshotAction.CopyScreenshotToClipboard)
},
onDeleteScreenshot = {
screenshotStateHolder.deleteScreenShotToClipboard()
onAction(ScreenshotAction.DeleteScreenshotToClipboard)
},
onTakeScreenshot = { screenshot ->
screenshotStateHolder.takeScreenShot(
screenshot,
)
onAction(ScreenshotAction.TakeScreenshot(screenshot))
},
onSelectScreenshot = { screenshot ->
screenshotStateHolder.selectScreenshot(screenshot)
onAction(ScreenshotAction.SelectScreenshot(screenshot))
},
onNextScreenshot = {
screenshotStateHolder.nextScreenshot()
onAction(ScreenshotAction.NextScreenshot)
},
onPreviousScreenshot = {
screenshotStateHolder.previousScreenshot()
onAction(ScreenshotAction.PreviousScreenshot)
},
onUpdateSearchText = {
onAction(ScreenshotAction.UpdateSearchText(it))
},
)
}
Expand Down
8 changes: 6 additions & 2 deletions src/jvmMain/kotlin/jp/kaleidot725/adbpad/MainStateHolder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ class MainStateHolder(
private val children: List<ChildStateHolder<*>> =
listOf(
commandStateHolder,
textCommandStateHolder,
screenshotStateHolder,
topStateHolder,
)

Expand All @@ -74,6 +72,8 @@ class MainStateHolder(

override fun setup() {
children.forEach { it.setup() }
textCommandStateHolder.onSetup()
screenshotStateHolder.onSetup()
}

override fun refresh() {
Expand All @@ -82,10 +82,14 @@ class MainStateHolder(
syncLanguage()
refreshUseCase()
children.forEach { it.refresh() }
textCommandStateHolder.onRefresh()
screenshotStateHolder.onRefresh()
}

override fun dispose() {
children.forEach { it.dispose() }
textCommandStateHolder.onDispose()
screenshotStateHolder.onDispose()
}

fun saveSetting(windowSize: WindowSize) {
Expand Down
24 changes: 24 additions & 0 deletions src/jvmMain/kotlin/jp/kaleidot725/adbpad/core/mvi/MVI.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package jp.kaleidot725.adbpad.core.mvi

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow

interface MVI<UiState : MVIState, UiAction : MVIAction, SideEffect : MVISideEffect> {
val coroutineScope: CoroutineScope
val state: StateFlow<UiState>
val currentState: UiState
val sideEffect: Flow<SideEffect>

fun onSetup()

fun onAction(uiAction: UiAction)

fun onRefresh()

fun onDispose()

fun update(block: UiState.() -> UiState)

suspend fun sideEffect(effect: SideEffect)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package jp.kaleidot725.adbpad.core.mvi

interface MVIAction
45 changes: 45 additions & 0 deletions src/jvmMain/kotlin/jp/kaleidot725/adbpad/core/mvi/MVIDelegate.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package jp.kaleidot725.adbpad.core.mvi

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

class MVIDelegate<UiState : MVIState, UiAction : MVIAction, SideEffect : MVISideEffect> internal constructor(
initialUiState: UiState,
) : MVI<UiState, UiAction, SideEffect> {
override val coroutineScope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main + Dispatchers.IO)

private val uiState = MutableStateFlow(initialUiState)
override val state: StateFlow<UiState> = uiState.asStateFlow()
override val currentState: UiState get() = state.value
private val _sideEffect by lazy { Channel<SideEffect>() }
override val sideEffect: Flow<SideEffect> by lazy { _sideEffect.receiveAsFlow() }

override fun onSetup() {}

override fun onAction(uiAction: UiAction) {}

override fun onRefresh() {}

override fun onDispose() {}

override fun update(block: UiState.() -> UiState) {
uiState.update { block(it) }
}

override suspend fun sideEffect(effect: SideEffect) {
coroutineScope.launch { _sideEffect.send(effect) }
}
}

fun <UiState : MVIState, UiAction : MVIAction, SideEffect : MVISideEffect> mvi(
initialUiState: UiState,
): MVI<UiState, UiAction, SideEffect> = MVIDelegate(initialUiState)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package jp.kaleidot725.adbpad.core.mvi

interface MVISideEffect
3 changes: 3 additions & 0 deletions src/jvmMain/kotlin/jp/kaleidot725/adbpad/core/mvi/MVIState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package jp.kaleidot725.adbpad.core.mvi

interface MVIState
12 changes: 0 additions & 12 deletions src/jvmMain/kotlin/jp/kaleidot725/adbpad/domain/di/DomainModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,8 @@ import jp.kaleidot725.adbpad.domain.usecase.screenshot.TakeScreenshotUseCase
import jp.kaleidot725.adbpad.domain.usecase.sdkpath.GetSdkPathUseCase
import jp.kaleidot725.adbpad.domain.usecase.sdkpath.SaveSdkPathUseCase
import jp.kaleidot725.adbpad.domain.usecase.text.AddTextCommandUseCase
import jp.kaleidot725.adbpad.domain.usecase.text.DeleteTextCommandUseCase
import jp.kaleidot725.adbpad.domain.usecase.text.ExecuteTextCommandUseCase
import jp.kaleidot725.adbpad.domain.usecase.text.GetTextCommandUseCase
import jp.kaleidot725.adbpad.domain.usecase.text.SendTabCommandUseCase
import jp.kaleidot725.adbpad.domain.usecase.text.SendUserInputTextCommandUseCase
import jp.kaleidot725.adbpad.domain.usecase.theme.GetDarkModeFlowUseCase
import jp.kaleidot725.adbpad.domain.usecase.window.GetWindowSizeUseCase
import jp.kaleidot725.adbpad.domain.usecase.window.SaveWindowSizeUseCase
Expand Down Expand Up @@ -54,9 +51,6 @@ val domainModule =
factory {
AddTextCommandUseCase(get())
}
factory {
DeleteTextCommandUseCase(get())
}
factory {
ExecuteTextCommandUseCase(get())
}
Expand All @@ -69,9 +63,6 @@ val domainModule =
factory {
GetScreenshotCommandUseCase(get())
}
factory {
SendUserInputTextCommandUseCase(get())
}
factory {
GetWindowSizeUseCase(get())
}
Expand Down Expand Up @@ -99,9 +90,6 @@ val domainModule =
factory {
GetLanguageUseCase(get())
}
factory {
SendTabCommandUseCase(get())
}
factory {
RefreshUseCase(get(), get(), get())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
package jp.kaleidot725.adbpad.domain.model.command

import com.malinskiy.adam.request.shell.v1.ShellCommandRequest
import kotlinx.serialization.Serializable
import java.util.UUID

@Serializable
data class TextCommand(
val id: String = UUID.randomUUID().toString(),
val title: String,
val text: String,
val isRunning: Boolean = false,
) {
val requests: List<ShellCommandRequest> = listOf(ShellCommandRequest("input text $text"))
val requests: List<ShellCommandRequest> get() {
return buildList {
val texts = text.split('\n')
texts.forEach { text ->
if (text.isEmpty()) {
add(ShellCommandRequest(""))
} else {
add(ShellCommandRequest("input text $text"))
}
}
}
}

enum class Option {
SendWithTab,
SendWithNewLine,
}
}
Loading
Loading