profile editing. styling
This commit is contained in:
parent
d5ff6a1a0a
commit
f73be7184f
|
|
@ -1,5 +1,6 @@
|
||||||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
||||||
import org.jetbrains.compose.internal.de.undercouch.gradle.tasks.download.Download
|
import org.jetbrains.compose.internal.de.undercouch.gradle.tasks.download.Download
|
||||||
|
import org.gradle.internal.os.OperatingSystem
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
val kotlinVersion = "2.0.21"
|
val kotlinVersion = "2.0.21"
|
||||||
|
|
@ -67,35 +68,53 @@ dependencies {
|
||||||
val serializationVersion = "1.5.1"
|
val serializationVersion = "1.5.1"
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion")
|
||||||
|
|
||||||
|
//FileKit
|
||||||
|
val fileKitVersion = "0.8.7"
|
||||||
|
implementation("io.github.vinceglb:filekit-core:$fileKitVersion")
|
||||||
|
implementation("io.github.vinceglb:filekit-compose:$fileKitVersion")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val currentOs = OperatingSystem.current()
|
||||||
|
|
||||||
compose.desktop {
|
compose.desktop {
|
||||||
application {
|
application {
|
||||||
mainClass = "MainKt"
|
mainClass = "MainKt"
|
||||||
|
|
||||||
nativeDistributions {
|
nativeDistributions {
|
||||||
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
|
linux {
|
||||||
|
modules("jdk.security.auth")
|
||||||
|
}
|
||||||
|
targetFormats(
|
||||||
|
*listOf(
|
||||||
|
TargetFormat.Dmg.takeIf { currentOs.isMacOsX },
|
||||||
|
TargetFormat.Msi.takeIf { currentOs.isWindows },
|
||||||
|
TargetFormat.Deb.takeIf { currentOs.isLinux }
|
||||||
|
).filterNotNull().toTypedArray()
|
||||||
|
)
|
||||||
packageName = "mia"
|
packageName = "mia"
|
||||||
packageVersion = "1.0.0"
|
packageVersion = "1.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register("buildLite") {
|
tasks.register("packageLiteInstaller") {
|
||||||
|
group = "package project"
|
||||||
description = "Build program with the small vosk STT model"
|
description = "Build program with the small vosk STT model"
|
||||||
dependsOn("prepareLiteResources", "build")
|
dependsOn("prepareLiteResources", "package")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register("buildFull") {
|
tasks.register("packageFullInstaller") {
|
||||||
|
group = "package project"
|
||||||
description = "Build program with the large vosk STT model"
|
description = "Build program with the large vosk STT model"
|
||||||
dependsOn("prepareFullResources", "build")
|
dependsOn("prepareFullResources", "package")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tasks.register("generateSemanticModel") {
|
tasks.register("generateSemanticModel") {
|
||||||
|
group = "package project"
|
||||||
description = "Run DJL to generate Semantic model from HuggingFace (all-roberta-large-v1)"
|
description = "Run DJL to generate Semantic model from HuggingFace (all-roberta-large-v1)"
|
||||||
|
|
||||||
val exeDir = ""
|
|
||||||
val modelName = "sentence-transformers/all-roberta-large-v1"
|
val modelName = "sentence-transformers/all-roberta-large-v1"
|
||||||
val djlOutputDir = project.file("src/main/resources/Semantic-model")
|
val djlOutputDir = project.file("src/main/resources/Semantic-model")
|
||||||
|
|
||||||
|
|
@ -106,9 +125,9 @@ tasks.register("generateSemanticModel") {
|
||||||
doLast {
|
doLast {
|
||||||
val os = System.getProperty("os.name")
|
val os = System.getProperty("os.name")
|
||||||
val executable = when {
|
val executable = when {
|
||||||
os.contains("win") -> project.file("$exeDir/djl-windows.exe")
|
currentOs.isWindows -> project.file("djl/windows.exe")
|
||||||
os.contains("mac") -> project.file("$exeDir/djl-mac")
|
currentOs.isMacOsX -> project.file("djl/mac")
|
||||||
os.contains("linux") || os.contains("nix") || os.contains("nux") -> project.file("$exeDir/djl-linux")
|
currentOs.isLinux -> project.file("djl/linux")
|
||||||
else -> throw GradleException("Unsupported OS: $os")
|
else -> throw GradleException("Unsupported OS: $os")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,6 +142,7 @@ val modelUrl = "https://alphacephei.com/vosk/models"
|
||||||
val zipFile = layout.buildDirectory.file("STT-model.zip")
|
val zipFile = layout.buildDirectory.file("STT-model.zip")
|
||||||
|
|
||||||
tasks.register<Download>("prepareLiteResources") {
|
tasks.register<Download>("prepareLiteResources") {
|
||||||
|
group = "package project"
|
||||||
description = "Download small vosk model to resources"
|
description = "Download small vosk model to resources"
|
||||||
|
|
||||||
val modelName = "vosk-model-small-en-us-0.15"
|
val modelName = "vosk-model-small-en-us-0.15"
|
||||||
|
|
@ -144,6 +164,7 @@ tasks.register<Download>("prepareLiteResources") {
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register<Download>("prepareFullResources") {
|
tasks.register<Download>("prepareFullResources") {
|
||||||
|
group = "package project"
|
||||||
description = "Download large vosk model to resources"
|
description = "Download large vosk model to resources"
|
||||||
|
|
||||||
val modelName = "vosk-model-en-us-0.22"
|
val modelName = "vosk-model-en-us-0.22"
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,4 @@ fun transparentButton(icon: ImageVector, contentDescription: String, onClick: ()
|
||||||
contentDescription = contentDescription
|
contentDescription = contentDescription
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: If folders (Semantic-model/, STT-model/) don't exist on start-up install
|
|
||||||
// Install Semantic-model by downloading, using djl-converter (look into using pip module from Java), move to resources
|
|
||||||
// Install STT-model by downloading, move to resources
|
|
||||||
|
|
@ -42,6 +42,7 @@ import kotlinx.serialization.SerializationException
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.decodeFromStream
|
import kotlinx.serialization.json.decodeFromStream
|
||||||
import kotlinx.serialization.json.encodeToStream
|
import kotlinx.serialization.json.encodeToStream
|
||||||
|
import logger
|
||||||
import transparentButton
|
import transparentButton
|
||||||
import ui.Profiles.Companion.Dialogs.Companion.activateDialog
|
import ui.Profiles.Companion.Dialogs.Companion.activateDialog
|
||||||
import ui.Profiles.Companion.Dialogs.Companion.deleteDialog
|
import ui.Profiles.Companion.Dialogs.Companion.deleteDialog
|
||||||
|
|
@ -102,9 +103,13 @@ class Profiles {
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
fun save(profile: Profile) {
|
fun save(profile: Profile) {
|
||||||
val stream = FileOutputStream(getProfileLocation(profile.name))
|
val stream = FileOutputStream(getProfileLocation(profile.name))
|
||||||
Json.encodeToStream(profile, stream)
|
val json = Json { prettyPrint = true }
|
||||||
|
|
||||||
|
json.encodeToStream(profile, stream)
|
||||||
stream.flush()
|
stream.flush()
|
||||||
stream.close()
|
stream.close()
|
||||||
|
logger.info { "Profile Saved: ${profile.name}.profile" }
|
||||||
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,48 @@
|
||||||
package ui.screens
|
package ui.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.TooltipArea
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material.Button
|
||||||
|
import androidx.compose.material.Icon
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.material.TextField
|
||||||
|
import androidx.compose.material.TextFieldDefaults
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.FileOpen
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import cafe.adriel.voyager.core.screen.Screen
|
import cafe.adriel.voyager.core.screen.Screen
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
|
||||||
import ui.Profiles.Companion.Dialogs.Companion.activateDialog
|
import ui.Profiles.Companion.Dialogs.Companion.activateDialog
|
||||||
import ui.Profiles.Companion.Buttons.Companion.activateButton
|
import ui.Profiles.Companion.Buttons.Companion.activateButton
|
||||||
import ui.Profiles.Companion.Buttons.Companion.saveButton
|
import ui.Profiles.Companion.Buttons.Companion.saveButton
|
||||||
import ui.Profiles.Companion.Buttons.Companion.deleteButton
|
import ui.Profiles.Companion.Buttons.Companion.deleteButton
|
||||||
import ui.Profiles.Companion.Dialogs.Companion.deleteDialog
|
import ui.Profiles.Companion.Dialogs.Companion.deleteDialog
|
||||||
import ui.Profiles.Companion.Entities.Profile
|
import ui.Profiles.Companion.Entities.Profile
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.github.vinceglb.filekit.core.FileKit
|
||||||
|
import io.github.vinceglb.filekit.core.PickerMode
|
||||||
|
import io.github.vinceglb.filekit.core.PickerType
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import logger
|
||||||
|
|
||||||
class ProfileDetails(val profile: Profile): Screen {
|
class ProfileDetails(val profile: Profile): Screen {
|
||||||
/**
|
/**
|
||||||
|
|
@ -23,22 +53,156 @@ class ProfileDetails(val profile: Profile): Screen {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() { //TODO: Description of what each attribute represents
|
override fun Content() {
|
||||||
Column {
|
Row {
|
||||||
Text("Name: ${profile.name}") //TODO: Text Field
|
generalAttributes()
|
||||||
Text("AI name: ${profile.aiName}") //TODO: Text Field
|
commands()
|
||||||
Text("Program name: ${profile.programName}") //TODO: Text Field
|
}
|
||||||
Text("Program path: ${profile.programPath}") //TODO: FileDialog
|
}
|
||||||
|
|
||||||
Row {
|
@Composable
|
||||||
activateButton(profile)
|
fun commands() {
|
||||||
saveButton(profile)
|
//TODO: Display commands
|
||||||
deleteButton(profile)
|
}
|
||||||
activateDialog(profile)
|
|
||||||
deleteDialog(profile)
|
@Composable
|
||||||
|
fun generalAttributes() {
|
||||||
|
Column {
|
||||||
|
textAttribute(
|
||||||
|
title = "Name",
|
||||||
|
tooltip = "This is the name of the profile. It also acts as the name of the saved file.",
|
||||||
|
currentValue = profile.name,
|
||||||
|
onValueChange = { newValue ->
|
||||||
|
profile.name = newValue
|
||||||
|
logger.info { "Profile Attribute Changed: name = $newValue" }
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
textAttribute(
|
||||||
|
title = "AI name",
|
||||||
|
tooltip = "This is the name you want to refer to the program as. It will also serve as the trigger word for commands.",
|
||||||
|
currentValue = profile.aiName,
|
||||||
|
onValueChange = { newValue ->
|
||||||
|
profile.aiName = newValue
|
||||||
|
logger.info { "Profile Attribute Changed: ai_name = $newValue" }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
textAttribute(
|
||||||
|
title = "Program name",
|
||||||
|
tooltip = "This is the name of the window you want to control.",
|
||||||
|
currentValue = profile.programName,
|
||||||
|
onValueChange = { newValue ->
|
||||||
|
profile.programName = newValue
|
||||||
|
logger.info { "Profile Attribute Changed: program_name = $newValue" }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
pathAttribute(
|
||||||
|
title = "Program path",
|
||||||
|
tooltip = "This is the absolute path to the program you want to control.",
|
||||||
|
currentValue = profile.programPath,
|
||||||
|
onValueChange = { newValue ->
|
||||||
|
profile.programPath = newValue
|
||||||
|
logger.info { "Profile Attribute Changed: program_path = $newValue" }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
buttons()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
@Composable
|
||||||
|
fun pathAttribute(title: String, currentValue: String, tooltip: String, onValueChange: (String) -> Unit) {
|
||||||
|
var fieldValue by remember { mutableStateOf(currentValue) }
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
textAttribute(
|
||||||
|
title = title,
|
||||||
|
tooltip = tooltip,
|
||||||
|
currentValue = profile.programName,
|
||||||
|
onValueChange = onValueChange
|
||||||
|
)
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
CoroutineScope(Dispatchers.IO + SupervisorJob()).async {
|
||||||
|
fieldValue = FileKit.pickFile(
|
||||||
|
title = "Pick program path",
|
||||||
|
type = PickerType.File(),
|
||||||
|
mode = PickerMode.Single,
|
||||||
|
initialDirectory = null,
|
||||||
|
)?.path.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.FileOpen,
|
||||||
|
contentDescription = "Choose File"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: Display commands
|
|
||||||
// Allow editing. on unFocus, update profile entry
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Composable
|
||||||
|
fun buttons() {
|
||||||
|
Row {
|
||||||
|
activateButton(profile)
|
||||||
|
Spacer(Modifier.width(10.dp))
|
||||||
|
saveButton(profile)
|
||||||
|
Spacer(Modifier.width(10.dp))
|
||||||
|
deleteButton(profile)
|
||||||
|
|
||||||
|
activateDialog(profile)
|
||||||
|
deleteDialog(profile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
@Composable
|
||||||
|
fun textAttribute(title: String, currentValue: String, tooltip: String, onValueChange: (String) -> Unit) {
|
||||||
|
var fieldText by remember { mutableStateOf(currentValue) }
|
||||||
|
TooltipArea(
|
||||||
|
tooltip = {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.wrapContentSize()
|
||||||
|
.background(MaterialTheme.colors.primary, CircleShape)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(10.dp),
|
||||||
|
text = tooltip,
|
||||||
|
color = MaterialTheme.colors.onPrimary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
TextField(
|
||||||
|
colors = TextFieldDefaults.textFieldColors(
|
||||||
|
textColor = MaterialTheme.colors.onBackground,
|
||||||
|
backgroundColor = Color.Transparent
|
||||||
|
),
|
||||||
|
value = fieldText,
|
||||||
|
onValueChange = { newValue ->
|
||||||
|
onValueChange(newValue)
|
||||||
|
fieldText = newValue
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
Text(
|
||||||
|
text = "$title:"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue