From ccf21533768fb8d8d62e9b10273fc978daea9743 Mon Sep 17 00:00:00 2001 From: "hasinarak3@gmail.com" Date: Thu, 22 Jan 2026 11:01:59 +0300 Subject: [PATCH] fix Remember window position & last dir used --- composeApp/build.gradle.kts | 1 + .../kotlin/mg/dot/feufaro/FileRepository.kt | 105 ------------------ .../kotlin/mg/dot/feufaro/SaveSettings.kt | 43 +++++++ .../kotlin/mg/dot/feufaro/solfa/Solfa.kt | 10 +- .../desktopMain/kotlin/mg/dot/feufaro/main.kt | 34 ++---- 5 files changed, 60 insertions(+), 133 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/mg/dot/feufaro/SaveSettings.kt diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 5d0aceb..ed9d246 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -83,6 +83,7 @@ kotlin { implementation(kotlin("stdlib-jdk8")) implementation(compose.desktop.currentOs) //implementation("org.jetbrains.compose.foundation:foundation-desktop") + implementation("com.russhwolf:multiplatform-settings-no-arg:1.3.0") //implementation(libs.ktmidi) } diff --git a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/FileRepository.kt b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/FileRepository.kt index e97ef4d..d9133d9 100644 --- a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/FileRepository.kt +++ b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/FileRepository.kt @@ -18,13 +18,6 @@ interface FileRepository { suspend fun readFileContent(filePath: String): String suspend fun getOutputStream(filePath: String): OutputStream //Lire le dernier dossier d'importation - suspend fun readLastDirectoryPath(): String? - - //Enregistrer le dernier dossier d'importation - suspend fun saveLastDirectoryPath(path: String) - - suspend fun readWindowState(): WindowState? - suspend fun saveWindowState(state: WindowState) } // This is just a regular class that implements the common 'FileRepository' interface. @@ -60,104 +53,6 @@ class CommonFileRepository : FileRepository { // IMPORTS AND IMPLEMENTS THE comm println("Could not read /"+assetFileName.removePrefix("assets://")) throw IOException("Could not read asset file: $assetFileName", e) } - - } - private val CONFIG_FILE_NAME = "feufaro.conf" - private val configDir = getConfigDirectoryPath() - private val configFile: File get() = File(System.getProperty("user.home"), CONFIG_FILE_NAME) - - override suspend fun readLastDirectoryPath(): String? { - var file = configFile - var lastPath: String? = null - try { - val fileContents = file.readText().trim() - if(fileContents.startsWith("LAST_DIR: ")) { - lastPath = fileContents.substringAfter("LAST_DIR: ").trim() - } - } catch (e: Exception) { - System.err.println("Erreur de $CONFIG_FILE_NAME : ${e.message}") - } - return lastPath - } - - override suspend fun saveLastDirectoryPath(path: String) { - val pathDir = File(path).parent - if (pathDir != null) { - try { - var file = configFile - file.parentFile?.mkdirs() - //file.writeText(pathDir) - - configFile.writeText("LAST_DIR: $pathDir/") - } catch (e: Exception) { - System.err.println("Erreur d'écriture de $CONFIG_FILE_NAME : ${e.message}") - } - } - } - - override suspend fun saveWindowState(state: WindowState) = withContext(Dispatchers.IO) { - val file = configFile - - val allLines: MutableList = try { - file.readLines().toMutableList() - } catch (e: Exception) { - mutableListOf() - } - - while (allLines.size < 3) { - allLines.add("") - } - - val positionLine = "WINDOW_POS: ${state.x},${state.y}" - val sizeLine = "WINDOW_SIZE: ${state.width},${state.height}" - - allLines[1] = positionLine - allLines[2] = sizeLine - - try { - file.parentFile?.mkdirs() - - file.writeText(allLines.joinToString("\n")) - } catch (e: Exception) { - System.err.println("Erreur d'écriture du fichier .conf : ${e.message}") - } - } - - - override suspend fun readWindowState(): WindowState? = withContext(Dispatchers.IO) { - val file = configFile - if (!file.exists()) { - return@withContext null - } - val lines = try { - file.readLines() - } catch (e: Exception) { - System.err.println("Erreur de lecture : ${e.message}") - return@withContext null - } - - if (lines.size < 3) { - System.err.println("Fichier de configuration incomplet .") - //return@withContext null - } - - val posLine = lines[1].substringAfter("WINDOW_POS:", "").trim() - val posParts = posLine.split(",") - - val x = posParts.getOrNull(0)?.toIntOrNull() - val y = posParts.getOrNull(1)?.toIntOrNull() - - val sizeLine = lines[2].substringAfter("WINDOW_SIZE:", "").trim() - val sizeParts = sizeLine.split(",") - - val width = sizeParts.getOrNull(0)?.toIntOrNull() - val height = sizeParts.getOrNull(1)?.toIntOrNull() - - if (x != null && y != null && width != null && height != null) { - return@withContext WindowState(width, height, x, y) - } - - return@withContext null } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/SaveSettings.kt b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/SaveSettings.kt new file mode 100644 index 0000000..aa3a5d8 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/SaveSettings.kt @@ -0,0 +1,43 @@ +package mg.dot.feufaro + +import com.russhwolf.settings.Settings +import com.russhwolf.settings.set +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.WindowPlacement +import androidx.compose.ui.window.WindowState +import androidx.compose.ui.window.WindowPosition + +class SaveSettings { + + private val settings: Settings = Settings() + + fun loadLastUsedDir(): String { + val lastDirectory = settings.getString("last_dir", "/") + + return lastDirectory + } + + fun saveLastUsedDir(lastDir: String) { + settings["last_dir"] = lastDir + } + + fun loadWindowState(): WindowState { + val width = settings.getInt("window_width", 800) + val height = settings.getInt("window_height", 600) + val x = settings.getInt("window_x", 100) + val y = settings.getInt("window_y", 100) + + return WindowState( + size = DpSize(width.dp, height.dp), + position = WindowPosition(x.dp, y.dp) + ) + } + + fun saveWindowState(state: WindowState) { + settings["window_width"] = state.size.width.value.toInt() + settings["window_height"] = state.size.height.value.toInt() + settings["window_x"] = state.position.x.value.toInt() + settings["window_y"] = state.position.y.value.toInt() + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/Solfa.kt b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/Solfa.kt index d173334..8313cd1 100644 --- a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/Solfa.kt +++ b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/Solfa.kt @@ -1,12 +1,14 @@ package mg.dot.feufaro.solfa import SharedScreenModel +import androidx.compose.runtime.remember import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import mg.dot.feufaro.FileRepository +import mg.dot.feufaro.SaveSettings import mg.dot.feufaro.getConfigDirectoryPath import mg.dot.feufaro.launchFilePicker import mg.dot.feufaro.midi.MidiPitch @@ -146,19 +148,21 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository fun loadFile() { val screenModelScope= CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) + val stateSettings = SaveSettings() + screenModelScope.launch { - val initialPath = fileRepository.readLastDirectoryPath() + val initialPath = stateSettings.loadLastUsedDir() val homedir = getConfigDirectoryPath(); launchFilePicker( mimeTypes = arrayOf("text/plain"), - initialDirectory = initialPath, + initialDirectory = if (initialPath.isNotBlank()) initialPath else homedir, onFileSelected = { path -> if (path != null) { sharedScreenModel.reset() parse(path) screenModelScope.launch { - fileRepository.saveLastDirectoryPath(path) + stateSettings.saveLastUsedDir(path) } //loadSolfa() } else { diff --git a/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/main.kt b/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/main.kt index afebcc5..61d9783 100644 --- a/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/main.kt +++ b/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/main.kt @@ -1,5 +1,7 @@ package mg.dot.feufaro +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp @@ -29,35 +31,12 @@ fun main() = application { val fileRepository = org.koin.core.context.GlobalContext.get().get() println("FileRepository initialized for Desktop: $fileRepository") - val initialWindowState: WindowState? = runBlocking { - fileRepository.readWindowState() - } - val defaultWidth = 1200.dp - val defaultHeight = 800.dp - val windowState = rememberWindowState( - size = DpSize( - width = initialWindowState?.width?.dp ?: defaultWidth, - height = initialWindowState?.height?.dp ?: defaultHeight, - ), - position = if (initialWindowState != null) { - WindowPosition(initialWindowState.x.dp, initialWindowState.y.dp) - } else { - WindowPosition(Alignment.Center) - } - ) + val stateManager = remember { SaveSettings() } + val windowState = remember { stateManager.loadWindowState() } Window( state = windowState, onCloseRequest = { - val currentState = WindowState( - width = windowState.size.width.value.toInt(), - height = windowState.size.height.value.toInt(), - x = windowState.position.x.value.toInt(), - y = windowState.position.y.value.toInt() - ) - CoroutineScope(Dispatchers.IO).launch { - fileRepository.saveWindowState(currentState) - } exitApplication(); }, title = "Feufaro", @@ -65,5 +44,10 @@ fun main() = application { KoinContext { App() } + DisposableEffect(Unit){ + onDispose { + stateManager.saveWindowState(windowState) + } + } } } \ No newline at end of file