From 27aabc139dbabba7d1e1d5db1e5f2cf2257b0fb7 Mon Sep 17 00:00:00 2001 From: dotmg Date: Tue, 6 Jan 2026 20:15:57 +0100 Subject: [PATCH] Remember window position --- .../kotlin/mg/dot/feufaro/ConfigPaths.kt | 9 ++ .../kotlin/mg/dot/feufaro/ConfigPaths.kt | 3 + .../kotlin/mg/dot/feufaro/FileRepository.kt | 106 ++++++++++++++++++ .../kotlin/mg/dot/feufaro/WindowState.kt | 8 ++ .../kotlin/mg/dot/feufaro/ConfigPaths.kt | 5 + .../desktopMain/kotlin/mg/dot/feufaro/main.kt | 42 ++++++- 6 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 composeApp/src/androidMain/kotlin/mg/dot/feufaro/ConfigPaths.kt create mode 100644 composeApp/src/commonMain/kotlin/mg/dot/feufaro/ConfigPaths.kt create mode 100644 composeApp/src/commonMain/kotlin/mg/dot/feufaro/WindowState.kt create mode 100644 composeApp/src/desktopMain/kotlin/mg/dot/feufaro/ConfigPaths.kt diff --git a/composeApp/src/androidMain/kotlin/mg/dot/feufaro/ConfigPaths.kt b/composeApp/src/androidMain/kotlin/mg/dot/feufaro/ConfigPaths.kt new file mode 100644 index 0000000..a48fc12 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/mg/dot/feufaro/ConfigPaths.kt @@ -0,0 +1,9 @@ +package mg.dot.feufaro + +import android.content.Context +import org.koin.core.context.GlobalContext + +actual fun getConfigDirectoryPath(): String { + val context = GlobalContext.get().get() + return context.filesDir.absolutePath +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/ConfigPaths.kt b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/ConfigPaths.kt new file mode 100644 index 0000000..3796b8f --- /dev/null +++ b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/ConfigPaths.kt @@ -0,0 +1,3 @@ +package mg.dot.feufaro + +expect fun getConfigDirectoryPath(): String \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/FileRepository.kt b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/FileRepository.kt index d04e5c8..e97ef4d 100644 --- a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/FileRepository.kt +++ b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/FileRepository.kt @@ -17,6 +17,14 @@ interface FileRepository { // Lecture de fichier entier en tant que String 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. @@ -54,4 +62,102 @@ class CommonFileRepository : FileRepository { // IMPORTS AND IMPLEMENTS THE comm } } + 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/WindowState.kt b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/WindowState.kt new file mode 100644 index 0000000..699a0ae --- /dev/null +++ b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/WindowState.kt @@ -0,0 +1,8 @@ +package mg.dot.feufaro + +data class WindowState( + val width: Int, + val height: Int, + val x: Int, + val y: Int +) \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/ConfigPaths.kt b/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/ConfigPaths.kt new file mode 100644 index 0000000..a7ff204 --- /dev/null +++ b/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/ConfigPaths.kt @@ -0,0 +1,5 @@ +package mg.dot.feufaro + +actual fun getConfigDirectoryPath(): String { + return System.getProperty("user.home") +} \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/main.kt b/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/main.kt index 3a630a4..afebcc5 100644 --- a/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/main.kt +++ b/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/main.kt @@ -1,13 +1,22 @@ package mg.dot.feufaro +import androidx.compose.ui.Alignment +import androidx.compose.ui.unit.DpSize +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 kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import mg.dot.feufaro.di.commonModule import mg.dot.feufaro.di.desktopModule +import org.koin.compose.KoinContext import org.koin.core.context.GlobalContext.startKoin import org.koin.core.context.KoinContext import org.koin.core.logger.Level -import org.koin.compose.KoinContext fun main() = application { @@ -20,8 +29,37 @@ 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) + } + ) + Window( - onCloseRequest = ::exitApplication, + 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", ) { KoinContext {