Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion FloconAndroid/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
agp = "8.11.0-rc02"
apollo = "4.0.0"
coilCompose = "3.2.0"
compose = "1.11.0"
compose = "1.12.0"
datastorePreferences = "1.1.7"
kotlin = "2.4.0"
mavenPublish = "0.34.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
@file:OptIn(ExperimentalComposeUiApi::class)

package io.github.openflocon.flocon.myapplication.multi

import androidx.compose.ui.window.Window
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.window.application
import androidx.compose.ui.window.v2.Window
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.driver.bundled.BundledSQLiteDriver
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
@file:OptIn(ExperimentalComposeUiApi::class)

package io.github.openflocon.flocon.myapplication.multi

import androidx.compose.ui.window.Window
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.window.application
import androidx.compose.ui.window.v2.Window
import io.github.openflocon.flocon.ktor.FloconKtorPlugin
import io.github.openflocon.flocon.myapplication.multi.ui.App
import io.ktor.client.HttpClient
Expand Down
1 change: 1 addition & 0 deletions FloconDesktop/composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ kotlin {
// Pour Kotlin 1.9+
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
freeCompilerArgs.add("-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi")
freeCompilerArgs.add("-opt-in=androidx.compose.ui.ExperimentalComposeUiApi")
freeCompilerArgs.add("-Xcontext-parameters")
freeCompilerArgs.add("-Xcontext-sensitive-resolution")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,63 +1 @@
package io.github.openflocon.flocondesktop.common.ui.window

import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.type
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowPlacement
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.WindowState
import flocondesktop.composeapp.generated.resources.Res
import flocondesktop.composeapp.generated.resources.app_icon
import io.github.openflocon.library.designsystem.components.escape.LocalEscapeHandlerStack
import org.jetbrains.compose.resources.painterResource

data class FloconWindowStateDesktop(
val windowState: WindowState,
) : FloconWindowState

actual fun createFloconWindowState(size: DpSize?): FloconWindowState = FloconWindowStateDesktop(
WindowState(
placement = WindowPlacement.Floating,
position = WindowPosition(Alignment.Center),
size = size ?: defaultWindowSize
)
)

// TODO Use this component for main window too
@Composable
actual fun FloconWindow(
title: String,
state: FloconWindowState,
onCloseRequest: () -> Unit,
alwaysOnTop: Boolean,
content: @Composable () -> Unit,
) {
val handlers = remember { mutableStateListOf<() -> Boolean>() }

Window(
title = title,
icon = painterResource(Res.drawable.app_icon),
state = (state as FloconWindowStateDesktop).windowState,
alwaysOnTop = alwaysOnTop,
onPreviewKeyEvent = {
when (it.key) {
Key.Escape if (it.type == KeyEventType.KeyDown) -> handlers.lastOrNull()?.invoke() ?: false

else -> false
}
},
onCloseRequest = onCloseRequest,
) {
CompositionLocalProvider(LocalEscapeHandlerStack provides handlers) {
content()
}
}
}
// File moved to src/desktopMain/kotlin/io/github/openflocon/flocondesktop/common/ui/window/FloconWindow.desktop.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:OptIn(ExperimentalComposeUiApi::class)

package io.github.openflocon.flocondesktop

import androidx.compose.runtime.Composable
Expand All @@ -8,17 +10,19 @@ import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.type
import androidx.compose.ui.unit.size
import androidx.compose.ui.window.ApplicationScope
import androidx.compose.ui.window.Notification
import androidx.compose.ui.window.Tray
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberTrayState
import androidx.compose.ui.window.rememberWindowState
import androidx.compose.ui.window.v2.Window
import androidx.compose.ui.window.v2.rememberWindowState
import coil3.ImageLoader
import coil3.compose.setSingletonImageLoaderFactory
import coil3.network.ktor3.KtorNetworkFetcherFactory
Expand All @@ -31,8 +35,7 @@ import io.github.openflocon.flocondesktop.window.MIN_WINDOW_HEIGHT
import io.github.openflocon.flocondesktop.window.MIN_WINDOW_WIDTH
import io.github.openflocon.flocondesktop.window.WindowStateData
import io.github.openflocon.flocondesktop.window.WindowStateSaver
import io.github.openflocon.flocondesktop.window.size
import io.github.openflocon.flocondesktop.window.windowPosition
import io.github.openflocon.flocondesktop.window.windowBoundsProvider
import io.github.openflocon.library.designsystem.components.escape.LocalEscapeHandlerStack
import org.jetbrains.compose.resources.painterResource
import org.koin.compose.koinInject
Expand All @@ -54,8 +57,7 @@ fun main() {
var openAbout by remember { mutableStateOf(false) }
val savedState = remember { WindowStateSaver.load() }
val windowState = rememberWindowState(
size = savedState.size(),
position = savedState.windowPosition(),
initialBoundsProvider = savedState.windowBoundsProvider(),
)

with(Desktop.getDesktop()) {
Expand All @@ -77,16 +79,17 @@ fun main() {
Window(
state = windowState,
onCloseRequest = {
val currentSize = windowState.size
val currentPosition = windowState.position
WindowStateSaver.save(
WindowStateData(
width = currentSize.width.value.toInt(),
height = currentSize.height.value.toInt(),
x = currentPosition.x.value.toInt(),
y = currentPosition.y.value.toInt(),
),
)
if (windowState.isInitialized) {
val currentBounds = windowState.bounds
WindowStateSaver.save(
WindowStateData(
width = currentBounds.size.width.value.toInt(),
height = currentBounds.size.height.value.toInt(),
x = currentBounds.left.value.toInt(),
y = currentBounds.top.value.toInt(),
),
)
}

exitApplication()
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowPlacement
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.rememberWindowState
import androidx.compose.ui.window.v2.Window
import androidx.compose.ui.window.v2.WindowBoundsProvider
import androidx.compose.ui.window.v2.WindowPositionProvider
import androidx.compose.ui.window.v2.rememberWindowState
import flocondesktop.composeapp.generated.resources.Res
import flocondesktop.composeapp.generated.resources.app_icon
import io.github.openflocon.flocondesktop.BuildConfig
Expand All @@ -40,10 +41,11 @@ internal fun AboutScreen(
title = "About",
onCloseRequest = onCloseRequest,
state = rememberWindowState(
placement = WindowPlacement.Floating,
position = WindowPosition(Alignment.Center),
size = DpSize(Dp.Unspecified, Dp.Unspecified)
)
initialPlacement = WindowPlacement.Floating,
initialBoundsProvider = WindowBoundsProvider(
positionProvider = WindowPositionProvider.CenteredOnScreen,
),
),
) {
FloconSurface {
Column(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package io.github.openflocon.flocondesktop.common.ui.window

import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.type
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.window.WindowPlacement
import androidx.compose.ui.window.v2.Window
import androidx.compose.ui.window.v2.WindowBoundsProvider
import androidx.compose.ui.window.v2.WindowPositionProvider
import androidx.compose.ui.window.v2.WindowState
import flocondesktop.composeapp.generated.resources.Res
import flocondesktop.composeapp.generated.resources.app_icon
import io.github.openflocon.library.designsystem.components.escape.LocalEscapeHandlerStack
import org.jetbrains.compose.resources.painterResource

data class FloconWindowStateDesktop(
val windowState: WindowState,
) : FloconWindowState

actual fun createFloconWindowState(size: DpSize?): FloconWindowState = FloconWindowStateDesktop(
WindowState(
initialPlacement = WindowPlacement.Floating,
initialBoundsProvider = WindowBoundsProvider(
sizeProvider = { size ?: defaultWindowSize },
positionProvider = WindowPositionProvider.CenteredOnScreen,
),
),
)

// TODO Use this component for main window too
@Composable
actual fun FloconWindow(
title: String,
state: FloconWindowState,
onCloseRequest: () -> Unit,
alwaysOnTop: Boolean,
content: @Composable () -> Unit,
) {
val handlers = remember { mutableStateListOf<() -> Boolean>() }

Window(
title = title,
icon = painterResource(Res.drawable.app_icon),
state = (state as FloconWindowStateDesktop).windowState,
alwaysOnTop = alwaysOnTop,
onPreviewKeyEvent = {
when (it.key) {
Key.Escape if (it.type == KeyEventType.KeyDown) -> handlers.lastOrNull()?.invoke() ?: false

else -> false
}
},
onCloseRequest = onCloseRequest,
) {
CompositionLocalProvider(LocalEscapeHandlerStack provides handlers) {
content()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ package io.github.openflocon.flocondesktop.window

import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.v2.WindowBoundsProvider
import androidx.compose.ui.window.v2.WindowPositionProvider
import java.awt.Toolkit
import kotlin.math.min

fun WindowStateData?.windowPosition() = this?.let { WindowPosition(x.dp, y.dp) } ?: WindowPosition.PlatformDefault
fun WindowStateData?.windowPositionProvider(): WindowPositionProvider =
this?.let { WindowPositionProvider.Absolute(x.dp, y.dp) } ?: WindowPositionProvider.Default

fun WindowStateData?.size(): DpSize {
val screenSize = Toolkit.getDefaultToolkit().screenSize

Expand All @@ -23,3 +26,9 @@ fun WindowStateData?.size(): DpSize {
width = width, height = height,
)
}

fun WindowStateData?.windowBoundsProvider(): WindowBoundsProvider =
WindowBoundsProvider(
positionProvider = windowPositionProvider(),
sizeProvider = { size() },
)
2 changes: 1 addition & 1 deletion FloconDesktop/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[versions]
about-libraries = "15.0.2"
agp = "9.2.0"
androidx-lifecycle = "2.11.0-rc01"
androidx-lifecycle = "2.11.0"
buildconfig = "6.0.10"
coil = "3.5.0"
compose-multiplatform = "1.12.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
@file:OptIn(ExperimentalUuidApi::class)
@file:OptIn(ExperimentalUuidApi::class, ExperimentalComposeUiApi::class)

package io.github.openflocon.navigation.scene

import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.rememberWindowState
import androidx.compose.ui.window.v2.DialogWindow
import androidx.compose.ui.window.v2.WindowBoundsProvider
import androidx.compose.ui.window.v2.WindowPositionProvider
import androidx.compose.ui.window.v2.rememberDialogState
import androidx.navigation3.runtime.NavEntry
import androidx.navigation3.runtime.NavMetadataKey
import androidx.navigation3.runtime.get
Expand All @@ -23,7 +26,7 @@ import kotlin.uuid.ExperimentalUuidApi
data class WindowScene(
private val entry: NavEntry<FloconRoute>,
override val previousEntries: List<NavEntry<FloconRoute>>,
private val onBack: () -> Unit
private val onBack: () -> Unit,
) : OverlayScene<FloconRoute> {

override val key: Any = entry.contentKey
Expand All @@ -34,10 +37,16 @@ data class WindowScene(
override val content: @Composable (() -> Unit) = {
val windowProperties = entry.metadata[WindowPropertiesKey]

val state = rememberWindowState(
size = windowProperties?.size ?: DpSize(800.dp, 600.dp),
val state = rememberDialogState(
initialBoundsProvider = WindowBoundsProvider(
sizeProvider = {
windowProperties?.size ?: DpSize(800.dp, 600.dp)
},
positionProvider = WindowPositionProvider.CenteredInParentWindow,
),
)
Window(

DialogWindow(
onCloseRequest = onBack,
state = state,
title = windowProperties?.title ?: "",
Expand All @@ -56,7 +65,7 @@ class WindowSceneStrategy : SceneStrategy<FloconRoute> {
return WindowScene(
entry = entry,
previousEntries = entries.dropLast(1),
onBack = onBack
onBack = onBack,
)
}

Expand All @@ -72,9 +81,9 @@ class WindowSceneStrategy : SceneStrategy<FloconRoute> {

data class WindowProperties(
val size: DpSize? = null,
val title: String? = null
val title: String? = null,
) {
val isWindow: Boolean = true
}

private object WindowPropertiesKey: NavMetadataKey<WindowProperties>
private object WindowPropertiesKey : NavMetadataKey<WindowProperties>
Loading