Skip to content

Commit

Permalink
Implement several desktop features
Browse files Browse the repository at this point in the history
Desktop:
- Set AWT window class on startup
- Rename settings 'server' category to 'desktop'
- Add launch command option
- Fix settings text field reset not applying to UI
  • Loading branch information
toasterofbread committed Nov 25, 2023
1 parent a350af0 commit 6aafd2d
Show file tree
Hide file tree
Showing 24 changed files with 141 additions and 93 deletions.
2 changes: 1 addition & 1 deletion ComposeKit
2 changes: 1 addition & 1 deletion androidApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ android {
}

defaultConfig {
versionCode = 10
versionCode = getString("version_code").toInt()
versionName = getString("version_string")

applicationId = "com.toasterofbread.spmp"
Expand Down
9 changes: 7 additions & 2 deletions desktopApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import java.nio.file.Files.getPosixFilePermissions
import java.nio.file.Files.setPosixFilePermissions
import java.nio.file.attribute.PosixFilePermission

val strings_file: File = rootProject.file("shared/src/commonMain/resources/assets/values/strings.xml")

plugins {
kotlin("multiplatform")
id("org.jetbrains.compose")
}

val strings_file: File = rootProject.file("shared/src/commonMain/resources/assets/values/strings.xml")

fun getString(key: String): String {
val reader = strings_file.reader()
val parser = org.xmlpull.v1.XmlPullParserFactory.newInstance().newPullParser()
Expand Down Expand Up @@ -58,6 +58,10 @@ compose.desktop {
application {
mainClass = "MainKt"

// Required for setting WM_CLASS in main.kt
// https://stackoverflow.com/a/69404254
jvmArgs += listOf("--add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED")

nativeDistributions {
packageName = getString("app_name")
version = getString("version_string")
Expand All @@ -69,6 +73,7 @@ compose.desktop {

linux {
iconFile.set(rootProject.file("metadata/en-US/images/icon.png"))
appRelease = getString("version_code")
}
}
}
Expand Down
61 changes: 42 additions & 19 deletions desktopApp/src/jvmMain/kotlin/main.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
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.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
Expand All @@ -19,14 +15,19 @@ import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
import com.toasterofbread.composekit.platform.composable.onWindowBackPressed
import com.toasterofbread.spmp.model.settings.category.DesktopSettings
import com.toasterofbread.spmp.platform.AppContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

private const val SCREEN_SIZE_UPDATE_INTERVAL: Long = 100
import kotlinx.coroutines.withContext
import org.jetbrains.skiko.OS
import org.jetbrains.skiko.hostOs
import java.awt.Toolkit
import java.lang.reflect.Field

@OptIn(ExperimentalComposeUiApi::class)
fun main() {
Expand All @@ -40,6 +41,11 @@ fun main() {

SpMp.onStart()

val toolkit: Toolkit = Toolkit.getDefaultToolkit()
val class_name_field: Field = toolkit.javaClass.getDeclaredField("awtAppClassName")
class_name_field.isAccessible = true
class_name_field.set(toolkit, SpMp.app_name.lowercase())

application {
Window(
title = SpMp.app_name,
Expand All @@ -52,25 +58,42 @@ fun main() {
},
state = rememberWindowState(size = DpSize(1280.dp, 720.dp), position = WindowPosition(Alignment.Center))
) {
var initialised by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
initialised = true
val startup_command: String = DesktopSettings.Key.STARTUP_COMMAND.get()
if (startup_command.isBlank()) {
return@LaunchedEffect
}

while (true) {
delay(SCREEN_SIZE_UPDATE_INTERVAL)
withContext(Dispatchers.IO) {
try {
val process_builder: ProcessBuilder =
when (hostOs) {
OS.Linux -> ProcessBuilder("bash", "-c", startup_command)
OS.Windows -> TODO()
else -> return@withContext
}

process_builder.inheritIO().start()
}
catch (e: Throwable) {
e.printStackTrace()
}

delay(2000)
context.sendToast("This is a toast")
delay(2000)
context.sendNotification("And this", "Is a goddamn notification")
}
}

if (initialised) {
SpMp.App(
Modifier.onPointerEvent(PointerEventType.Press) { event ->
// Mouse back click
if (event.button?.index == 5) {
onWindowBackPressed()
}
SpMp.App(
Modifier.onPointerEvent(PointerEventType.Press) { event ->
// Mouse back click
if (event.button?.index == 5) {
onWindowBackPressed()
}
)
}
}
)
}
}

Expand Down
6 changes: 3 additions & 3 deletions shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,13 @@ kotlin {

val androidMain by getting {
dependencies {
api("androidx.activity:activity-compose:1.7.2")
api("androidx.activity:activity-compose:1.8.1")
api("androidx.core:core-ktx:1.12.0")
api("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.palette:palette:1.0.0")
implementation("androidx.localbroadcastmanager:localbroadcastmanager:1.1.0")

val media3_version = "1.1.1"
val media3_version = "1.2.0"
implementation("androidx.media3:media3-exoplayer:$media3_version")
implementation("androidx.media3:media3-ui:$media3_version")
implementation("androidx.media3:media3-session:$media3_version")
Expand All @@ -180,7 +180,7 @@ kotlin {
implementation("com.anggrayudi:storage:1.5.5")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:1.6.0")
implementation("io.github.jan-tennert.supabase:functions-kt:1.3.2")
implementation("io.ktor:ktor-client-cio:2.3.4")
implementation("io.ktor:ktor-client-cio:2.3.6")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ class ErrorReportActivity : ComponentActivity() {
}
}
}) {
Icon(painterResource("drawable/ic_discord.xml"), null)
Icon(painterResource("assets/drawable/ic_discord.xml"), null)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.toasterofbread.spmp.model.settings.category

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.DesktopWindows
import com.toasterofbread.spmp.model.settings.SettingsKey
import com.toasterofbread.spmp.resources.getString
import com.toasterofbread.spmp.ui.layout.apppage.settingspage.category.getDesktopCategoryItems

data object DesktopSettings: SettingsCategory("desktop") {
override val keys: List<SettingsKey> = Key.values().toList()

override fun getPage(): Page? =
Page(
getString("s_cat_desktop"),
getString("s_cat_desc_desktop"),
{ getDesktopCategoryItems() }
) { Icons.Outlined.DesktopWindows }

enum class Key: SettingsKey {
STARTUP_COMMAND,

SERVER_IP_ADDRESS,
SERVER_PORT,
SERVER_LOCAL_COMMAND,
SERVER_KILL_CHILD_ON_EXIT;

override val category: SettingsCategory get() = DesktopSettings

@Suppress("UNCHECKED_CAST")
override fun <T> getDefaultValue(): T =
when (this) {
STARTUP_COMMAND -> ""
SERVER_IP_ADDRESS -> "127.0.0.1"
SERVER_PORT -> 3973
SERVER_LOCAL_COMMAND -> "spms"
SERVER_KILL_CHILD_ON_EXIT -> true
} as T
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalDensity
import com.toasterofbread.spmp.ProjectBuildConfig
import com.toasterofbread.spmp.model.settings.SettingsKey
import com.toasterofbread.spmp.platform.AppContext
import com.toasterofbread.spmp.platform.DiscordStatus
import com.toasterofbread.spmp.resources.getString
import com.toasterofbread.spmp.ui.layout.apppage.settingspage.category.getDiscordCategoryItems
Expand All @@ -29,7 +28,7 @@ data object DiscordSettings: SettingsCategory("discord") {
@OptIn(ExperimentalResourceApi::class)
@Composable
fun getIcon(): ImageVector =
resource("drawable/ic_discord.xml").readBytesSync().toImageVector(LocalDensity.current)
resource("assets/drawable/ic_discord.xml").readBytesSync().toImageVector(LocalDensity.current)

enum class Key: SettingsKey {
STATUS_DISABLE_WHEN_INVISIBLE,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,14 @@ sealed class SettingsCategory(id: String) {
this,
title
) {
override fun getItems(context: AppContext): List<SettingsItem>? =
getPageItems(context)
private var items: List<SettingsItem>? = null

override fun getItems(context: AppContext): List<SettingsItem>? {
if (items == null) {
items = getPageItems(context)
}
return items!!
}

override fun getTitleItem(context: AppContext): SettingsItem? =
ComposableSettingsItem { modifier ->
Expand All @@ -73,7 +79,7 @@ sealed class SettingsCategory(id: String) {
openPage(
SettingsPageWithItems(
getTitle = { title },
getItems = { getPageItems(context) },
getItems = { getItems(context)!! },
getIcon = { getPageIcon() }
)
)
Expand Down Expand Up @@ -115,7 +121,7 @@ sealed class SettingsCategory(id: String) {
DiscordAuthSettings,
FilterSettings,
StreamingSettings,
ServerSettings,
DesktopSettings,
MiscSettings,

YTApiSettings,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fun LoadingSplashView(splash_mode: SplashMode?, loading_message: String?, modifi
when (mode) {
null -> {}
SplashMode.SPLASH -> {
val image: ImageBitmap = bitmapResource("drawable/ic_splash.png")
val image: ImageBitmap = bitmapResource("assets/drawable/ic_splash.png")

Column(
Modifier.fillMaxSize().background(player.theme.background).padding(10.dp),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ private fun ProjectButton(modifier: Modifier = Modifier) {
}

Icon(
painterResource("drawable/ic_github.xml"),
painterResource("assets/drawable/ic_github.xml"),
null,
modifier.platformClickable(
onClick = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import com.toasterofbread.composekit.settings.ui.item.InfoTextSettingsItem
import com.toasterofbread.composekit.settings.ui.item.TextFieldSettingsItem
import com.toasterofbread.composekit.settings.ui.item.ToggleSettingsItem
import com.toasterofbread.composekit.settings.ui.item.SettingsValueState
import com.toasterofbread.spmp.model.settings.category.ServerSettings
import com.toasterofbread.spmp.model.settings.category.DesktopSettings
import com.toasterofbread.spmp.resources.getString

internal fun getServerCategoryItems(): List<SettingsItem> {
internal fun getDesktopCategoryItems(): List<SettingsItem> {
// (I will never learn regex)
// https://stackoverflow.com/a/36760050
val ip_regex: Regex = "^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}\$".toRegex()
Expand All @@ -19,12 +19,17 @@ internal fun getServerCategoryItems(): List<SettingsItem> {
check(port_regex.matches("1111"))

return listOf(
TextFieldSettingsItem(
SettingsValueState(DesktopSettings.Key.STARTUP_COMMAND.getName()),
getString("s_key_startup_command"), getString("s_sub_startup_command")
),

InfoTextSettingsItem(
getString("s_info_server")
),

TextFieldSettingsItem(
SettingsValueState(ServerSettings.Key.IP_ADDRESS.getName()),
SettingsValueState(DesktopSettings.Key.SERVER_IP_ADDRESS.getName()),
getString("s_key_server_ip"), null,
getStringError = { input ->
if (!ip_regex.matches(input)) {
Expand All @@ -36,7 +41,7 @@ internal fun getServerCategoryItems(): List<SettingsItem> {

TextFieldSettingsItem(
SettingsValueState(
ServerSettings.Key.PORT.getName(),
DesktopSettings.Key.SERVER_PORT.getName(),
getValueConverter = {
it?.toString()
},
Expand All @@ -54,12 +59,12 @@ internal fun getServerCategoryItems(): List<SettingsItem> {
),

TextFieldSettingsItem(
SettingsValueState(ServerSettings.Key.LOCAL_COMMAND.getName()),
SettingsValueState(DesktopSettings.Key.SERVER_LOCAL_COMMAND.getName()),
getString("s_key_server_command"), getString("s_sub_server_command")
),

ToggleSettingsItem(
SettingsValueState(ServerSettings.Key.KILL_CHILD_ON_EXIT.getName()),
SettingsValueState(DesktopSettings.Key.SERVER_KILL_CHILD_ON_EXIT.getName()),
getString("s_key_server_kill_child_on_exit"), null
)
)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 6aafd2d

Please sign in to comment.