Compare commits
2
Commits
8f5d5d1ca8
...
22c0a61e32
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22c0a61e32 | ||
|
|
057be15822 |
@@ -1,4 +1,4 @@
|
||||
.PHONY: android desktop android-usb android-emulator
|
||||
.PHONY: android desktop desktop-install android-usb android-emulator
|
||||
|
||||
ADB := $(shell command -v adb 2>/dev/null || echo "$(HOME)/Library/Android/sdk/platform-tools/adb")
|
||||
EMULATOR := $(shell command -v emulator 2>/dev/null || echo "$(HOME)/Library/Android/sdk/emulator/emulator")
|
||||
@@ -11,6 +11,10 @@ android:
|
||||
desktop:
|
||||
./gradlew composeApp:run
|
||||
|
||||
desktop-install:
|
||||
./gradlew composeApp:packageDistributionForCurrentOS
|
||||
cp -R composeApp/build/compose/binaries/main/app/myicek.app /Applications/myicek.app
|
||||
|
||||
android-usb: android
|
||||
$(ADB) -d install -r $(APK)
|
||||
$(ADB) -d shell am start -n ch.parano.myicek/.MainActivity
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// MyIce Kotlin Multiplatform — schedule/convocation viewer
|
||||
// Copyright (C) 2026 parano.ch
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package ch.parano.myicek
|
||||
|
||||
import com.russhwolf.settings.Settings
|
||||
|
||||
data class SavedWindowState(
|
||||
val width: Int,
|
||||
val height: Int,
|
||||
val x: Int,
|
||||
val y: Int,
|
||||
)
|
||||
|
||||
class WindowStateStorage(private val settings: Settings) {
|
||||
|
||||
companion object {
|
||||
private const val WIDTH_KEY = "window_width"
|
||||
private const val HEIGHT_KEY = "window_height"
|
||||
private const val X_KEY = "window_x"
|
||||
private const val Y_KEY = "window_y"
|
||||
}
|
||||
|
||||
fun save(width: Int, height: Int, x: Int, y: Int) {
|
||||
settings.putInt(WIDTH_KEY, width)
|
||||
settings.putInt(HEIGHT_KEY, height)
|
||||
settings.putInt(X_KEY, x)
|
||||
settings.putInt(Y_KEY, y)
|
||||
}
|
||||
|
||||
fun load(): SavedWindowState? {
|
||||
val width = settings.getIntOrNull(WIDTH_KEY) ?: return null
|
||||
val height = settings.getIntOrNull(HEIGHT_KEY) ?: return null
|
||||
val x = settings.getIntOrNull(X_KEY) ?: return null
|
||||
val y = settings.getIntOrNull(Y_KEY) ?: return null
|
||||
return SavedWindowState(width, height, x, y)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// MyIce Kotlin Multiplatform — schedule/convocation viewer
|
||||
// Copyright (C) 2026 parano.ch
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package ch.parano.myicek
|
||||
|
||||
import com.russhwolf.settings.MapSettings
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class WindowStateStorageTest {
|
||||
|
||||
@Test
|
||||
fun saveAndLoadWindowState() {
|
||||
val settings = MapSettings()
|
||||
val storage = WindowStateStorage(settings)
|
||||
|
||||
storage.save(width = 1200, height = 800, x = 100, y = 50)
|
||||
|
||||
val state = storage.load()
|
||||
assertEquals(1200, state?.width)
|
||||
assertEquals(800, state?.height)
|
||||
assertEquals(100, state?.x)
|
||||
assertEquals(50, state?.y)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun loadReturnsNullWhenNothingSaved() {
|
||||
val settings = MapSettings()
|
||||
val storage = WindowStateStorage(settings)
|
||||
|
||||
assertNull(storage.load())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun saveOverwritesPreviousState() {
|
||||
val settings = MapSettings()
|
||||
val storage = WindowStateStorage(settings)
|
||||
|
||||
storage.save(width = 1200, height = 800, x = 100, y = 50)
|
||||
storage.save(width = 1024, height = 768, x = 200, y = 75)
|
||||
|
||||
val state = storage.load()
|
||||
assertEquals(1024, state?.width)
|
||||
assertEquals(768, state?.height)
|
||||
assertEquals(200, state?.x)
|
||||
assertEquals(75, state?.y)
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,43 @@
|
||||
|
||||
package ch.parano.myicek
|
||||
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.WindowPosition
|
||||
import androidx.compose.ui.window.application
|
||||
import androidx.compose.ui.window.rememberWindowState
|
||||
import ch.parano.myicek.auth.DesktopOAuthClient
|
||||
import com.russhwolf.settings.Settings
|
||||
import java.util.prefs.Preferences
|
||||
|
||||
fun main() = application {
|
||||
Window(onCloseRequest = ::exitApplication, title = "MyIce") {
|
||||
val storage = WindowStateStorage(Settings())
|
||||
val saved = storage.load()
|
||||
val windowState = rememberWindowState(
|
||||
width = saved?.width?.dp ?: 1024.dp,
|
||||
height = saved?.height?.dp ?: 768.dp,
|
||||
position = if (saved != null) WindowPosition(saved.x.dp, saved.y.dp) else WindowPosition(0.dp, 0.dp),
|
||||
)
|
||||
|
||||
Window(
|
||||
onCloseRequest = ::exitApplication,
|
||||
title = "MyIce",
|
||||
state = windowState,
|
||||
) {
|
||||
LaunchedEffect(Unit) {
|
||||
snapshotFlow { windowState.size to windowState.position }
|
||||
.collect { (size, position) ->
|
||||
storage.save(
|
||||
width = size.width.value.toInt(),
|
||||
height = size.height.value.toInt(),
|
||||
x = position.x.value.toInt(),
|
||||
y = position.y.value.toInt(),
|
||||
)
|
||||
Preferences.userRoot().flush()
|
||||
}
|
||||
}
|
||||
App(oauthClient = DesktopOAuthClient())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user