fix Remember window position & last dir used

This commit is contained in:
hasinarak3@gmail.com 2026-01-22 11:01:59 +03:00
parent 5cf90d54d4
commit ccf2153376
5 changed files with 60 additions and 133 deletions

View file

@ -83,6 +83,7 @@ kotlin {
implementation(kotlin("stdlib-jdk8")) implementation(kotlin("stdlib-jdk8"))
implementation(compose.desktop.currentOs) implementation(compose.desktop.currentOs)
//implementation("org.jetbrains.compose.foundation:foundation-desktop") //implementation("org.jetbrains.compose.foundation:foundation-desktop")
implementation("com.russhwolf:multiplatform-settings-no-arg:1.3.0")
//implementation(libs.ktmidi) //implementation(libs.ktmidi)
} }

View file

@ -18,13 +18,6 @@ interface FileRepository {
suspend fun readFileContent(filePath: String): String suspend fun readFileContent(filePath: String): String
suspend fun getOutputStream(filePath: String): OutputStream suspend fun getOutputStream(filePath: String): OutputStream
//Lire le dernier dossier d'importation //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. // 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://")) println("Could not read /"+assetFileName.removePrefix("assets://"))
throw IOException("Could not read asset file: $assetFileName", e) 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<String> = 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
} }
} }

View file

@ -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()
}
}

View file

@ -1,12 +1,14 @@
package mg.dot.feufaro.solfa package mg.dot.feufaro.solfa
import SharedScreenModel import SharedScreenModel
import androidx.compose.runtime.remember
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import mg.dot.feufaro.FileRepository import mg.dot.feufaro.FileRepository
import mg.dot.feufaro.SaveSettings
import mg.dot.feufaro.getConfigDirectoryPath import mg.dot.feufaro.getConfigDirectoryPath
import mg.dot.feufaro.launchFilePicker import mg.dot.feufaro.launchFilePicker
import mg.dot.feufaro.midi.MidiPitch import mg.dot.feufaro.midi.MidiPitch
@ -146,19 +148,21 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
fun loadFile() { fun loadFile() {
val screenModelScope= CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) val screenModelScope= CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
val stateSettings = SaveSettings()
screenModelScope.launch { screenModelScope.launch {
val initialPath = fileRepository.readLastDirectoryPath() val initialPath = stateSettings.loadLastUsedDir()
val homedir = getConfigDirectoryPath(); val homedir = getConfigDirectoryPath();
launchFilePicker( launchFilePicker(
mimeTypes = arrayOf("text/plain"), mimeTypes = arrayOf("text/plain"),
initialDirectory = initialPath, initialDirectory = if (initialPath.isNotBlank()) initialPath else homedir,
onFileSelected = { path -> onFileSelected = { path ->
if (path != null) { if (path != null) {
sharedScreenModel.reset() sharedScreenModel.reset()
parse(path) parse(path)
screenModelScope.launch { screenModelScope.launch {
fileRepository.saveLastDirectoryPath(path) stateSettings.saveLastUsedDir(path)
} }
//loadSolfa() //loadSolfa()
} else { } else {

View file

@ -1,5 +1,7 @@
package mg.dot.feufaro package mg.dot.feufaro
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -29,35 +31,12 @@ fun main() = application {
val fileRepository = org.koin.core.context.GlobalContext.get().get<FileRepository>() val fileRepository = org.koin.core.context.GlobalContext.get().get<FileRepository>()
println("FileRepository initialized for Desktop: $fileRepository") println("FileRepository initialized for Desktop: $fileRepository")
val initialWindowState: WindowState? = runBlocking { val stateManager = remember { SaveSettings() }
fileRepository.readWindowState() val windowState = remember { stateManager.loadWindowState() }
}
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( Window(
state = windowState, state = windowState,
onCloseRequest = { 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(); exitApplication();
}, },
title = "Feufaro", title = "Feufaro",
@ -65,5 +44,10 @@ fun main() = application {
KoinContext { KoinContext {
App() App()
} }
DisposableEffect(Unit){
onDispose {
stateManager.saveWindowState(windowState)
}
}
} }
} }