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(compose.desktop.currentOs)
//implementation("org.jetbrains.compose.foundation:foundation-desktop")
implementation("com.russhwolf:multiplatform-settings-no-arg:1.3.0")
//implementation(libs.ktmidi)
}

View file

@ -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<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
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 {

View file

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