setup project
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
alias(libs.plugins.composeMultiplatform)
|
||||
alias(libs.plugins.composeCompiler)
|
||||
alias(libs.plugins.composeHotReload)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation(compose.runtime)
|
||||
implementation(compose.foundation)
|
||||
implementation(compose.material3)
|
||||
implementation(compose.ui)
|
||||
implementation(compose.materialIconsExtended)
|
||||
implementation(compose.components.resources)
|
||||
implementation(compose.components.uiToolingPreview)
|
||||
implementation(libs.androidx.lifecycle.viewmodelCompose)
|
||||
implementation(libs.androidx.lifecycle.runtimeCompose)
|
||||
// Koin DI
|
||||
implementation(libs.koin.core)
|
||||
implementation(libs.koin.compose)
|
||||
}
|
||||
commonTest.dependencies {
|
||||
implementation(libs.kotlin.test)
|
||||
}
|
||||
jvmMain.dependencies {
|
||||
implementation(compose.desktop.currentOs)
|
||||
implementation(libs.kotlinx.coroutinesSwing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
compose.desktop {
|
||||
application {
|
||||
mainClass = "com.brp.tools.adbkey.MainKt"
|
||||
|
||||
nativeDistributions {
|
||||
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
|
||||
packageName = "com.brp.tools.adbkey"
|
||||
packageVersion = "1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="450dp"
|
||||
android:height="450dp"
|
||||
android:viewportWidth="64"
|
||||
android:viewportHeight="64">
|
||||
<path
|
||||
android:pathData="M56.25,18V46L32,60 7.75,46V18L32,4Z"
|
||||
android:fillColor="#6075f2"/>
|
||||
<path
|
||||
android:pathData="m41.5,26.5v11L32,43V60L56.25,46V18Z"
|
||||
android:fillColor="#6b57ff"/>
|
||||
<path
|
||||
android:pathData="m32,43 l-9.5,-5.5v-11L7.75,18V46L32,60Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:centerX="23.131"
|
||||
android:centerY="18.441"
|
||||
android:gradientRadius="42.132"
|
||||
android:type="radial">
|
||||
<item android:offset="0" android:color="#FF5383EC"/>
|
||||
<item android:offset="0.867" android:color="#FF7F52FF"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="M22.5,26.5 L32,21 41.5,26.5 56.25,18 32,4 7.75,18Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="44.172"
|
||||
android:startY="4.377"
|
||||
android:endX="17.973"
|
||||
android:endY="34.035"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#FF33C3FF"/>
|
||||
<item android:offset="0.878" android:color="#FF5383EC"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="m32,21 l9.526,5.5v11L32,43 22.474,37.5v-11z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,162 @@
|
||||
package com.brp.tools.adbkey
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
data class AdbCommand(
|
||||
val title: String,
|
||||
val cmd: String,
|
||||
val description: String = "",
|
||||
)
|
||||
|
||||
val commands = listOf(
|
||||
AdbCommand(
|
||||
title = "Android Setting",
|
||||
cmd = "adb -s {device} shell am start -a android.settings.SETTINGS"
|
||||
),
|
||||
AdbCommand(
|
||||
title = "App List",
|
||||
cmd = "adb -s {device} shell am start -a android.settings.APPLICATION_SETTINGS"
|
||||
),
|
||||
AdbCommand(
|
||||
title = "BGE Setting",
|
||||
cmd = "adb -s {device} shell am start -a android.settings.APPLICATION_DETAILS_SETTINGS -e \"android.provider.extra.APP_PACKAGE\" \"com.brp.goembedded\""
|
||||
),
|
||||
AdbCommand(
|
||||
title = "Location Setting",
|
||||
cmd = "adb -s {device} shell am start -a android.settings.LOCATION_SOURCE_SETTINGS"
|
||||
),
|
||||
AdbCommand(
|
||||
title = "Launch BGE",
|
||||
cmd = "adb -s {device} shell monkey -p com.brp.goembedded -c android.intent.category.LAUNCHER 1"
|
||||
),
|
||||
AdbCommand(
|
||||
title = "Key Home",
|
||||
cmd = "adb -s {device} shell input keyevent KEYCODE_HOME "
|
||||
),
|
||||
AdbCommand(
|
||||
title = "Force Stop Setting",
|
||||
cmd = "adb -s {device} shell am force-stop com.android.car.settings"
|
||||
),
|
||||
AdbCommand(
|
||||
title = "Uninstall BGE",
|
||||
cmd = "adb -s {device} uninstall com.brp.goembedded"
|
||||
),
|
||||
AdbCommand(
|
||||
title = "Stop BGE",
|
||||
cmd = "adb -s {device} shell am force-stop com.brp.goembedded"
|
||||
),
|
||||
AdbCommand(
|
||||
title = "Clea Cache For All ",
|
||||
cmd = "adb -s {device} shell pm trim-caches 9999999999"
|
||||
)
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun CommandItemView(
|
||||
modifier: Modifier = Modifier,
|
||||
adbCommand: AdbCommand,
|
||||
executeCommand: (AdbCommand) -> Unit = {}
|
||||
) {
|
||||
Button(
|
||||
modifier = modifier.defaultMinSize(minWidth = 300.dp),
|
||||
onClick = {
|
||||
executeCommand(adbCommand)
|
||||
},
|
||||
content = {
|
||||
Text(text = adbCommand.title)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
data class AppState(
|
||||
val message: String = "",
|
||||
val commands: List<AdbCommand> = emptyList(),
|
||||
)
|
||||
|
||||
class AppViewModel {
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||
private val mutableStateFlow = MutableStateFlow(AppState())
|
||||
val state: StateFlow<AppState> = mutableStateFlow
|
||||
|
||||
init {
|
||||
mutableStateFlow.update {
|
||||
it.copy(commands = commands)
|
||||
}
|
||||
}
|
||||
|
||||
fun executeCommand(command: AdbCommand, selectedDevice: AdbDevice?) {
|
||||
scope.launch {
|
||||
try {
|
||||
if (selectedDevice != null) {
|
||||
val newCommand = command.cmd.replace("{device}", selectedDevice.id)
|
||||
println("New command: $newCommand")
|
||||
val process = Runtime.getRuntime().exec(newCommand)
|
||||
process.inputStream.bufferedReader().forEachLine { line ->
|
||||
println("Process line: $line")
|
||||
mutableStateFlow.update {
|
||||
it.copy(message = line)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
mutableStateFlow.update {
|
||||
it.copy(message = e.localizedMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun App(viewModel: AppViewModel = AppViewModel()) {
|
||||
val state by viewModel.state.collectAsState()
|
||||
var selectedDevice by remember { mutableStateOf<AdbDevice?>(null) }
|
||||
MaterialTheme {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(16.dp),
|
||||
content = {
|
||||
item {
|
||||
Text("Selected Device : ${selectedDevice?.model}")
|
||||
}
|
||||
item {
|
||||
DeviceSelector {
|
||||
selectedDevice = it
|
||||
}
|
||||
}
|
||||
items(items = state.commands) { command ->
|
||||
CommandItemView(
|
||||
adbCommand = command,
|
||||
executeCommand = {
|
||||
viewModel.executeCommand(it, selectedDevice)
|
||||
}
|
||||
)
|
||||
}
|
||||
item {
|
||||
Text(text = "Message : ${state.message}")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.brp.tools.adbkey
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.DropdownMenu
|
||||
import androidx.compose.material.DropdownMenuItem
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
data class AdbDevice(
|
||||
val id: String,
|
||||
val model: String,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun DeviceSelector(
|
||||
onDeviceSelected: (AdbDevice) -> Unit,
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
var devices by remember { mutableStateOf<List<AdbDevice>>(emptyList()) }
|
||||
|
||||
LaunchedEffect(expanded) {
|
||||
if (expanded) {
|
||||
val process = Runtime.getRuntime().exec("adb devices -l")
|
||||
val output = process.inputStream.bufferedReader().readText()
|
||||
devices = output.split("\n").drop(1).filter { it.isNotBlank() }.map {
|
||||
val deviceId = it.substringBefore("device").trim()
|
||||
val deviceName = it.substringAfter("model:").substringBefore("device:").trim()
|
||||
AdbDevice(id = deviceId, model = deviceName)
|
||||
}
|
||||
println("Devices found: $devices")
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
expanded = false
|
||||
devices = emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
content = {
|
||||
IconButton(onClick = { expanded = !expanded }) {
|
||||
Icon(Icons.Default.MoreVert, contentDescription = "More options")
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
content = {
|
||||
devices.forEach { device ->
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text("${device.id} - ${device.model}")
|
||||
},
|
||||
onClick = {
|
||||
onDeviceSelected(device)
|
||||
expanded = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.brp.tools.adbkey
|
||||
|
||||
class JVMPlatform {
|
||||
val name: String = "Java ${System.getProperty("java.version")}"
|
||||
}
|
||||
|
||||
fun getPlatform() = JVMPlatform()
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.brp.tools.adbkey.kointest
|
||||
|
||||
import com.brp.tools.adbkey.kointest.module
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
import org.koin.core.context.GlobalContext.startKoin
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import org.koin.dsl.module
|
||||
|
||||
data class BtDevice(val id: String)
|
||||
|
||||
class LinkConnector(val btDevice: BtDevice) {
|
||||
init {
|
||||
println("Link connector ${btDevice.id}")
|
||||
}
|
||||
}
|
||||
|
||||
class Client() : KoinComponent {
|
||||
fun connect(btDevice: BtDevice) {
|
||||
val link = get<LinkConnector> { parametersOf(btDevice) }
|
||||
println("Connected to ${link.btDevice}, Link $link")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val module = module {
|
||||
single { Client() }
|
||||
factory { (device: BtDevice) -> LinkConnector(device) }
|
||||
}
|
||||
|
||||
|
||||
fun main() {
|
||||
val koin = startKoin {
|
||||
modules(listOf(module))
|
||||
}
|
||||
|
||||
val bt1 = BtDevice("abc")
|
||||
val bt2 = BtDevice("efg")
|
||||
|
||||
val client = koin.koin.get<Client>()
|
||||
client.connect(bt1)
|
||||
client.connect(bt2)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.brp.tools.adbkey
|
||||
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.application
|
||||
|
||||
fun main() = application {
|
||||
// Initialize Koin once at app start
|
||||
Window(
|
||||
onCloseRequest = ::exitApplication,
|
||||
title = "adbkey",
|
||||
content = {
|
||||
App()
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.brp.tools.adbkey
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class ComposeAppDesktopTest {
|
||||
|
||||
@Test
|
||||
fun example() {
|
||||
assertEquals(3, 1 + 2)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user