From d99ad6ee2b33929e58aa512b62905324925806c0 Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Mon, 1 Sep 2025 10:02:44 +0200 Subject: [PATCH 01/28] feature: Add nav3 --- .../io/github/openflocon/flocondesktop/App.kt | 15 +++ FloconDesktop/gradle/libs.versions.toml | 14 ++- .../library/designsystem/build.gradle.kts | 7 ++ FloconDesktop/navigation/.gitignore | 1 + FloconDesktop/navigation/build.gradle.kts | 100 ++++++++++++++++++ .../navigation/ExampleInstrumentedTest.kt | 24 +++++ .../openflocon/navigation/ExampleUnitTest.kt | 16 +++ .../src/androidMain/AndroidManifest.xml | 4 + .../openflocon/navigation/Platform.android.kt | 3 + .../github/openflocon/navigation/Platform.kt | 3 + .../openflocon/navigation/Platform.ios.kt | 3 + FloconDesktop/settings.gradle.kts | 1 + 12 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 FloconDesktop/navigation/.gitignore create mode 100644 FloconDesktop/navigation/build.gradle.kts create mode 100644 FloconDesktop/navigation/src/androidDeviceTest/kotlin/io/github/openflocon/navigation/ExampleInstrumentedTest.kt create mode 100644 FloconDesktop/navigation/src/androidHostTest/kotlin/io/github/openflocon/navigation/ExampleUnitTest.kt create mode 100644 FloconDesktop/navigation/src/androidMain/AndroidManifest.xml create mode 100644 FloconDesktop/navigation/src/androidMain/kotlin/io/github/openflocon/navigation/Platform.android.kt create mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/Platform.kt create mode 100644 FloconDesktop/navigation/src/iosMain/kotlin/io/github/openflocon/navigation/Platform.ios.kt diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt index e3643e523..07a1f81ee 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt @@ -113,3 +113,18 @@ fun App() { } } } + +@Composable +private fun Navigation() { + val backStack = remember { mutableStateListOf() } + + NavDisplay( + backStack = backStack, + entryDecorators = listOf( + rememberSceneSetupNavEntryDecorator(), + rememberSavedStateNavEntryDecorator() + ) + ) { + + } +} diff --git a/FloconDesktop/gradle/libs.versions.toml b/FloconDesktop/gradle/libs.versions.toml index ff661dd00..f9dae421d 100644 --- a/FloconDesktop/gradle/libs.versions.toml +++ b/FloconDesktop/gradle/libs.versions.toml @@ -36,6 +36,11 @@ uiToolingPreviewDesktop = "1.8.2" buildconfig = "5.6.8" paging = "3.3.2" +# TODO Sort +nav3Core = "1.0.0-alpha08" +lifecycleViewmodelNav3 = "2.10.0-alpha03" +kotlinxSerializationCore = "1.8.1" + [libraries] kermit = { module = "co.touchlab:kermit", version.ref = "kermit" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } @@ -91,8 +96,13 @@ androidx-core = { group = "androidx.test", name = "core", version.ref = "core" } other-jsontree = { module = "com.sebastianneubauer.jsontree:jsontree", version.ref = "other-jsontree"} ui-tooling-preview-desktop = { module = "org.jetbrains.compose.ui:ui-tooling-preview-desktop", version.ref = "uiToolingPreviewDesktop" } -androidx-paging-common = { module = "androidx.paging:paging-common", version.ref = "paging" } -androidx-paging-compose = { module = "androidx.paging:paging-compose", version = "3.4.0-alpha04" } +# TODO Sort +androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" } +androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "nav3Core" } + +# Optional add-on libraries +androidx-lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "lifecycleViewmodelNav3" } +kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinxSerializationCore" } [plugins] composeHotReload = { id = "org.jetbrains.compose.hot-reload", version.ref = "composeHotReload" } diff --git a/FloconDesktop/library/designsystem/build.gradle.kts b/FloconDesktop/library/designsystem/build.gradle.kts index 98a1843aa..2256afee1 100644 --- a/FloconDesktop/library/designsystem/build.gradle.kts +++ b/FloconDesktop/library/designsystem/build.gradle.kts @@ -31,6 +31,13 @@ kotlin { api(compose.components.resources) api(compose.components.uiToolingPreview) api(libs.other.jsontree) + + api(libs.androidx.navigation3.ui) + api(libs.androidx.navigation3.runtime) + + // Not KMP yet +// api(libs.androidx.lifecycle.viewmodel.navigation3) + api(libs.kotlinx.serialization.core) api("com.composables:core:1.43.1") } } diff --git a/FloconDesktop/navigation/.gitignore b/FloconDesktop/navigation/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/FloconDesktop/navigation/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/FloconDesktop/navigation/build.gradle.kts b/FloconDesktop/navigation/build.gradle.kts new file mode 100644 index 000000000..49bb728e5 --- /dev/null +++ b/FloconDesktop/navigation/build.gradle.kts @@ -0,0 +1,100 @@ +plugins { + alias(libs.plugins.kotlinMultiplatform) + alias(libs.plugins.android.kotlin.multiplatform.library) + alias(libs.plugins.android.lint) +} + +kotlin { + + // Target declarations - add or remove as needed below. These define + // which platforms this KMP module supports. + // See: https://kotlinlang.org/docs/multiplatform-discover-project.html#targets + androidLibrary { + namespace = "io.github.openflocon.navigation" + compileSdk = 36 + minSdk = 24 + + withHostTestBuilder { + } + + withDeviceTestBuilder { + sourceSetTreeName = "test" + }.configure { + instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + } + + // For iOS targets, this is also where you should + // configure native binary output. For more information, see: + // https://kotlinlang.org/docs/multiplatform-build-native-binaries.html#build-xcframeworks + + // A step-by-step guide on how to include this library in an XCode + // project can be found here: + // https://developer.android.com/kotlin/multiplatform/migrate + val xcfName = "navigationKit" + + iosX64 { + binaries.framework { + baseName = xcfName + } + } + + iosArm64 { + binaries.framework { + baseName = xcfName + } + } + + iosSimulatorArm64 { + binaries.framework { + baseName = xcfName + } + } + + // Source set declarations. + // Declaring a target automatically creates a source set with the same name. By default, the + // Kotlin Gradle Plugin creates additional source sets that depend on each other, since it is + // common to share sources between related targets. + // See: https://kotlinlang.org/docs/multiplatform-hierarchy.html + sourceSets { + commonMain { + dependencies { + implementation(libs.kotlin.stdlib) + // Add KMP dependencies here + } + } + + commonTest { + dependencies { + implementation(libs.kotlin.test) + } + } + + androidMain { + dependencies { + // Add Android-specific dependencies here. Note that this source set depends on + // commonMain by default and will correctly pull the Android artifacts of any KMP + // dependencies declared in commonMain. + } + } + + getByName("androidDeviceTest") { + dependencies { + implementation(libs.androidx.runner) + implementation(libs.androidx.core) + implementation(libs.androidx.testExt.junit) + } + } + + iosMain { + dependencies { + // Add iOS-specific dependencies here. This a source set created by Kotlin Gradle + // Plugin (KGP) that each specific iOS target (e.g., iosX64) depends on as + // part of KMP’s default source set hierarchy. Note that this source set depends + // on common by default and will correctly pull the iOS artifacts of any + // KMP dependencies declared in commonMain. + } + } + } + +} diff --git a/FloconDesktop/navigation/src/androidDeviceTest/kotlin/io/github/openflocon/navigation/ExampleInstrumentedTest.kt b/FloconDesktop/navigation/src/androidDeviceTest/kotlin/io/github/openflocon/navigation/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..7e645936f --- /dev/null +++ b/FloconDesktop/navigation/src/androidDeviceTest/kotlin/io/github/openflocon/navigation/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package io.github.openflocon.navigation + +import android.support.test.InstrumentationRegistry +import android.support.test.runner.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("io.github.openflocon.navigation.test", appContext.packageName) + } +} diff --git a/FloconDesktop/navigation/src/androidHostTest/kotlin/io/github/openflocon/navigation/ExampleUnitTest.kt b/FloconDesktop/navigation/src/androidHostTest/kotlin/io/github/openflocon/navigation/ExampleUnitTest.kt new file mode 100644 index 000000000..87dbe2c42 --- /dev/null +++ b/FloconDesktop/navigation/src/androidHostTest/kotlin/io/github/openflocon/navigation/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package io.github.openflocon.navigation + +import kotlin.test.Test +import kotlin.test.assertEquals + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/FloconDesktop/navigation/src/androidMain/AndroidManifest.xml b/FloconDesktop/navigation/src/androidMain/AndroidManifest.xml new file mode 100644 index 000000000..a5918e68a --- /dev/null +++ b/FloconDesktop/navigation/src/androidMain/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/FloconDesktop/navigation/src/androidMain/kotlin/io/github/openflocon/navigation/Platform.android.kt b/FloconDesktop/navigation/src/androidMain/kotlin/io/github/openflocon/navigation/Platform.android.kt new file mode 100644 index 000000000..9a26098e0 --- /dev/null +++ b/FloconDesktop/navigation/src/androidMain/kotlin/io/github/openflocon/navigation/Platform.android.kt @@ -0,0 +1,3 @@ +package io.github.openflocon.navigation + +actual fun platform() = "Android" diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/Platform.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/Platform.kt new file mode 100644 index 000000000..44ece76e8 --- /dev/null +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/Platform.kt @@ -0,0 +1,3 @@ +package io.github.openflocon.navigation + +expect fun platform(): String diff --git a/FloconDesktop/navigation/src/iosMain/kotlin/io/github/openflocon/navigation/Platform.ios.kt b/FloconDesktop/navigation/src/iosMain/kotlin/io/github/openflocon/navigation/Platform.ios.kt new file mode 100644 index 000000000..5ef2cc460 --- /dev/null +++ b/FloconDesktop/navigation/src/iosMain/kotlin/io/github/openflocon/navigation/Platform.ios.kt @@ -0,0 +1,3 @@ +package io.github.openflocon.navigation + +actual fun platform() = "iOS" diff --git a/FloconDesktop/settings.gradle.kts b/FloconDesktop/settings.gradle.kts index 2601754eb..177470f6f 100644 --- a/FloconDesktop/settings.gradle.kts +++ b/FloconDesktop/settings.gradle.kts @@ -38,3 +38,4 @@ include(":data:remote") include(":domain") include(":data:core") include(":data:local") +include(":navigation") From b90386494fff837dd434d1b9c9cdae81b6f66056 Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Mon, 1 Sep 2025 14:26:41 +0200 Subject: [PATCH 02/28] feature: Nav3 --- FloconDesktop/composeApp/build.gradle.kts | 3 + .../io/github/openflocon/flocondesktop/App.kt | 37 ++++--- .../features/network/Navigation.kt | 16 +++ FloconDesktop/gradle/libs.versions.toml | 4 + FloconDesktop/navigation/build.gradle.kts | 104 +++++------------- .../openflocon/navigation/Platform.android.kt | 3 - .../io/github/openflocon/navigation/DI.kt | 8 ++ .../openflocon/navigation/FloconNavigation.kt | 47 ++++++++ .../navigation/FloconNavigationState.kt | 16 +++ .../openflocon/navigation/FloconRoute.kt | 5 + .../openflocon/navigation/LoadingRoute.kt | 6 + .../github/openflocon/navigation/Platform.kt | 3 - .../openflocon/navigation/Platform.ios.kt | 3 - 13 files changed, 151 insertions(+), 104 deletions(-) create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt delete mode 100644 FloconDesktop/navigation/src/androidMain/kotlin/io/github/openflocon/navigation/Platform.android.kt create mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/DI.kt create mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt create mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt create mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconRoute.kt create mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/LoadingRoute.kt delete mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/Platform.kt delete mode 100644 FloconDesktop/navigation/src/iosMain/kotlin/io/github/openflocon/navigation/Platform.ios.kt diff --git a/FloconDesktop/composeApp/build.gradle.kts b/FloconDesktop/composeApp/build.gradle.kts index 24b7d5d71..8f920407e 100644 --- a/FloconDesktop/composeApp/build.gradle.kts +++ b/FloconDesktop/composeApp/build.gradle.kts @@ -77,6 +77,9 @@ kotlin { implementation(projects.domain) implementation(projects.library.designsystem) + + implementation(projects.navigation) + implementation(libs.kermit) } commonTest.dependencies { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt index 07a1f81ee..e14ad7d4f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt @@ -38,11 +38,11 @@ import io.github.openflocon.flocondesktop.app.AppViewModel import io.github.openflocon.flocondesktop.app.di.appModule import io.github.openflocon.flocondesktop.app.version.VersionCheckerView import io.github.openflocon.flocondesktop.common.di.commonModule -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayerView import io.github.openflocon.flocondesktop.core.di.coreModule import io.github.openflocon.flocondesktop.features.featuresModule +import io.github.openflocon.flocondesktop.features.network.NetworkRoute +import io.github.openflocon.flocondesktop.features.network.networkNavigation import io.github.openflocon.flocondesktop.main.di.mainModule -import io.github.openflocon.flocondesktop.main.ui.MainScreen import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconSurface import io.github.openflocon.library.designsystem.components.panel.FloconPanelDisplayer @@ -71,6 +71,7 @@ fun App() { dataCoreModule, dataLocalModule, dataRemoteModule, + navigationModule, // Temporary module { singleOf(::AdbRepositoryImpl) bind AdbRepository::class @@ -87,6 +88,7 @@ fun App() { fontSizeMultiplier = fontSizeMultiplier ) { val appViewModel: AppViewModel = koinViewModel() + val navigationState = koinInject() FloconSurface( modifier = Modifier @@ -110,21 +112,22 @@ fun App() { } } } - } - } -} - -@Composable -private fun Navigation() { - val backStack = remember { mutableStateListOf() } - - NavDisplay( - backStack = backStack, - entryDecorators = listOf( - rememberSceneSetupNavEntryDecorator(), - rememberSavedStateNavEntryDecorator() - ) - ) { + FloconNavigation { + networkNavigation() + } +// Box( +// Modifier +// .safeContentPadding() +// .fillMaxSize() +// .background(FloconTheme.colorPalette.background), +// ) { +// MainScreen( +// modifier = Modifier +// .fillMaxSize(), +// ) +// FeedbackDisplayerView() +// } + } } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt new file mode 100644 index 000000000..e593c35f7 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt @@ -0,0 +1,16 @@ +package io.github.openflocon.flocondesktop.features.network + +import androidx.navigation3.runtime.EntryProviderBuilder +import androidx.navigation3.runtime.entry +import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen +import io.github.openflocon.navigation.FloconRoute +import kotlinx.serialization.Serializable + +@Serializable +data object NetworkRoute : FloconRoute + +fun EntryProviderBuilder.networkNavigation() { + entry { + NetworkScreen() + } +} diff --git a/FloconDesktop/gradle/libs.versions.toml b/FloconDesktop/gradle/libs.versions.toml index f9dae421d..e0472e048 100644 --- a/FloconDesktop/gradle/libs.versions.toml +++ b/FloconDesktop/gradle/libs.versions.toml @@ -38,6 +38,7 @@ paging = "3.3.2" # TODO Sort nav3Core = "1.0.0-alpha08" +navEvent = "1.0.0-alpha07" lifecycleViewmodelNav3 = "2.10.0-alpha03" kotlinxSerializationCore = "1.8.1" @@ -100,6 +101,9 @@ ui-tooling-preview-desktop = { module = "org.jetbrains.compose.ui:ui-tooling-pre androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" } androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "nav3Core" } +androidx-navigationevent-core = { group = "androidx.navigationevent", name = "navigationevent", version.ref = "navEvent" } +androidx-navigationevent-compose = { group = "androidx.navigationevent", name = "navigationevent-compose", version.ref = "navEvent" } + # Optional add-on libraries androidx-lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "lifecycleViewmodelNav3" } kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinxSerializationCore" } diff --git a/FloconDesktop/navigation/build.gradle.kts b/FloconDesktop/navigation/build.gradle.kts index 49bb728e5..eb6c077ac 100644 --- a/FloconDesktop/navigation/build.gradle.kts +++ b/FloconDesktop/navigation/build.gradle.kts @@ -1,55 +1,32 @@ +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion + plugins { alias(libs.plugins.kotlinMultiplatform) - alias(libs.plugins.android.kotlin.multiplatform.library) - alias(libs.plugins.android.lint) -} - -kotlin { - - // Target declarations - add or remove as needed below. These define - // which platforms this KMP module supports. - // See: https://kotlinlang.org/docs/multiplatform-discover-project.html#targets - androidLibrary { - namespace = "io.github.openflocon.navigation" - compileSdk = 36 - minSdk = 24 - withHostTestBuilder { - } + alias(libs.plugins.composeCompiler) + alias(libs.plugins.composeMultiplatform) - withDeviceTestBuilder { - sourceSetTreeName = "test" - }.configure { - instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - } - } - - // For iOS targets, this is also where you should - // configure native binary output. For more information, see: - // https://kotlinlang.org/docs/multiplatform-build-native-binaries.html#build-xcframeworks - - // A step-by-step guide on how to include this library in an XCode - // project can be found here: - // https://developer.android.com/kotlin/multiplatform/migrate - val xcfName = "navigationKit" + alias(libs.plugins.kotlinx.serialization) +} - iosX64 { - binaries.framework { - baseName = xcfName - } +kotlin { + jvmToolchain(21) + + compilerOptions { + // Pour Kotlin 1.9+ + freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime") + freeCompilerArgs.add("-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi") + freeCompilerArgs.add("-Xcontext-parameters") + freeCompilerArgs.add("-Xcontext-sensitive-resolution") } - iosArm64 { - binaries.framework { - baseName = xcfName - } + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + languageVersion.set(KotlinVersion.KOTLIN_2_2) } - iosSimulatorArm64 { - binaries.framework { - baseName = xcfName - } - } + jvm("desktop") // Source set declarations. // Declaring a target automatically creates a source set with the same name. By default, the @@ -57,43 +34,14 @@ kotlin { // common to share sources between related targets. // See: https://kotlinlang.org/docs/multiplatform-hierarchy.html sourceSets { - commonMain { - dependencies { - implementation(libs.kotlin.stdlib) - // Add KMP dependencies here - } - } + commonMain.dependencies { + implementation(projects.library.designsystem) - commonTest { - dependencies { - implementation(libs.kotlin.test) - } - } - - androidMain { - dependencies { - // Add Android-specific dependencies here. Note that this source set depends on - // commonMain by default and will correctly pull the Android artifacts of any KMP - // dependencies declared in commonMain. - } - } - - getByName("androidDeviceTest") { - dependencies { - implementation(libs.androidx.runner) - implementation(libs.androidx.core) - implementation(libs.androidx.testExt.junit) - } - } + implementation(project.dependencies.platform(libs.koin.bom)) + implementation(libs.koin.core) + implementation(libs.koin.compose.viewmodel) - iosMain { - dependencies { - // Add iOS-specific dependencies here. This a source set created by Kotlin Gradle - // Plugin (KGP) that each specific iOS target (e.g., iosX64) depends on as - // part of KMP’s default source set hierarchy. Note that this source set depends - // on common by default and will correctly pull the iOS artifacts of any - // KMP dependencies declared in commonMain. - } + api(libs.kotlinx.serialization.core) } } diff --git a/FloconDesktop/navigation/src/androidMain/kotlin/io/github/openflocon/navigation/Platform.android.kt b/FloconDesktop/navigation/src/androidMain/kotlin/io/github/openflocon/navigation/Platform.android.kt deleted file mode 100644 index 9a26098e0..000000000 --- a/FloconDesktop/navigation/src/androidMain/kotlin/io/github/openflocon/navigation/Platform.android.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.github.openflocon.navigation - -actual fun platform() = "Android" diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/DI.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/DI.kt new file mode 100644 index 000000000..e232bebc9 --- /dev/null +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/DI.kt @@ -0,0 +1,8 @@ +package io.github.openflocon.navigation + +import org.koin.dsl.module + +val navigationModule = module { + // Add qualifier ? + single { FloconNavigationState() } +} diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt new file mode 100644 index 000000000..9ab2a260e --- /dev/null +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt @@ -0,0 +1,47 @@ +package io.github.openflocon.navigation + +import androidx.compose.foundation.layout.Box +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.navigation3.runtime.EntryProviderBuilder +import androidx.navigation3.runtime.entry +import androidx.navigation3.runtime.entryProvider +import androidx.navigation3.ui.NavDisplay +import androidx.navigationevent.NavigationEventDispatcher +import androidx.navigationevent.NavigationEventDispatcherOwner +import androidx.navigationevent.compose.LocalNavigationEventDispatcherOwner +import androidx.navigationevent.compose.NavigationEventDispatcherOwner +import org.koin.compose.koinInject + +@Composable +fun FloconNavigation( + builder: EntryProviderBuilder.() -> Unit +) { + val navigationState = koinInject() + val dispatcher = remember { NavigationEventDispatcher() } + val parent = remember { + object : NavigationEventDispatcherOwner { + override val navigationEventDispatcher: NavigationEventDispatcher = dispatcher + } + } + + LocalNavigationEventDispatcherOwner.provides(parent) + + NavigationEventDispatcherOwner(parent = parent) { + NavDisplay( + backStack = navigationState.stack, + entryDecorators = listOf( +// rememberSceneSetupNavEntryDecorator(), +// rememberSavedStateNavEntryDecorator() + ), + onBack = { navigationState.back(it) }, + entryProvider = entryProvider { + entry { + Box(Modifier) + } + builder() + } + ) + } +} diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt new file mode 100644 index 000000000..76e00a336 --- /dev/null +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt @@ -0,0 +1,16 @@ +package io.github.openflocon.navigation + +class FloconNavigationState internal constructor() { + + private val _stack = mutableListOf(LoadingRoute) + val stack: List = _stack + + fun navigate(route: FloconRoute) { + _stack.add(route) + } + + fun back(count: Int = 1) { + repeat(count) { _stack.removeLast() } + } + +} diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconRoute.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconRoute.kt new file mode 100644 index 000000000..51b4f4369 --- /dev/null +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconRoute.kt @@ -0,0 +1,5 @@ +package io.github.openflocon.navigation + +import androidx.navigation3.runtime.NavKey + +interface FloconRoute : NavKey diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/LoadingRoute.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/LoadingRoute.kt new file mode 100644 index 000000000..0b14b0cf9 --- /dev/null +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/LoadingRoute.kt @@ -0,0 +1,6 @@ +package io.github.openflocon.navigation + +import kotlinx.serialization.Serializable + +@Serializable +object LoadingRoute : FloconRoute diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/Platform.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/Platform.kt deleted file mode 100644 index 44ece76e8..000000000 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/Platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.github.openflocon.navigation - -expect fun platform(): String diff --git a/FloconDesktop/navigation/src/iosMain/kotlin/io/github/openflocon/navigation/Platform.ios.kt b/FloconDesktop/navigation/src/iosMain/kotlin/io/github/openflocon/navigation/Platform.ios.kt deleted file mode 100644 index 5ef2cc460..000000000 --- a/FloconDesktop/navigation/src/iosMain/kotlin/io/github/openflocon/navigation/Platform.ios.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.github.openflocon.navigation - -actual fun platform() = "iOS" From 48fe233bbcd4cbb7286c3dd10dfab66d3a314a5a Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Thu, 11 Sep 2025 09:57:34 +0200 Subject: [PATCH 03/28] feature: Upgrade lib --- FloconDesktop/gradle/libs.versions.toml | 4 ++-- .../io/github/openflocon/navigation/FloconNavigation.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/FloconDesktop/gradle/libs.versions.toml b/FloconDesktop/gradle/libs.versions.toml index e0472e048..d4bb5a7be 100644 --- a/FloconDesktop/gradle/libs.versions.toml +++ b/FloconDesktop/gradle/libs.versions.toml @@ -37,8 +37,8 @@ buildconfig = "5.6.8" paging = "3.3.2" # TODO Sort -nav3Core = "1.0.0-alpha08" -navEvent = "1.0.0-alpha07" +nav3Core = "1.0.0-alpha09" +navEvent = "1.0.0-alpha08" lifecycleViewmodelNav3 = "2.10.0-alpha03" kotlinxSerializationCore = "1.8.1" diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt index 9ab2a260e..029812013 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt @@ -25,7 +25,7 @@ fun FloconNavigation( override val navigationEventDispatcher: NavigationEventDispatcher = dispatcher } } - + LocalNavigationEventDispatcherOwner.provides(parent) NavigationEventDispatcherOwner(parent = parent) { From cf21ef4000fb809f53947b8fc27d60976c07474f Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Mon, 29 Sep 2025 09:15:30 +0200 Subject: [PATCH 04/28] bump: Nav3 --- .../openflocon/flocondesktop/features/network/Navigation.kt | 1 - FloconDesktop/gradle/libs.versions.toml | 6 +++--- .../io/github/openflocon/navigation/FloconNavigation.kt | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt index e593c35f7..13fdd74e5 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt @@ -1,7 +1,6 @@ package io.github.openflocon.flocondesktop.features.network import androidx.navigation3.runtime.EntryProviderBuilder -import androidx.navigation3.runtime.entry import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen import io.github.openflocon.navigation.FloconRoute import kotlinx.serialization.Serializable diff --git a/FloconDesktop/gradle/libs.versions.toml b/FloconDesktop/gradle/libs.versions.toml index d4bb5a7be..92adbf2a4 100644 --- a/FloconDesktop/gradle/libs.versions.toml +++ b/FloconDesktop/gradle/libs.versions.toml @@ -37,9 +37,9 @@ buildconfig = "5.6.8" paging = "3.3.2" # TODO Sort -nav3Core = "1.0.0-alpha09" -navEvent = "1.0.0-alpha08" -lifecycleViewmodelNav3 = "2.10.0-alpha03" +nav3Core = "1.0.0-alpha10" +navEvent = "1.0.0-alpha09" +lifecycleViewmodelNav3 = "2.10.0-alpha04" kotlinxSerializationCore = "1.8.1" [libraries] diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt index 029812013..1b001cde5 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt @@ -5,7 +5,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.navigation3.runtime.EntryProviderBuilder -import androidx.navigation3.runtime.entry import androidx.navigation3.runtime.entryProvider import androidx.navigation3.ui.NavDisplay import androidx.navigationevent.NavigationEventDispatcher From 80a4d6d52e9cdf858c017c8877ab77b77af09ead Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 1 Oct 2025 13:17:21 +0200 Subject: [PATCH 05/28] feat: Make it work --- .../io/github/openflocon/flocondesktop/App.kt | 11 ++++++++-- FloconDesktop/gradle/libs.versions.toml | 6 +++--- .../library/designsystem/build.gradle.kts | 4 ++-- .../openflocon/navigation/FloconNavigation.kt | 21 +++++++++++++------ .../navigation/FloconNavigationState.kt | 4 +++- FloconDesktop/settings.gradle.kts | 2 ++ 6 files changed, 34 insertions(+), 14 deletions(-) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt index e14ad7d4f..61ce5a91f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt @@ -113,8 +113,15 @@ fun App() { } } - FloconNavigation { - networkNavigation() + FloconSurface( + modifier = Modifier.fillMaxSize() + ) { + FloconNavigation( + navigationState = navigationState, + modifier = Modifier.fillMaxSize() + ) { + networkNavigation() + } } // Box( // Modifier diff --git a/FloconDesktop/gradle/libs.versions.toml b/FloconDesktop/gradle/libs.versions.toml index 92adbf2a4..cd5d85163 100644 --- a/FloconDesktop/gradle/libs.versions.toml +++ b/FloconDesktop/gradle/libs.versions.toml @@ -37,7 +37,7 @@ buildconfig = "5.6.8" paging = "3.3.2" # TODO Sort -nav3Core = "1.0.0-alpha10" +nav3Core = "1.0.0+dev3004" navEvent = "1.0.0-alpha09" lifecycleViewmodelNav3 = "2.10.0-alpha04" kotlinxSerializationCore = "1.8.1" @@ -98,8 +98,8 @@ other-jsontree = { module = "com.sebastianneubauer.jsontree:jsontree", version.r ui-tooling-preview-desktop = { module = "org.jetbrains.compose.ui:ui-tooling-preview-desktop", version.ref = "uiToolingPreviewDesktop" } # TODO Sort -androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" } -androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "nav3Core" } +#compose-navigation3-runtime = { module = "org.jetbrains.androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" } +compose-navigation3-ui = { module = "org.jetbrains.androidx.navigation3:navigation3-ui", version.ref = "nav3Core" } androidx-navigationevent-core = { group = "androidx.navigationevent", name = "navigationevent", version.ref = "navEvent" } androidx-navigationevent-compose = { group = "androidx.navigationevent", name = "navigationevent-compose", version.ref = "navEvent" } diff --git a/FloconDesktop/library/designsystem/build.gradle.kts b/FloconDesktop/library/designsystem/build.gradle.kts index 2256afee1..7b13aa189 100644 --- a/FloconDesktop/library/designsystem/build.gradle.kts +++ b/FloconDesktop/library/designsystem/build.gradle.kts @@ -32,8 +32,8 @@ kotlin { api(compose.components.uiToolingPreview) api(libs.other.jsontree) - api(libs.androidx.navigation3.ui) - api(libs.androidx.navigation3.runtime) + api(libs.compose.navigation3.ui) +// api(libs.compose.navigation3.runtime) // Not KMP yet // api(libs.androidx.lifecycle.viewmodel.navigation3) diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt index 1b001cde5..4aba35081 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt @@ -1,38 +1,46 @@ package io.github.openflocon.navigation +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.navigation3.runtime.EntryProviderBuilder import androidx.navigation3.runtime.entryProvider +import androidx.navigation3.runtime.rememberSavedStateNavEntryDecorator +import androidx.navigation3.scene.rememberSceneSetupNavEntryDecorator import androidx.navigation3.ui.NavDisplay import androidx.navigationevent.NavigationEventDispatcher import androidx.navigationevent.NavigationEventDispatcherOwner import androidx.navigationevent.compose.LocalNavigationEventDispatcherOwner import androidx.navigationevent.compose.NavigationEventDispatcherOwner -import org.koin.compose.koinInject @Composable fun FloconNavigation( + navigationState: FloconNavigationState, + modifier: Modifier = Modifier, builder: EntryProviderBuilder.() -> Unit ) { - val navigationState = koinInject() val dispatcher = remember { NavigationEventDispatcher() } val parent = remember { object : NavigationEventDispatcherOwner { override val navigationEventDispatcher: NavigationEventDispatcher = dispatcher } } - + LocalNavigationEventDispatcherOwner.provides(parent) NavigationEventDispatcherOwner(parent = parent) { NavDisplay( backStack = navigationState.stack, + transitionSpec = { fadeIn() togetherWith fadeOut() }, + popTransitionSpec = { fadeIn() togetherWith fadeOut() }, + predictivePopTransitionSpec = { fadeIn() togetherWith fadeOut() }, entryDecorators = listOf( -// rememberSceneSetupNavEntryDecorator(), -// rememberSavedStateNavEntryDecorator() + rememberSceneSetupNavEntryDecorator(), + rememberSavedStateNavEntryDecorator() ), onBack = { navigationState.back(it) }, entryProvider = entryProvider { @@ -40,7 +48,8 @@ fun FloconNavigation( Box(Modifier) } builder() - } + }, + modifier = modifier ) } } diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt index 76e00a336..b6945ae47 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt @@ -1,8 +1,10 @@ package io.github.openflocon.navigation +import androidx.compose.runtime.mutableStateListOf + class FloconNavigationState internal constructor() { - private val _stack = mutableListOf(LoadingRoute) + private val _stack = mutableStateListOf(LoadingRoute) val stack: List = _stack fun navigate(route: FloconRoute) { diff --git a/FloconDesktop/settings.gradle.kts b/FloconDesktop/settings.gradle.kts index 177470f6f..6d20c3563 100644 --- a/FloconDesktop/settings.gradle.kts +++ b/FloconDesktop/settings.gradle.kts @@ -11,6 +11,7 @@ pluginManagement { } } mavenCentral() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") gradlePluginPortal() } } @@ -24,6 +25,7 @@ dependencyResolutionManagement { includeGroupAndSubgroups("com.google") } } + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") mavenCentral() } } From 6911a89cbf3455192b4c19f007ec1cd3112a3815 Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 1 Oct 2025 13:35:13 +0200 Subject: [PATCH 06/28] feat: Add draft of menu --- .../features/network/Navigation.kt | 8 ++- .../openflocon/navigation/FloconNavigation.kt | 5 ++ .../openflocon/navigation/scene/MenuScene.kt | 66 +++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt index 13fdd74e5..4ef6d0cf8 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt @@ -3,13 +3,19 @@ package io.github.openflocon.flocondesktop.features.network import androidx.navigation3.runtime.EntryProviderBuilder import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen import io.github.openflocon.navigation.FloconRoute +import io.github.openflocon.navigation.scene.Menu +import io.github.openflocon.navigation.scene.MenuScene import kotlinx.serialization.Serializable @Serializable data object NetworkRoute : FloconRoute fun EntryProviderBuilder.networkNavigation() { - entry { + entry( + metadata = mapOf( + MenuScene.MENU_KEY to Menu.HOME // TODO Change + ) + ) { NetworkScreen() } } diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt index 4aba35081..e307271ae 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt @@ -8,14 +8,17 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.navigation3.runtime.EntryProviderBuilder +import androidx.navigation3.runtime.NavEntry import androidx.navigation3.runtime.entryProvider import androidx.navigation3.runtime.rememberSavedStateNavEntryDecorator +import androidx.navigation3.scene.SinglePaneSceneStrategy import androidx.navigation3.scene.rememberSceneSetupNavEntryDecorator import androidx.navigation3.ui.NavDisplay import androidx.navigationevent.NavigationEventDispatcher import androidx.navigationevent.NavigationEventDispatcherOwner import androidx.navigationevent.compose.LocalNavigationEventDispatcherOwner import androidx.navigationevent.compose.NavigationEventDispatcherOwner +import io.github.openflocon.navigation.scene.MenuSceneStrategy @Composable fun FloconNavigation( @@ -42,6 +45,8 @@ fun FloconNavigation( rememberSceneSetupNavEntryDecorator(), rememberSavedStateNavEntryDecorator() ), + sceneStrategy = MenuSceneStrategy() + .then(SinglePaneSceneStrategy()), onBack = { navigationState.back(it) }, entryProvider = entryProvider { entry { diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt new file mode 100644 index 000000000..6b4277f8e --- /dev/null +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt @@ -0,0 +1,66 @@ +package io.github.openflocon.navigation.scene + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.navigation3.runtime.NavEntry +import androidx.navigation3.scene.Scene +import androidx.navigation3.scene.SceneStrategy +import io.github.openflocon.navigation.FloconRoute + +enum class Menu { + HOME, + SETTINGS, + ABOUT, +} + +class MenuScene( + override val key: String, + override val previousEntries: List>, + private val entry: NavEntry +) : Scene { + override val entries: List> = listOf(entry) + override val content: @Composable (() -> Unit) = { + Row { + Box( + modifier = Modifier + .width(300.dp) + .fillMaxHeight() + .background(Color.Blue) + ) + entry.Content() + } + } + + companion object { + const val MENU_KEY = "menu" + } +} + +class MenuSceneStrategy : SceneStrategy { + + @Composable + override fun calculateScene( + entries: List>, + onBack: (Int) -> Unit + ): Scene? { + val lastEntry = entries.last() + + return if (lastEntry.metadata.containsKey(MenuScene.MENU_KEY)) { + MenuScene( + key = MenuScene.MENU_KEY, + previousEntries = entries.dropLast(1), + entry = lastEntry + ) + } else { + null + } + } + +} From f9fd70f9c55c9587e2fe67527ab7581b2905f9aa Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 1 Oct 2025 13:48:51 +0200 Subject: [PATCH 07/28] feat: Move menu --- .../io/github/openflocon/flocondesktop/App.kt | 66 ++++++++++++++++--- .../flocondesktop/app/AppViewModel.kt | 21 ++++++ .../openflocon/navigation/FloconNavigation.kt | 7 +- .../openflocon/navigation/scene/MenuScene.kt | 33 +++++----- 4 files changed, 97 insertions(+), 30 deletions(-) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt index 61ce5a91f..506746e97 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt @@ -8,15 +8,13 @@ import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeContentPadding -import androidx.compose.material3.Button -import androidx.compose.material3.OutlinedButton +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.ChevronRight import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.getValue @@ -43,7 +41,11 @@ import io.github.openflocon.flocondesktop.features.featuresModule import io.github.openflocon.flocondesktop.features.network.NetworkRoute import io.github.openflocon.flocondesktop.features.network.networkNavigation import io.github.openflocon.flocondesktop.main.di.mainModule +import io.github.openflocon.flocondesktop.main.ui.view.leftpannel.LeftPanelView +import io.github.openflocon.flocondesktop.main.ui.view.leftpannel.PanelMaxWidth +import io.github.openflocon.flocondesktop.main.ui.view.leftpannel.PanelMinWidth import io.github.openflocon.library.designsystem.FloconTheme +import io.github.openflocon.library.designsystem.components.FloconIcon import io.github.openflocon.library.designsystem.components.FloconSurface import io.github.openflocon.library.designsystem.components.panel.FloconPanelDisplayer import io.github.openflocon.library.designsystem.components.panel.LocalFloconPanelController @@ -89,6 +91,14 @@ fun App() { ) { val appViewModel: AppViewModel = koinViewModel() val navigationState = koinInject() + val leftPanelState by appViewModel.leftPanelState.collectAsStateWithLifecycle() + var expanded by remember { mutableStateOf(true) } + val width by animateDpAsState(targetValue = if (expanded) PanelMaxWidth else PanelMinWidth) + var windowSize by remember { mutableStateOf(IntSize.Zero) } + val position by animateDpAsState( + targetValue = if (expanded) PanelMaxWidth else PanelMinWidth, + ) + val rotate by animateFloatAsState(targetValue = if (expanded) 180f else 0f) FloconSurface( modifier = Modifier @@ -114,10 +124,48 @@ fun App() { } FloconSurface( - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() + .onGloballyPositioned { + windowSize = it.size // TODO Add windowsize lib + }, ) { FloconNavigation( navigationState = navigationState, + sceneStrategy = MenuSceneStrategy( + menuContent = { + LeftPanelView( + state = leftPanelState, + onClickItem = {}, + modifier = Modifier + .width(width) + .fillMaxHeight(), + expanded = expanded + ) + }, + expander = { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .width(20.dp) + .height(60.dp) + .graphicsLayer { + translationX = position.toPx() - size.width / 2 - 8.dp.toPx() + translationY = (windowSize.height / 2) - (size.height / 2) + } + .clip(RoundedCornerShape(4.dp)) + .background(FloconTheme.colorPalette.primary) + .clickable(onClick = { expanded = !expanded }), + ) { + FloconIcon( + imageVector = Icons.Outlined.ChevronRight, + tint = Color.LightGray, + modifier = Modifier.rotate(rotate), + ) + } + } + ) + .then(SinglePaneSceneStrategy()), modifier = Modifier.fillMaxSize() ) { networkNavigation() diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt index 09afabb14..4bbd2e1dc 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt @@ -5,8 +5,16 @@ import androidx.lifecycle.viewModelScope import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.settings.usecase.InitAdbPathUseCase import io.github.openflocon.domain.settings.usecase.StartAdbForwardUseCase +import io.github.openflocon.flocondesktop.main.ui.buildLeftPanelState +import io.github.openflocon.flocondesktop.main.ui.model.SubScreen +import io.github.openflocon.flocondesktop.main.ui.model.id import io.github.openflocon.flocondesktop.messages.ui.MessagesServerDelegate import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.isActive import kotlinx.coroutines.launch @@ -20,6 +28,19 @@ class AppViewModel( messagesServerDelegate, ) { + val subScreen = MutableStateFlow(SubScreen.Network) + val leftPanelState = subScreen.map { subScreen -> + buildLeftPanelState( + selectedId = subScreen.id, + ) + } + .flowOn(dispatcherProvider.ui) + .stateIn( + scope = viewModelScope, + started = SharingStarted.Eagerly, + initialValue = buildLeftPanelState(subScreen.value.id), + ) + init { viewModelScope.launch(dispatcherProvider.viewModel) { initAdbPathUseCase().alsoFailure { diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt index e307271ae..64e6cc3a8 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt @@ -8,9 +8,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.navigation3.runtime.EntryProviderBuilder -import androidx.navigation3.runtime.NavEntry import androidx.navigation3.runtime.entryProvider import androidx.navigation3.runtime.rememberSavedStateNavEntryDecorator +import androidx.navigation3.scene.SceneStrategy import androidx.navigation3.scene.SinglePaneSceneStrategy import androidx.navigation3.scene.rememberSceneSetupNavEntryDecorator import androidx.navigation3.ui.NavDisplay @@ -18,12 +18,12 @@ import androidx.navigationevent.NavigationEventDispatcher import androidx.navigationevent.NavigationEventDispatcherOwner import androidx.navigationevent.compose.LocalNavigationEventDispatcherOwner import androidx.navigationevent.compose.NavigationEventDispatcherOwner -import io.github.openflocon.navigation.scene.MenuSceneStrategy @Composable fun FloconNavigation( navigationState: FloconNavigationState, modifier: Modifier = Modifier, + sceneStrategy: SceneStrategy = SinglePaneSceneStrategy(), builder: EntryProviderBuilder.() -> Unit ) { val dispatcher = remember { NavigationEventDispatcher() } @@ -45,8 +45,7 @@ fun FloconNavigation( rememberSceneSetupNavEntryDecorator(), rememberSavedStateNavEntryDecorator() ), - sceneStrategy = MenuSceneStrategy() - .then(SinglePaneSceneStrategy()), + sceneStrategy = sceneStrategy, onBack = { navigationState.back(it) }, entryProvider = entryProvider { entry { diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt index 6b4277f8e..e7a17acbd 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt @@ -1,14 +1,8 @@ package io.github.openflocon.navigation.scene -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp import androidx.navigation3.runtime.NavEntry import androidx.navigation3.scene.Scene import androidx.navigation3.scene.SceneStrategy @@ -23,18 +17,18 @@ enum class Menu { class MenuScene( override val key: String, override val previousEntries: List>, - private val entry: NavEntry + private val entry: NavEntry, + private val menuContent: @Composable () -> Unit, + private val expander: @Composable (() -> Unit)? = null ) : Scene { override val entries: List> = listOf(entry) override val content: @Composable (() -> Unit) = { - Row { - Box( - modifier = Modifier - .width(300.dp) - .fillMaxHeight() - .background(Color.Blue) - ) - entry.Content() + Box { + Row { + menuContent() + entry.Content() + } + expander?.invoke() } } @@ -43,7 +37,10 @@ class MenuScene( } } -class MenuSceneStrategy : SceneStrategy { +class MenuSceneStrategy( + private val menuContent: @Composable () -> Unit, + private val expander: @Composable (() -> Unit)? = null +) : SceneStrategy { @Composable override fun calculateScene( @@ -56,7 +53,9 @@ class MenuSceneStrategy : SceneStrategy { MenuScene( key = MenuScene.MENU_KEY, previousEntries = entries.dropLast(1), - entry = lastEntry + entry = lastEntry, + menuContent = menuContent, + expander = expander ) } else { null From 586f19762d7e169a7cbaf1617a887735cac52b98 Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Mon, 13 Oct 2025 13:55:35 +0200 Subject: [PATCH 08/28] feat: Clean menu --- FloconAndroid/.idea/appInsightsSettings.xml | 26 +++ .../io/github/openflocon/flocondesktop/App.kt | 204 ++++++++++-------- .../openflocon/flocondesktop/app/AppAction.kt | 9 + .../flocondesktop/app/AppViewModel.kt | 65 +++--- .../flocondesktop/app/models/AppUiState.kt | 15 ++ .../flocondesktop/app/models/SubScreen.kt | 20 ++ .../common/utils/ViewModelExt.kt | 17 ++ .../features/analytics/Navigation.kt | 18 ++ .../features/network/Navigation.kt | 5 +- .../flocondesktop/main/ui/MainViewModel.kt | 53 ++--- .../main/ui/model/leftpanel/LeftPanelItem.kt | 5 +- .../{LeftPanelState.kt => MenuUiState.kt} | 23 +- .../main/ui/view/leftpannel/LeftPannelView.kt | 13 +- FloconDesktop/gradle/libs.versions.toml | 6 +- .../components/panel/FloconPanel.kt | 94 ++++---- .../openflocon/navigation/FloconNavigation.kt | 1 + .../openflocon/navigation/scene/MenuScene.kt | 8 +- 17 files changed, 357 insertions(+), 225 deletions(-) create mode 100644 FloconAndroid/.idea/appInsightsSettings.xml create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/AppUiState.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/SubScreen.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/utils/ViewModelExt.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/{LeftPanelState.kt => MenuUiState.kt} (81%) diff --git a/FloconAndroid/.idea/appInsightsSettings.xml b/FloconAndroid/.idea/appInsightsSettings.xml new file mode 100644 index 000000000..371f2e299 --- /dev/null +++ b/FloconAndroid/.idea/appInsightsSettings.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt index 506746e97..ddb14e1f9 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt @@ -2,11 +2,12 @@ package io.github.openflocon.flocondesktop -import androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.ComposeFoundationFlags import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize @@ -16,15 +17,22 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.ChevronRight import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.composeunstyled.Text +import androidx.navigation3.scene.SinglePaneSceneStrategy import com.flocon.data.remote.dataRemoteModule import io.github.openflocon.data.core.dataCoreModule import io.github.openflocon.data.local.dataLocalModule @@ -32,11 +40,13 @@ import io.github.openflocon.domain.adb.repository.AdbRepository import io.github.openflocon.domain.domainModule import io.github.openflocon.domain.settings.usecase.ObserveFontSizeMultiplierUseCase import io.github.openflocon.flocondesktop.adb.AdbRepositoryImpl +import io.github.openflocon.flocondesktop.app.AppAction import io.github.openflocon.flocondesktop.app.AppViewModel import io.github.openflocon.flocondesktop.app.di.appModule -import io.github.openflocon.flocondesktop.app.version.VersionCheckerView +import io.github.openflocon.flocondesktop.app.models.AppUiState import io.github.openflocon.flocondesktop.common.di.commonModule import io.github.openflocon.flocondesktop.core.di.coreModule +import io.github.openflocon.flocondesktop.features.analytics.analyticsNavigation import io.github.openflocon.flocondesktop.features.featuresModule import io.github.openflocon.flocondesktop.features.network.NetworkRoute import io.github.openflocon.flocondesktop.features.network.networkNavigation @@ -47,9 +57,10 @@ import io.github.openflocon.flocondesktop.main.ui.view.leftpannel.PanelMinWidth import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconIcon import io.github.openflocon.library.designsystem.components.FloconSurface -import io.github.openflocon.library.designsystem.components.panel.FloconPanelDisplayer -import io.github.openflocon.library.designsystem.components.panel.LocalFloconPanelController -import io.github.openflocon.library.designsystem.components.panel.rememberFloconPanelController +import io.github.openflocon.navigation.FloconNavigation +import io.github.openflocon.navigation.FloconNavigationState +import io.github.openflocon.navigation.navigationModule +import io.github.openflocon.navigation.scene.MenuSceneStrategy import org.koin.compose.KoinApplication import org.koin.compose.koinInject import org.koin.compose.viewmodel.koinViewModel @@ -84,93 +95,44 @@ fun App() { val fontSizeMultiplier by koinInject()() .collectAsStateWithLifecycle() - val panelController = rememberFloconPanelController() +// val panelController = rememberFloconPanelController() FloconTheme( fontSizeMultiplier = fontSizeMultiplier ) { - val appViewModel: AppViewModel = koinViewModel() - val navigationState = koinInject() - val leftPanelState by appViewModel.leftPanelState.collectAsStateWithLifecycle() - var expanded by remember { mutableStateOf(true) } - val width by animateDpAsState(targetValue = if (expanded) PanelMaxWidth else PanelMinWidth) - var windowSize by remember { mutableStateOf(IntSize.Zero) } - val position by animateDpAsState( - targetValue = if (expanded) PanelMaxWidth else PanelMinWidth, + val viewModel: AppViewModel = koinViewModel() + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + Content( + uiState = uiState, + navigationState = viewModel.navigationState, + onAction = viewModel::onAction ) - val rotate by animateFloatAsState(targetValue = if (expanded) 180f else 0f) - FloconSurface( - modifier = Modifier - .safeContentPadding() - .fillMaxSize() - ) { - CompositionLocalProvider(LocalFloconPanelController provides panelController) { - Box( - modifier = Modifier.fillMaxSize() - ) { - MainScreen( - modifier = Modifier - .fillMaxSize(), - ) - FloconPanelDisplayer( - panelController = panelController, - modifier = Modifier.fillMaxSize() - ) - FeedbackDisplayerView() - VersionCheckerView() - } - } - } - FloconSurface( - modifier = Modifier - .fillMaxSize() - .onGloballyPositioned { - windowSize = it.size // TODO Add windowsize lib - }, - ) { - FloconNavigation( - navigationState = navigationState, - sceneStrategy = MenuSceneStrategy( - menuContent = { - LeftPanelView( - state = leftPanelState, - onClickItem = {}, - modifier = Modifier - .width(width) - .fillMaxHeight(), - expanded = expanded - ) - }, - expander = { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .width(20.dp) - .height(60.dp) - .graphicsLayer { - translationX = position.toPx() - size.width / 2 - 8.dp.toPx() - translationY = (windowSize.height / 2) - (size.height / 2) - } - .clip(RoundedCornerShape(4.dp)) - .background(FloconTheme.colorPalette.primary) - .clickable(onClick = { expanded = !expanded }), - ) { - FloconIcon( - imageVector = Icons.Outlined.ChevronRight, - tint = Color.LightGray, - modifier = Modifier.rotate(rotate), - ) - } - } - ) - .then(SinglePaneSceneStrategy()), - modifier = Modifier.fillMaxSize() - ) { - networkNavigation() - } - } +// FloconSurface( +// modifier = Modifier +// .safeContentPadding() +// .fillMaxSize() +// ) { +// CompositionLocalProvider(LocalFloconPanelController provides panelController) { +// Box( +// modifier = Modifier.fillMaxSize() +// ) { +// MainScreen( +// modifier = Modifier +// .fillMaxSize(), +// ) +// FloconPanelDisplayer( +// panelController = panelController, +// modifier = Modifier.fillMaxSize() +// ) +// FeedbackDisplayerView() +// } +// } +// } + + // Box( // Modifier // .safeContentPadding() @@ -186,3 +148,67 @@ fun App() { } } } + +@Composable +private fun Content( + navigationState: FloconNavigationState, + uiState: AppUiState, + onAction: (AppAction) -> Unit +) { + var expanded by remember { mutableStateOf(true) } + val width by animateDpAsState(targetValue = if (expanded) PanelMaxWidth else PanelMinWidth) + var windowSize by remember { mutableStateOf(IntSize.Zero) } + val position by animateDpAsState( + targetValue = if (expanded) PanelMaxWidth else PanelMinWidth, + ) + val rotate by animateFloatAsState(targetValue = if (expanded) 180f else 0f) + + FloconSurface( + modifier = Modifier + .fillMaxSize() + .onGloballyPositioned { + windowSize = it.size // TODO Add windowsize lib + }, + ) { + FloconNavigation( + navigationState = navigationState, + sceneStrategy = MenuSceneStrategy( + menuContent = { + LeftPanelView( + state = uiState.menuState, + onClickItem = { onAction(AppAction.SelectMenu(it.screen)) }, + modifier = Modifier + .width(width) + .fillMaxHeight(), + expanded = expanded + ) + }, + expander = { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.width(20.dp) + .height(60.dp) + .graphicsLayer { + translationX = position.toPx() - size.width / 2 - 8.dp.toPx() + translationY = (windowSize.height / 2) - (size.height / 2) + } + .clip(RoundedCornerShape(4.dp)) + .background(FloconTheme.colorPalette.primary) + .clickable(onClick = { expanded = !expanded }), + ) { + FloconIcon( + imageVector = Icons.Outlined.ChevronRight, + tint = Color.LightGray, + modifier = Modifier.rotate(rotate), + ) + } + } + ) + .then(SinglePaneSceneStrategy()), + modifier = Modifier.fillMaxSize() + ) { + networkNavigation() + analyticsNavigation() + } + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt new file mode 100644 index 000000000..eb21e0561 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt @@ -0,0 +1,9 @@ +package io.github.openflocon.flocondesktop.app + +import io.github.openflocon.flocondesktop.main.ui.model.SubScreen + +internal sealed interface AppAction { + + data class SelectMenu(val screen: SubScreen) : AppAction + +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt index 4bbd2e1dc..69ce836eb 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt @@ -5,57 +5,66 @@ import androidx.lifecycle.viewModelScope import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.settings.usecase.InitAdbPathUseCase import io.github.openflocon.domain.settings.usecase.StartAdbForwardUseCase +import io.github.openflocon.flocondesktop.app.models.AppUiState +import io.github.openflocon.flocondesktop.app.models.route +import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed +import io.github.openflocon.flocondesktop.features.network.NetworkRoute import io.github.openflocon.flocondesktop.main.ui.buildLeftPanelState import io.github.openflocon.flocondesktop.main.ui.model.SubScreen -import io.github.openflocon.flocondesktop.main.ui.model.id import io.github.openflocon.flocondesktop.messages.ui.MessagesServerDelegate +import io.github.openflocon.navigation.FloconNavigationState import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -class AppViewModel( +internal class AppViewModel( messagesServerDelegate: MessagesServerDelegate, initAdbPathUseCase: InitAdbPathUseCase, startAdbForwardUseCase: StartAdbForwardUseCase, + val navigationState: FloconNavigationState, private val initialSetupStateHolder: InitialSetupStateHolder, - private val dispatcherProvider: DispatcherProvider, -) : ViewModel( - messagesServerDelegate, -) { - - val subScreen = MutableStateFlow(SubScreen.Network) - val leftPanelState = subScreen.map { subScreen -> - buildLeftPanelState( - selectedId = subScreen.id, - ) + dispatcherProvider: DispatcherProvider, +) : ViewModel(messagesServerDelegate) { + + private val menuState = MutableStateFlow( + buildLeftPanelState(current = SubScreen.Network) + ) + + val uiState = menuState.map { + AppUiState(menuState = it) } - .flowOn(dispatcherProvider.ui) - .stateIn( - scope = viewModelScope, - started = SharingStarted.Eagerly, - initialValue = buildLeftPanelState(subScreen.value.id), - ) + .stateInWhileSubscribed(AppUiState(menuState = menuState.value)) init { viewModelScope.launch(dispatcherProvider.viewModel) { initAdbPathUseCase().alsoFailure { initialSetupStateHolder.setRequiresInitialSetup() } - } - messagesServerDelegate.initialize() + messagesServerDelegate.initialize() - viewModelScope.launch { - while (isActive) { - // ensure we have the forward enabled - startAdbForwardUseCase() - delay(1_500) + launch { + while (isActive) { + // ensure we have the forward enabled + startAdbForwardUseCase() + delay(1_500) + } } + + navigationState.navigate(NetworkRoute) } } + + fun onAction(action: AppAction) = when (action) { + is AppAction.SelectMenu -> onSelectMenu(action) + } + + private fun onSelectMenu(action: AppAction.SelectMenu) { + menuState.update { it.copy(current = action.screen) } + navigationState.navigate(action.screen.route) + } + } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/AppUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/AppUiState.kt new file mode 100644 index 000000000..9c13b10e7 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/AppUiState.kt @@ -0,0 +1,15 @@ +package io.github.openflocon.flocondesktop.app.models + +import androidx.compose.runtime.Immutable +import io.github.openflocon.flocondesktop.main.ui.model.SubScreen +import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPanelState +import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.previewLeftPannelState + +@Immutable +internal data class AppUiState( + val menuState: LeftPanelState // TODO Rename +) + +private fun previewAppUiState() = AppUiState( + menuState = previewLeftPannelState(SubScreen.Network) +) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/SubScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/SubScreen.kt new file mode 100644 index 000000000..7923077e7 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/SubScreen.kt @@ -0,0 +1,20 @@ +package io.github.openflocon.flocondesktop.app.models + +import io.github.openflocon.flocondesktop.features.analytics.AnalyticsRoute +import io.github.openflocon.flocondesktop.features.network.NetworkRoute +import io.github.openflocon.flocondesktop.main.ui.model.SubScreen +import io.github.openflocon.navigation.FloconRoute + +val SubScreen.route: FloconRoute + get() = when (this) { + SubScreen.Dashboard -> TODO() + SubScreen.Network -> NetworkRoute + SubScreen.Images -> TODO() + SubScreen.Database -> TODO() + SubScreen.Files -> TODO() + SubScreen.SharedPreferences -> TODO() + SubScreen.Analytics -> AnalyticsRoute + SubScreen.Tables -> TODO() + SubScreen.Settings -> TODO() + SubScreen.Deeplinks -> TODO() + } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/utils/ViewModelExt.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/utils/ViewModelExt.kt new file mode 100644 index 000000000..ccdb85034 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/utils/ViewModelExt.kt @@ -0,0 +1,17 @@ +package io.github.openflocon.flocondesktop.common.utils + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.stateIn + +context(viewModel: ViewModel) +fun Flow.stateInWhileSubscribed(default: T): StateFlow { + return stateIn( + scope = viewModel.viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = default + ) +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt new file mode 100644 index 000000000..f28f2eb14 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt @@ -0,0 +1,18 @@ +package io.github.openflocon.flocondesktop.features.analytics + +import androidx.navigation3.runtime.EntryProviderBuilder +import io.github.openflocon.flocondesktop.features.analytics.view.AnalyticsScreen +import io.github.openflocon.navigation.FloconRoute +import io.github.openflocon.navigation.scene.MenuScene +import kotlinx.serialization.Serializable + +@Serializable +data object AnalyticsRoute : FloconRoute + +fun EntryProviderBuilder.analyticsNavigation() { + entry( + metadata = mapOf(MenuScene.MENU_KEY to true) + ) { + AnalyticsScreen() + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt index 4ef6d0cf8..17357e582 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt @@ -3,7 +3,6 @@ package io.github.openflocon.flocondesktop.features.network import androidx.navigation3.runtime.EntryProviderBuilder import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen import io.github.openflocon.navigation.FloconRoute -import io.github.openflocon.navigation.scene.Menu import io.github.openflocon.navigation.scene.MenuScene import kotlinx.serialization.Serializable @@ -12,9 +11,7 @@ data object NetworkRoute : FloconRoute fun EntryProviderBuilder.networkNavigation() { entry( - metadata = mapOf( - MenuScene.MENU_KEY to Menu.HOME // TODO Change - ) + metadata = mapOf(MenuScene.MENU_KEY to true) ) { NetworkScreen() } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainViewModel.kt index 48a48c920..0fa63477e 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainViewModel.kt @@ -18,7 +18,6 @@ import io.github.openflocon.flocondesktop.main.ui.model.DeviceItemUiModel import io.github.openflocon.flocondesktop.main.ui.model.DevicesStateUiModel import io.github.openflocon.flocondesktop.main.ui.model.RecordVideoStateUiModel import io.github.openflocon.flocondesktop.main.ui.model.SubScreen -import io.github.openflocon.flocondesktop.main.ui.model.id import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPanelItem import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPanelState import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPannelSection @@ -38,8 +37,8 @@ class MainViewModel( private val devicesDelegate: DevicesDelegate, private val dispatcherProvider: DispatcherProvider, private val initialSetupStateHolder: InitialSetupStateHolder, - private val takeScreenshotUseCase : TakeScreenshotUseCase, - private val restartAppUseCase : RestartAppUseCase, + private val takeScreenshotUseCase: TakeScreenshotUseCase, + private val restartAppUseCase: RestartAppUseCase, private val recordVideoDelegate: RecordVideoDelegate, private val feedbackDisplayer: FeedbackDisplayer, private val observeCurrentDeviceCapabilitiesUseCase: ObserveCurrentDeviceCapabilitiesUseCase, @@ -66,17 +65,13 @@ class MainViewModel( observeCurrentDeviceCapabilitiesUseCase(), ).map { (subScreen, capabilities) -> buildLeftPanelState( - selectedId = subScreen.id, - currentDeviceCapabilities = capabilities, + current = subScreen, ) }.flowOn(dispatcherProvider.ui) .stateIn( scope = viewModelScope, started = SharingStarted.Eagerly, - initialValue = buildLeftPanelState( - selectedId = subScreen.value.id, - currentDeviceCapabilities = null - ), + initialValue = buildLeftPanelState(subScreen.value), ) val devicesState: StateFlow = devicesDelegate.devicesState @@ -107,7 +102,7 @@ class MainViewModel( } fun onClickLeftPanelItem(leftPanelItem: LeftPanelItem) { - this.subScreen.update { SubScreen.fromId(leftPanelItem.id) } + this.subScreen.update { leftPanelItem.screen } } fun onRecordClicked() { @@ -136,58 +131,50 @@ class MainViewModel( } } -internal fun buildLeftPanelState(selectedId: String?, currentDeviceCapabilities: DeviceCapabilitiesDomainModel?) = LeftPanelState( +internal fun buildLeftPanelState(current: SubScreen) = LeftPanelState( + current = current, bottomItems = listOf( - item( - subScreen = SubScreen.Settings, - selectedId = selectedId, - isEnabled = true, - ), + item(subScreen = SubScreen.Settings) ), sections = listOf( LeftPannelSection( title = "Network", items = listOf( - item(subScreen = SubScreen.Network, selectedId = selectedId, isEnabled = true,), - item(subScreen = SubScreen.Images, selectedId = selectedId, isEnabled = true,), + item(subScreen = SubScreen.Network), + item(subScreen = SubScreen.Images), ), ), LeftPannelSection( title = "Storage", items = listOf( - item(SubScreen.Database, selectedId = selectedId, isEnabled = true), - item(SubScreen.SharedPreferences, selectedId = selectedId, isEnabled = currentDeviceCapabilities?.sharedPreferences ?: true), - item(SubScreen.Files, selectedId = selectedId, isEnabled = currentDeviceCapabilities?.files ?: true), + item(SubScreen.Database), + item(SubScreen.SharedPreferences), + item(SubScreen.Files), ), ), LeftPannelSection( title = "Data", items = listOf( - item(SubScreen.Dashboard, selectedId = selectedId, isEnabled = true), - item(SubScreen.Analytics, selectedId = selectedId, isEnabled = true), - item(SubScreen.Tables, selectedId = selectedId, isEnabled = true), + item(SubScreen.Dashboard), + item(SubScreen.Analytics), + item(SubScreen.Tables), ), ), LeftPannelSection( title = "Actions", items = listOf( - item(SubScreen.Deeplinks, selectedId = selectedId, isEnabled = currentDeviceCapabilities?.deeplinks ?: true), + item(SubScreen.Deeplinks) ), ), ), ) private fun item( - subScreen: SubScreen, - selectedId: String?, - isEnabled: Boolean, + subScreen: SubScreen ): LeftPanelItem { - val id = subScreen.id return LeftPanelItem( - id = id, + screen = subScreen, icon = subScreen.icon(), - text = subScreen.displayName(), - isSelected = selectedId == id, - isEnabled = isEnabled, + text = subScreen.displayName() ) } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/LeftPanelItem.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/LeftPanelItem.kt index 7a1117a72..2f989ebdb 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/LeftPanelItem.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/LeftPanelItem.kt @@ -1,9 +1,12 @@ package io.github.openflocon.flocondesktop.main.ui.model.leftpanel +import androidx.compose.runtime.Immutable import androidx.compose.ui.graphics.vector.ImageVector +import io.github.openflocon.flocondesktop.main.ui.model.SubScreen +@Immutable data class LeftPanelItem( - val id: String, + val screen: SubScreen, val icon: ImageVector, val text: String, val isSelected: Boolean, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/LeftPanelState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/MenuUiState.kt similarity index 81% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/LeftPanelState.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/MenuUiState.kt index 07a613e0e..91706972a 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/LeftPanelState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/MenuUiState.kt @@ -2,16 +2,19 @@ package io.github.openflocon.flocondesktop.main.ui.model.leftpanel import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Settings +import io.github.openflocon.flocondesktop.main.ui.model.SubScreen data class LeftPanelState( + val current: SubScreen, val sections: List, val bottomItems: List, ) -fun previewLeftPannelState(selectedId: String?) = LeftPanelState( +fun previewLeftPannelState(current: SubScreen) = LeftPanelState( + current = current, bottomItems = listOf( LeftPanelItem( - id = "Settings", + screen = SubScreen.Settings, icon = Icons.Outlined.Settings, text = "Settings", isSelected = selectedId == "Settings", @@ -23,21 +26,21 @@ fun previewLeftPannelState(selectedId: String?) = LeftPanelState( title = "Network", items = listOf( LeftPanelItem( - id = "Http", + screen = SubScreen.Network, icon = Icons.Outlined.Settings, text = "Http", isSelected = selectedId == "Http", isEnabled = true, ), LeftPanelItem( - id = "Images", + screen = SubScreen.Images, icon = Icons.Outlined.Settings, text = "Images", isSelected = selectedId == "Images", isEnabled = true, ), LeftPanelItem( - id = "Grpc", + screen = SubScreen.Network, icon = Icons.Outlined.Settings, text = "Grpc", isSelected = selectedId == "Grpc", @@ -49,21 +52,21 @@ fun previewLeftPannelState(selectedId: String?) = LeftPanelState( title = "Storage", items = listOf( LeftPanelItem( - id = "Database", + screen = SubScreen.Network, icon = Icons.Outlined.Settings, text = "Database", isSelected = selectedId == "Database", isEnabled = true, ), LeftPanelItem( - id = "SharedPreferences", + screen = SubScreen.SharedPreferences, icon = Icons.Outlined.Settings, text = "SharedPreferences", isSelected = selectedId == "SharedPreferences", isEnabled = true, ), LeftPanelItem( - id = "Files", + screen = SubScreen.Files, icon = Icons.Outlined.Settings, text = "Files", isSelected = selectedId == "Files", @@ -75,14 +78,14 @@ fun previewLeftPannelState(selectedId: String?) = LeftPanelState( title = "Data", items = listOf( LeftPanelItem( - id = "Dashboard", + screen = SubScreen.Dashboard, icon = Icons.Outlined.Settings, text = "Dashboard", isSelected = selectedId == "Dashboard", isEnabled = true, ), LeftPanelItem( - id = "Tables", + screen = SubScreen.Tables, icon = Icons.Outlined.Settings, text = "Tables", isSelected = selectedId == "Tables", diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/LeftPannelView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/LeftPannelView.kt index 0292d53a5..e2ba05bb8 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/LeftPannelView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/LeftPannelView.kt @@ -19,6 +19,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.fastForEachIndexed +import io.github.openflocon.flocondesktop.main.ui.model.SubScreen import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPanelItem import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPanelState import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPannelSection @@ -44,6 +45,7 @@ fun LeftPanelView( .padding(horizontal = 12.dp), ) { MenuSection( + current = state.current, items = state.sections, expanded = expanded, onClickItem = onClickItem, @@ -51,6 +53,7 @@ fun LeftPanelView( Spacer(modifier = Modifier.height(12.dp)) Spacer(Modifier.weight(1f)) MenuItems( + current = state.current, items = state.bottomItems, expanded = expanded, onClickItem = onClickItem, @@ -60,6 +63,7 @@ fun LeftPanelView( @Composable private fun ColumnScope.MenuSection( + current: SubScreen, items: List, expanded: Boolean, onClickItem: (LeftPanelItem) -> Unit, @@ -70,6 +74,7 @@ private fun ColumnScope.MenuSection( text = section.title, ) MenuItems( + current = current, items = section.items, expanded = expanded, onClickItem = onClickItem, @@ -79,6 +84,7 @@ private fun ColumnScope.MenuSection( @Composable private fun ColumnScope.MenuItems( + current: SubScreen, items: List, expanded: Boolean, onClickItem: (LeftPanelItem) -> Unit, @@ -101,15 +107,16 @@ private fun ColumnScope.MenuItems( @Composable @Preview private fun LeftPanelViewPreview() { - val selectedItem = remember { mutableStateOf(null) } + val selectedItem = remember { mutableStateOf(SubScreen.Network) } + FloconTheme { Box(modifier = Modifier.background(Color.White)) LeftPanelView( state = previewLeftPannelState( - selectedId = selectedItem.value, + current = selectedItem.value, ), onClickItem = { - selectedItem.value = it.id + selectedItem.value = it.screen }, modifier = Modifier.wrapContentHeight(), expanded = false, diff --git a/FloconDesktop/gradle/libs.versions.toml b/FloconDesktop/gradle/libs.versions.toml index cd5d85163..7d5c76753 100644 --- a/FloconDesktop/gradle/libs.versions.toml +++ b/FloconDesktop/gradle/libs.versions.toml @@ -101,13 +101,13 @@ ui-tooling-preview-desktop = { module = "org.jetbrains.compose.ui:ui-tooling-pre #compose-navigation3-runtime = { module = "org.jetbrains.androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" } compose-navigation3-ui = { module = "org.jetbrains.androidx.navigation3:navigation3-ui", version.ref = "nav3Core" } -androidx-navigationevent-core = { group = "androidx.navigationevent", name = "navigationevent", version.ref = "navEvent" } -androidx-navigationevent-compose = { group = "androidx.navigationevent", name = "navigationevent-compose", version.ref = "navEvent" } - # Optional add-on libraries androidx-lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "lifecycleViewmodelNav3" } kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinxSerializationCore" } +androidx-paging-common = { module = "androidx.paging:paging-common", version.ref = "paging" } +androidx-paging-compose = { module = "androidx.paging:paging-compose", version = "3.4.0-alpha04" } + [plugins] composeHotReload = { id = "org.jetbrains.compose.hot-reload", version.ref = "composeHotReload" } composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "composeMultiplatform" } diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt index 45321550e..09785f8d6 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt @@ -57,54 +57,54 @@ fun FloconPanel( } } - val floconPanelController = LocalFloconPanelController.current +// val floconPanelController = LocalFloconPanelController.current - if (innerExpanded) { - DisposableEffect(Unit) { - floconPanelController.display { - if (onClose != null) { - EscapeHandler { - onClose() - true - } - } - - Row( - modifier = Modifier - .fillMaxHeight() - ) { - if (onClose != null) { - Box( - modifier = Modifier.padding(8.dp) - ) { - FloconIconTonalButton( - onClick = onClose, - modifier = Modifier - .graphicsLayer { - this.alpha = 1f - translationX.value.div(PanelWidth) - } - ) { - FloconIcon( - Icons.Outlined.Close - ) - } - } - } - Box( - modifier = Modifier - .width(PanelWidth) - .fillMaxHeight() - .graphicsLayer { - this.translationX = translationX.value.toPx() - } - .border(width = 1.dp, color = FloconTheme.colorPalette.surface), - content = content - ) - } - } - onDispose { floconPanelController.hide() } - } - } +// if (innerExpanded) { +// DisposableEffect(Unit) { +// floconPanelController.display { +// if (onClose != null) { +// EscapeHandler { +// onClose() +// true +// } +// } +// +// Row( +// modifier = Modifier +// .fillMaxHeight() +// ) { +// if (onClose != null) { +// Box( +// modifier = Modifier.padding(8.dp) +// ) { +// FloconIconTonalButton( +// onClick = onClose, +// modifier = Modifier +// .graphicsLayer { +// this.alpha = 1f - translationX.value.div(PanelWidth) +// } +// ) { +// FloconIcon( +// Icons.Outlined.Close +// ) +// } +// } +// } +// Box( +// modifier = Modifier +// .width(PanelWidth) +// .fillMaxHeight() +// .graphicsLayer { +// this.translationX = translationX.value.toPx() +// } +// .border(width = 1.dp, color = FloconTheme.colorPalette.surface), +// content = content +// ) +// } +// } +// onDispose { floconPanelController.hide() } +// } +// } } @Composable diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt index 64e6cc3a8..d77a2dbb9 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt @@ -10,6 +10,7 @@ import androidx.compose.ui.Modifier import androidx.navigation3.runtime.EntryProviderBuilder import androidx.navigation3.runtime.entryProvider import androidx.navigation3.runtime.rememberSavedStateNavEntryDecorator +import androidx.navigation3.scene.DialogSceneStrategy import androidx.navigation3.scene.SceneStrategy import androidx.navigation3.scene.SinglePaneSceneStrategy import androidx.navigation3.scene.rememberSceneSetupNavEntryDecorator diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt index e7a17acbd..63bdb933c 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt @@ -8,12 +8,6 @@ import androidx.navigation3.scene.Scene import androidx.navigation3.scene.SceneStrategy import io.github.openflocon.navigation.FloconRoute -enum class Menu { - HOME, - SETTINGS, - ABOUT, -} - class MenuScene( override val key: String, override val previousEntries: List>, @@ -49,7 +43,7 @@ class MenuSceneStrategy( ): Scene? { val lastEntry = entries.last() - return if (lastEntry.metadata.containsKey(MenuScene.MENU_KEY)) { + return if (lastEntry.metadata.containsKey(MenuScene.MENU_KEY) && lastEntry.metadata[MenuScene.MENU_KEY] == true) { MenuScene( key = MenuScene.MENU_KEY, previousEntries = entries.dropLast(1), From bc9e2a304d4d3feff7252707870255b541ecde82 Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 22 Oct 2025 08:49:50 +0200 Subject: [PATCH 09/28] feature: Rework --- FloconDesktop/composeApp/build.gradle.kts | 2 + .../io/github/openflocon/flocondesktop/App.kt | 214 ----------- .../openflocon/flocondesktop/AppWindow.kt | 116 ++++++ .../openflocon/flocondesktop/app/AppAction.kt | 8 +- .../flocondesktop/app/AppViewModel.kt | 32 +- .../flocondesktop/app/models/AppUiState.kt | 7 +- .../flocondesktop/app/models/SubScreen.kt | 20 - .../common/utils/ClosableScopeExt.kt | 16 + .../common/utils/ViewModelExt.kt | 1 + .../flocondesktop/core/data/settings/DI.kt | 9 + .../data/settings/SettingsRepositoryImpl.kt | 12 +- .../datasource/local/SettingsDataSource.kt | 6 +- .../local/SettingsDataSourcePrefs.kt | 67 +++- .../settings/models/NetworkSettingsLocal.kt | 21 ++ .../usecase/ObserveNetworkSettingsUseCase.kt | 13 + .../flocondesktop/core/di/CoreModule.kt | 3 + .../features/analytics/Navigation.kt | 14 +- .../features/network/Navigation.kt | 30 +- .../features/network/NetworkUiModule.kt | 3 + .../network/detail/NetworkDetailDelegate.kt | 67 ++++ .../network/detail/NetworkDetailViewModel.kt | 22 ++ .../detail/mapper/NetworkDetailUiMapper.kt | 8 +- .../detail/model/NetworkDetailHeaderUi.kt | 2 + .../detail/model/NetworkDetailViewState.kt | 9 + .../network/detail/view/NetworkDetailView.kt | 49 +-- .../features/network/list/NetworkViewModel.kt | 67 ++-- .../network/list/model/NetworkStatusUi.kt | 2 + .../network/list/model/NetworkUiState.kt | 4 +- .../network/list/view/NetworkScreen.kt | 345 +++++++++--------- .../flocondesktop/main/di/MainModule.kt | 11 - .../flocondesktop/main/ui/di/MainUiModule.kt | 17 - .../flocondesktop/main/ui/model/SubScreen.kt | 32 -- .../flocondesktop/menu/MenuRoutes.kt | 42 +++ .../flocondesktop/menu/di/MainModule.kt | 10 + .../menu/ui/MenuNavigationState.kt | 19 + .../MainScreen.kt => menu/ui/MenuScreen.kt} | 211 ++++------- .../ui/MenuViewModel.kt} | 45 ++- .../ui/delegates/DevicesDelegate.kt | 8 +- .../{main => menu}/ui/delegates/Mapper.kt | 6 +- .../ui/delegates/RecordVideoDelegate.kt | 4 +- .../flocondesktop/menu/ui/di/MainUiModule.kt | 25 ++ .../ui/model/DeviceAppUiModel.kt | 2 +- .../ui/model/DeviceItemUiModel.kt | 2 +- .../ui/model/DevicesStateUiModel.kt | 2 +- .../ui/model/RecordVideoStateUiModel.kt | 2 +- .../flocondesktop/menu/ui/model/SubScreen.kt | 26 ++ .../ui/model/leftpanel/LeftPanelItem.kt | 4 +- .../ui/model/leftpanel/LeftPannelSection.kt | 2 +- .../ui/model/leftpanel/MenuUiState.kt | 5 +- .../{main => menu}/ui/settings/AboutScreen.kt | 2 +- .../menu/ui/settings/Navigation.kt | 12 + .../ui/settings/SettingsAction.kt | 2 +- .../ui/settings/SettingsScreen.kt | 2 +- .../ui/settings/SettingsUiState.kt | 2 +- .../ui/settings/SettingsViewModel.kt | 2 +- .../ui/view/SubScreenSelectorItem.kt | 4 +- .../ui/view/leftpannel/LeftPannelDivider.kt | 2 +- .../ui/view/leftpannel/LeftPannelView.kt | 23 +- .../ui/view/leftpannel/PannelLabel.kt | 2 +- .../ui/view/leftpannel/PannelView.kt | 8 +- .../ui/view/topbar/MainScreenTopBar.kt | 24 +- .../ui/view/topbar/TopBarDeviceAndAppView.kt | 31 +- .../ui/view/topbar/TopBarSelector.kt | 2 +- .../ui/view/topbar/actions/TopBarActions.kt | 7 +- .../ui/view/topbar/actions/TopBarButton.kt | 2 +- .../ui/view/topbar/app/TopBarAppDropdown.kt | 10 +- .../ui/view/topbar/app/TopBarAppView.kt | 5 +- .../topbar/device/TopBarDeviceDropdown.kt | 8 +- .../ui/view/topbar/device/TopBarDeviceView.kt | 4 +- .../github/openflocon/flocondesktop/Main.kt | 2 +- .../domain/models/settings/NetworkSettings.kt | 5 + .../settings/repository/SettingsRepository.kt | 4 + FloconDesktop/gradle/libs.versions.toml | 5 +- .../components/FloconAnimateVisibility.kt | 32 ++ .../designsystem/components/FloconFeature.kt | 4 +- .../designsystem/components/FloconScaffold.kt | 4 + .../components/panel/FloconPanel.kt | 92 +++-- .../io/github/openflocon/navigation/DI.kt | 8 - .../openflocon/navigation/FloconNavigation.kt | 61 +--- .../navigation/FloconNavigationState.kt | 19 +- .../openflocon/navigation/scene/MenuScene.kt | 59 --- .../openflocon/navigation/scene/PanelScene.kt | 103 ++++++ .../navigation/scene/WindowScene.kt | 57 +++ 83 files changed, 1259 insertions(+), 994 deletions(-) delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/SubScreen.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/utils/ClosableScopeExt.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/DI.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/models/NetworkSettingsLocal.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/usecase/ObserveNetworkSettingsUseCase.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/NetworkDetailDelegate.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/NetworkDetailViewModel.kt delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/di/MainModule.kt delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/di/MainUiModule.kt delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/SubScreen.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/di/MainModule.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuNavigationState.kt rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main/ui/MainScreen.kt => menu/ui/MenuScreen.kt} (50%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main/ui/MainViewModel.kt => menu/ui/MenuViewModel.kt} (79%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/delegates/DevicesDelegate.kt (95%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/delegates/Mapper.kt (90%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/delegates/RecordVideoDelegate.kt (95%) create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/di/MainUiModule.kt rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/model/DeviceAppUiModel.kt (84%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/model/DeviceItemUiModel.kt (91%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/model/DevicesStateUiModel.kt (97%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/model/RecordVideoStateUiModel.kt (53%) create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/SubScreen.kt rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/model/leftpanel/LeftPanelItem.kt (68%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/model/leftpanel/LeftPannelSection.kt (59%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/model/leftpanel/MenuUiState.kt (94%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/settings/AboutScreen.kt (97%) create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/Navigation.kt rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/settings/SettingsAction.kt (65%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/settings/SettingsScreen.kt (99%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/settings/SettingsUiState.kt (76%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/settings/SettingsViewModel.kt (98%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/SubScreenSelectorItem.kt (93%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/leftpannel/LeftPannelDivider.kt (88%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/leftpannel/LeftPannelView.kt (82%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/leftpannel/PannelLabel.kt (96%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/leftpannel/PannelView.kt (95%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/topbar/MainScreenTopBar.kt (77%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/topbar/TopBarDeviceAndAppView.kt (55%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/topbar/TopBarSelector.kt (96%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/topbar/actions/TopBarActions.kt (89%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/topbar/actions/TopBarButton.kt (93%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/topbar/app/TopBarAppDropdown.kt (91%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/topbar/app/TopBarAppView.kt (96%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/topbar/device/TopBarDeviceDropdown.kt (92%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{main => menu}/ui/view/topbar/device/TopBarDeviceView.kt (98%) create mode 100644 FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/models/settings/NetworkSettings.kt create mode 100644 FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt delete mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/DI.kt delete mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt create mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt create mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/WindowScene.kt diff --git a/FloconDesktop/composeApp/build.gradle.kts b/FloconDesktop/composeApp/build.gradle.kts index 8f920407e..598940733 100644 --- a/FloconDesktop/composeApp/build.gradle.kts +++ b/FloconDesktop/composeApp/build.gradle.kts @@ -81,6 +81,8 @@ kotlin { implementation(projects.navigation) implementation(libs.kermit) + +// implementation(libs.material3.adaptive) } commonTest.dependencies { implementation(libs.kotlin.test) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt deleted file mode 100644 index ddb14e1f9..000000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/App.kt +++ /dev/null @@ -1,214 +0,0 @@ -@file:OptIn(ExperimentalFoundationApi::class) - -package io.github.openflocon.flocondesktop - -import androidx.compose.animation.core.animateDpAsState -import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.foundation.ComposeFoundationFlags -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.ChevronRight -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.rotate -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.layout.onGloballyPositioned -import androidx.compose.ui.unit.IntSize -import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation3.scene.SinglePaneSceneStrategy -import com.flocon.data.remote.dataRemoteModule -import io.github.openflocon.data.core.dataCoreModule -import io.github.openflocon.data.local.dataLocalModule -import io.github.openflocon.domain.adb.repository.AdbRepository -import io.github.openflocon.domain.domainModule -import io.github.openflocon.domain.settings.usecase.ObserveFontSizeMultiplierUseCase -import io.github.openflocon.flocondesktop.adb.AdbRepositoryImpl -import io.github.openflocon.flocondesktop.app.AppAction -import io.github.openflocon.flocondesktop.app.AppViewModel -import io.github.openflocon.flocondesktop.app.di.appModule -import io.github.openflocon.flocondesktop.app.models.AppUiState -import io.github.openflocon.flocondesktop.common.di.commonModule -import io.github.openflocon.flocondesktop.core.di.coreModule -import io.github.openflocon.flocondesktop.features.analytics.analyticsNavigation -import io.github.openflocon.flocondesktop.features.featuresModule -import io.github.openflocon.flocondesktop.features.network.NetworkRoute -import io.github.openflocon.flocondesktop.features.network.networkNavigation -import io.github.openflocon.flocondesktop.main.di.mainModule -import io.github.openflocon.flocondesktop.main.ui.view.leftpannel.LeftPanelView -import io.github.openflocon.flocondesktop.main.ui.view.leftpannel.PanelMaxWidth -import io.github.openflocon.flocondesktop.main.ui.view.leftpannel.PanelMinWidth -import io.github.openflocon.library.designsystem.FloconTheme -import io.github.openflocon.library.designsystem.components.FloconIcon -import io.github.openflocon.library.designsystem.components.FloconSurface -import io.github.openflocon.navigation.FloconNavigation -import io.github.openflocon.navigation.FloconNavigationState -import io.github.openflocon.navigation.navigationModule -import io.github.openflocon.navigation.scene.MenuSceneStrategy -import org.koin.compose.KoinApplication -import org.koin.compose.koinInject -import org.koin.compose.viewmodel.koinViewModel -import org.koin.core.module.dsl.singleOf -import org.koin.dsl.bind -import org.koin.dsl.module - -@Composable -fun App() { - ComposeFoundationFlags.isNewContextMenuEnabled = true - - KoinApplication( - application = { - modules( - commonModule, - appModule, - coreModule, - mainModule, - featuresModule, - domainModule, - dataCoreModule, - dataLocalModule, - dataRemoteModule, - navigationModule, - // Temporary - module { - singleOf(::AdbRepositoryImpl) bind AdbRepository::class - }, - ) - }, - ) { - val fontSizeMultiplier by koinInject()() - .collectAsStateWithLifecycle() - -// val panelController = rememberFloconPanelController() - - FloconTheme( - fontSizeMultiplier = fontSizeMultiplier - ) { - val viewModel: AppViewModel = koinViewModel() - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - - Content( - uiState = uiState, - navigationState = viewModel.navigationState, - onAction = viewModel::onAction - ) - - -// FloconSurface( -// modifier = Modifier -// .safeContentPadding() -// .fillMaxSize() -// ) { -// CompositionLocalProvider(LocalFloconPanelController provides panelController) { -// Box( -// modifier = Modifier.fillMaxSize() -// ) { -// MainScreen( -// modifier = Modifier -// .fillMaxSize(), -// ) -// FloconPanelDisplayer( -// panelController = panelController, -// modifier = Modifier.fillMaxSize() -// ) -// FeedbackDisplayerView() -// } -// } -// } - - -// Box( -// Modifier -// .safeContentPadding() -// .fillMaxSize() -// .background(FloconTheme.colorPalette.background), -// ) { -// MainScreen( -// modifier = Modifier -// .fillMaxSize(), -// ) -// FeedbackDisplayerView() -// } - } - } -} - -@Composable -private fun Content( - navigationState: FloconNavigationState, - uiState: AppUiState, - onAction: (AppAction) -> Unit -) { - var expanded by remember { mutableStateOf(true) } - val width by animateDpAsState(targetValue = if (expanded) PanelMaxWidth else PanelMinWidth) - var windowSize by remember { mutableStateOf(IntSize.Zero) } - val position by animateDpAsState( - targetValue = if (expanded) PanelMaxWidth else PanelMinWidth, - ) - val rotate by animateFloatAsState(targetValue = if (expanded) 180f else 0f) - - FloconSurface( - modifier = Modifier - .fillMaxSize() - .onGloballyPositioned { - windowSize = it.size // TODO Add windowsize lib - }, - ) { - FloconNavigation( - navigationState = navigationState, - sceneStrategy = MenuSceneStrategy( - menuContent = { - LeftPanelView( - state = uiState.menuState, - onClickItem = { onAction(AppAction.SelectMenu(it.screen)) }, - modifier = Modifier - .width(width) - .fillMaxHeight(), - expanded = expanded - ) - }, - expander = { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier.width(20.dp) - .height(60.dp) - .graphicsLayer { - translationX = position.toPx() - size.width / 2 - 8.dp.toPx() - translationY = (windowSize.height / 2) - (size.height / 2) - } - .clip(RoundedCornerShape(4.dp)) - .background(FloconTheme.colorPalette.primary) - .clickable(onClick = { expanded = !expanded }), - ) { - FloconIcon( - imageVector = Icons.Outlined.ChevronRight, - tint = Color.LightGray, - modifier = Modifier.rotate(rotate), - ) - } - } - ) - .then(SinglePaneSceneStrategy()), - modifier = Modifier.fillMaxSize() - ) { - networkNavigation() - analyticsNavigation() - } - } -} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt new file mode 100644 index 000000000..2a3267d92 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt @@ -0,0 +1,116 @@ +@file:OptIn(ExperimentalFoundationApi::class) + +package io.github.openflocon.flocondesktop + +import androidx.compose.foundation.ComposeFoundationFlags +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation3.scene.DialogSceneStrategy +import androidx.navigation3.scene.SinglePaneSceneStrategy +import com.flocon.data.remote.dataRemoteModule +import io.github.openflocon.data.core.dataCoreModule +import io.github.openflocon.data.local.dataLocalModule +import io.github.openflocon.domain.adb.repository.AdbRepository +import io.github.openflocon.domain.domainModule +import io.github.openflocon.domain.settings.usecase.ObserveFontSizeMultiplierUseCase +import io.github.openflocon.flocondesktop.adb.AdbRepositoryImpl +import io.github.openflocon.flocondesktop.app.AppViewModel +import io.github.openflocon.flocondesktop.app.di.appModule +import io.github.openflocon.flocondesktop.common.di.commonModule +import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayerView +import io.github.openflocon.flocondesktop.core.di.coreModule +import io.github.openflocon.flocondesktop.features.analytics.analyticsRoutes +import io.github.openflocon.flocondesktop.features.featuresModule +import io.github.openflocon.flocondesktop.features.network.networkRoutes +import io.github.openflocon.flocondesktop.menu.MainRoutes +import io.github.openflocon.flocondesktop.menu.di.mainModule +import io.github.openflocon.flocondesktop.menu.menuRoutes +import io.github.openflocon.library.designsystem.FloconTheme +import io.github.openflocon.navigation.FloconNavigation +import io.github.openflocon.navigation.MainFloconNavigationState +import io.github.openflocon.navigation.scene.PanelSceneStrategy +import io.github.openflocon.navigation.scene.WindowSceneStrategy +import org.koin.compose.KoinApplication +import org.koin.compose.koinInject +import org.koin.compose.scope.KoinScope +import org.koin.compose.viewmodel.koinViewModel +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.bind +import org.koin.dsl.module + +@Composable +fun App() { + ComposeFoundationFlags.isNewContextMenuEnabled = true + + KoinApplication( + application = { + modules( + commonModule, + appModule, + coreModule, + mainModule, + featuresModule, + domainModule, + dataCoreModule, + dataLocalModule, + dataRemoteModule, + // Temporary + module { + scope { + scoped { MainFloconNavigationState(MainRoutes.Main) } + } + singleOf(::AdbRepositoryImpl) bind AdbRepository::class + }, + ) + }, + ) { + val fontSizeMultiplier by koinInject()() + .collectAsStateWithLifecycle() + + KoinScope( + scopeDefinition = { createScope(MainRoutes.Sub.Main) } + ) { + FloconTheme( + fontSizeMultiplier = fontSizeMultiplier + ) { + val viewModel: AppViewModel = koinViewModel() + + Content( + navigationState = viewModel.navigationState, + ) + } + } + } +} + +@Composable +private fun Content( + navigationState: MainFloconNavigationState +) { + Box( + modifier = Modifier + .fillMaxSize() + ) { + FloconNavigation( + navigationState = navigationState, + sceneStrategy = PanelSceneStrategy() + .then(WindowSceneStrategy()) + .then(DialogSceneStrategy()) + .then(SinglePaneSceneStrategy()), + modifier = Modifier + .matchParentSize() + .background(FloconTheme.colorPalette.surface) + ) { + menuRoutes() + networkRoutes() + analyticsRoutes() + } + FeedbackDisplayerView() + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt index eb21e0561..a9fded2bd 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt @@ -1,9 +1,3 @@ package io.github.openflocon.flocondesktop.app -import io.github.openflocon.flocondesktop.main.ui.model.SubScreen - -internal sealed interface AppAction { - - data class SelectMenu(val screen: SubScreen) : AppAction - -} +internal sealed interface AppAction diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt index 69ce836eb..4afec9e08 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt @@ -5,18 +5,9 @@ import androidx.lifecycle.viewModelScope import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.settings.usecase.InitAdbPathUseCase import io.github.openflocon.domain.settings.usecase.StartAdbForwardUseCase -import io.github.openflocon.flocondesktop.app.models.AppUiState -import io.github.openflocon.flocondesktop.app.models.route -import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed -import io.github.openflocon.flocondesktop.features.network.NetworkRoute -import io.github.openflocon.flocondesktop.main.ui.buildLeftPanelState -import io.github.openflocon.flocondesktop.main.ui.model.SubScreen import io.github.openflocon.flocondesktop.messages.ui.MessagesServerDelegate -import io.github.openflocon.navigation.FloconNavigationState +import io.github.openflocon.navigation.MainFloconNavigationState import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.update import kotlinx.coroutines.isActive import kotlinx.coroutines.launch @@ -24,20 +15,11 @@ internal class AppViewModel( messagesServerDelegate: MessagesServerDelegate, initAdbPathUseCase: InitAdbPathUseCase, startAdbForwardUseCase: StartAdbForwardUseCase, - val navigationState: FloconNavigationState, + val navigationState: MainFloconNavigationState, private val initialSetupStateHolder: InitialSetupStateHolder, dispatcherProvider: DispatcherProvider, ) : ViewModel(messagesServerDelegate) { - private val menuState = MutableStateFlow( - buildLeftPanelState(current = SubScreen.Network) - ) - - val uiState = menuState.map { - AppUiState(menuState = it) - } - .stateInWhileSubscribed(AppUiState(menuState = menuState.value)) - init { viewModelScope.launch(dispatcherProvider.viewModel) { initAdbPathUseCase().alsoFailure { @@ -53,18 +35,8 @@ internal class AppViewModel( delay(1_500) } } - - navigationState.navigate(NetworkRoute) } } - fun onAction(action: AppAction) = when (action) { - is AppAction.SelectMenu -> onSelectMenu(action) - } - - private fun onSelectMenu(action: AppAction.SelectMenu) { - menuState.update { it.copy(current = action.screen) } - navigationState.navigate(action.screen.route) - } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/AppUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/AppUiState.kt index 9c13b10e7..880c1e759 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/AppUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/AppUiState.kt @@ -1,15 +1,12 @@ package io.github.openflocon.flocondesktop.app.models import androidx.compose.runtime.Immutable -import io.github.openflocon.flocondesktop.main.ui.model.SubScreen -import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPanelState -import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.previewLeftPannelState @Immutable internal data class AppUiState( - val menuState: LeftPanelState // TODO Rename + val test: String ) private fun previewAppUiState() = AppUiState( - menuState = previewLeftPannelState(SubScreen.Network) + test = "" ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/SubScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/SubScreen.kt deleted file mode 100644 index 7923077e7..000000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/SubScreen.kt +++ /dev/null @@ -1,20 +0,0 @@ -package io.github.openflocon.flocondesktop.app.models - -import io.github.openflocon.flocondesktop.features.analytics.AnalyticsRoute -import io.github.openflocon.flocondesktop.features.network.NetworkRoute -import io.github.openflocon.flocondesktop.main.ui.model.SubScreen -import io.github.openflocon.navigation.FloconRoute - -val SubScreen.route: FloconRoute - get() = when (this) { - SubScreen.Dashboard -> TODO() - SubScreen.Network -> NetworkRoute - SubScreen.Images -> TODO() - SubScreen.Database -> TODO() - SubScreen.Files -> TODO() - SubScreen.SharedPreferences -> TODO() - SubScreen.Analytics -> AnalyticsRoute - SubScreen.Tables -> TODO() - SubScreen.Settings -> TODO() - SubScreen.Deeplinks -> TODO() - } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/utils/ClosableScopeExt.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/utils/ClosableScopeExt.kt new file mode 100644 index 000000000..1fcf5739d --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/utils/ClosableScopeExt.kt @@ -0,0 +1,16 @@ +package io.github.openflocon.flocondesktop.common.utils + +import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableScoped +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.stateIn + +context(closableScope: CloseableScoped) +fun Flow.stateInWhileSubscribed(default: T): StateFlow { + return stateIn( + scope = closableScope.coroutineScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = default + ) +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/utils/ViewModelExt.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/utils/ViewModelExt.kt index ccdb85034..d3d5ce98b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/utils/ViewModelExt.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/utils/ViewModelExt.kt @@ -2,6 +2,7 @@ package io.github.openflocon.flocondesktop.common.utils import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableScoped import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/DI.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/DI.kt new file mode 100644 index 000000000..d44084a7f --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/DI.kt @@ -0,0 +1,9 @@ +package io.github.openflocon.flocondesktop.core.data.settings + +import io.github.openflocon.flocondesktop.core.data.settings.usecase.ObserveNetworkSettingsUseCase +import org.koin.core.module.dsl.factoryOf +import org.koin.dsl.module + +internal val settingsModule = module { + factoryOf(::ObserveNetworkSettingsUseCase) +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/SettingsRepositoryImpl.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/SettingsRepositoryImpl.kt index e77038fd8..eff8addc0 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/SettingsRepositoryImpl.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/SettingsRepositoryImpl.kt @@ -1,17 +1,27 @@ package io.github.openflocon.flocondesktop.core.data.settings +import io.github.openflocon.domain.models.settings.NetworkSettings import io.github.openflocon.domain.settings.repository.SettingsRepository import io.github.openflocon.flocondesktop.core.data.settings.datasource.local.SettingsDataSource +import io.github.openflocon.flocondesktop.core.data.settings.models.toDomain +import io.github.openflocon.flocondesktop.core.data.settings.models.toLocal import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.mapLatest -class SettingsRepositoryImpl( +internal class SettingsRepositoryImpl( private val localSettingsDataSource: SettingsDataSource, ) : SettingsRepository { override val adbPath: Flow = localSettingsDataSource.adbPath override val fontSizeMultiplier: StateFlow = localSettingsDataSource.fontSizeMultiplier + override var networkSettings: NetworkSettings + get() = localSettingsDataSource.networkSettings.toDomain() + set(value) { localSettingsDataSource.networkSettings = value.toLocal() } + override val networkSettingsFlow: Flow = localSettingsDataSource.networkSettingsFlow + .mapLatest { it.toDomain() } + override fun getAdbPath(): String? = localSettingsDataSource.getAdbPath() override suspend fun setAdbPath(path: String) { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/datasource/local/SettingsDataSource.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/datasource/local/SettingsDataSource.kt index c165ab00d..8401218b0 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/datasource/local/SettingsDataSource.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/datasource/local/SettingsDataSource.kt @@ -1,9 +1,13 @@ package io.github.openflocon.flocondesktop.core.data.settings.datasource.local +import io.github.openflocon.flocondesktop.core.data.settings.models.NetworkSettingsLocal import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow -interface SettingsDataSource { +internal interface SettingsDataSource { + var networkSettings: NetworkSettingsLocal + val networkSettingsFlow: StateFlow + fun getAdbPath(): String? suspend fun setAdbPath(path: String) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/datasource/local/SettingsDataSourcePrefs.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/datasource/local/SettingsDataSourcePrefs.kt index bb76e31c7..e4b2e26ed 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/datasource/local/SettingsDataSourcePrefs.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/datasource/local/SettingsDataSourcePrefs.kt @@ -1,35 +1,50 @@ -@file:OptIn(ExperimentalSettingsApi::class) +@file:OptIn(ExperimentalSettingsApi::class, ExperimentalSerializationApi::class) package io.github.openflocon.flocondesktop.core.data.settings.datasource.local import com.russhwolf.settings.ExperimentalSettingsApi import com.russhwolf.settings.ObservableSettings import com.russhwolf.settings.coroutines.toFlowSettings +import io.github.openflocon.flocondesktop.core.data.settings.models.NetworkSettingsLocal import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.stateIn +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.KSerializer +import kotlinx.serialization.json.Json +import kotlinx.serialization.serializer +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty expect fun createSettings(): ObservableSettings -class SettingsDataSourcePrefs( - applicationScope: CoroutineScope +internal class SettingsDataSourcePrefs( + private val applicationScope: CoroutineScope ) : SettingsDataSource { + + private val json = Json { + ignoreUnknownKeys = true + } + private val settings = createSettings() private val flowSettings = settings.toFlowSettings() + override var networkSettings: NetworkSettingsLocal by NETWORK_SETTINGS.classDelegateOf(NetworkSettingsLocal()) + override val networkSettingsFlow = flowSettings.getStringOrNullFlow(NETWORK_SETTINGS) + .filterNotNull() + .mapLatest { json.decodeFromString(it) } + .stateIn(networkSettings) + override val adbPath: Flow = flowSettings.getStringOrNullFlow(ADB_PATH) override val fontSizeMultiplier: StateFlow = settings.toFlowSettings() .getFloatOrNullFlow(FONT_SIZE_MULTIPLIER) .filterNotNull() - .stateIn( - scope = applicationScope, - started = SharingStarted.Lazily, - initialValue = 1f - ) + .stateIn(1f) override fun getAdbPath(): String? = settings.getStringOrNull(ADB_PATH) @@ -41,8 +56,44 @@ class SettingsDataSourcePrefs( settings.putFloat(FONT_SIZE_MULTIPLIER, value) } + private fun Flow.stateIn(default: T) = stateIn( + scope = applicationScope, + started = SharingStarted.Lazily, + initialValue = default + ) + + private inner class ClassDelegate( + private val key: String, + private val default: T, + private val serializer: KSerializer + ) : ReadWriteProperty { + + override fun getValue(thisRef: SettingsDataSourcePrefs, property: KProperty<*>): T { + return thisRef.settings.getStringOrNull(key) + ?.let { json.decodeFromString(serializer, it) } + ?: default + } + + override fun setValue(thisRef: SettingsDataSourcePrefs, property: KProperty<*>, value: T?) { + thisRef.settings + .putString(key = key, value = json.encodeToString(serializer, value ?: return)) + } + + } + + private inline fun String.classDelegateOf(default: T): ClassDelegate { + return ClassDelegate( + key = this, + default = default, + serializer = serializer() + ) + } + companion object { private const val ADB_PATH = "adb_path" private const val FONT_SIZE_MULTIPLIER = "font_size_multiplier" + + private const val NETWORK_SETTINGS = "network_settings" } + } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/models/NetworkSettingsLocal.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/models/NetworkSettingsLocal.kt new file mode 100644 index 000000000..517f040cc --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/models/NetworkSettingsLocal.kt @@ -0,0 +1,21 @@ +package io.github.openflocon.flocondesktop.core.data.settings.models + +import io.github.openflocon.domain.models.settings.NetworkSettings +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +internal data class NetworkSettingsLocal( + + @SerialName("pinned_detail") + val pinnedDetails: Boolean = false + +) + +internal fun NetworkSettingsLocal.toDomain() = NetworkSettings( + pinnedDetails = pinnedDetails +) + +internal fun NetworkSettings.toLocal() = NetworkSettingsLocal( + pinnedDetails = pinnedDetails +) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/usecase/ObserveNetworkSettingsUseCase.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/usecase/ObserveNetworkSettingsUseCase.kt new file mode 100644 index 000000000..052e577c9 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/usecase/ObserveNetworkSettingsUseCase.kt @@ -0,0 +1,13 @@ +package io.github.openflocon.flocondesktop.core.data.settings.usecase + +import io.github.openflocon.domain.models.settings.NetworkSettings +import io.github.openflocon.domain.settings.repository.SettingsRepository +import kotlinx.coroutines.flow.Flow + +class ObserveNetworkSettingsUseCase( + private val settingsRepository: SettingsRepository +) { + + operator fun invoke(): Flow = settingsRepository.networkSettingsFlow + +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/di/CoreModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/di/CoreModule.kt index 215f4f30b..354d945ea 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/di/CoreModule.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/di/CoreModule.kt @@ -1,10 +1,13 @@ package io.github.openflocon.flocondesktop.core.di import io.github.openflocon.flocondesktop.core.data.di.coreDataModule +import io.github.openflocon.flocondesktop.core.data.settings.settingsModule import org.koin.dsl.module val coreModule = module { includes( coreDataModule, + + settingsModule ) } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt index f28f2eb14..0736c2dbc 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt @@ -1,18 +1,8 @@ package io.github.openflocon.flocondesktop.features.analytics import androidx.navigation3.runtime.EntryProviderBuilder -import io.github.openflocon.flocondesktop.features.analytics.view.AnalyticsScreen import io.github.openflocon.navigation.FloconRoute -import io.github.openflocon.navigation.scene.MenuScene -import kotlinx.serialization.Serializable -@Serializable -data object AnalyticsRoute : FloconRoute - -fun EntryProviderBuilder.analyticsNavigation() { - entry( - metadata = mapOf(MenuScene.MENU_KEY to true) - ) { - AnalyticsScreen() - } +fun EntryProviderBuilder.analyticsRoutes() { + // TODO } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt index 17357e582..2468a027f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt @@ -1,18 +1,32 @@ package io.github.openflocon.flocondesktop.features.network import androidx.navigation3.runtime.EntryProviderBuilder -import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen +import io.github.openflocon.domain.settings.repository.SettingsRepository +import io.github.openflocon.flocondesktop.features.network.detail.view.NetworkDetailScreen import io.github.openflocon.navigation.FloconRoute -import io.github.openflocon.navigation.scene.MenuScene +import io.github.openflocon.navigation.scene.PanelSceneStrategy import kotlinx.serialization.Serializable +import org.koin.mp.KoinPlatform -@Serializable -data object NetworkRoute : FloconRoute +internal sealed interface NetworkRoutes : FloconRoute { -fun EntryProviderBuilder.networkNavigation() { - entry( - metadata = mapOf(MenuScene.MENU_KEY to true) + @Serializable + data class Panel(val requestId: String) : FloconRoute + +} + +fun EntryProviderBuilder.networkRoutes() { + entry( + metadata = PanelSceneStrategy.panel( + pinnable = true, + closable = true, + onPin = { + val repository = KoinPlatform.getKoin().get() + + repository.networkSettings = repository.networkSettings.copy(pinnedDetails = true) + } + ) ) { - NetworkScreen() + NetworkDetailScreen(requestId = it.requestId) } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkUiModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkUiModule.kt index c4ef7de9e..1b587e3f9 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkUiModule.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkUiModule.kt @@ -1,6 +1,7 @@ package io.github.openflocon.flocondesktop.features.network import io.github.openflocon.flocondesktop.features.network.badquality.BadQualityNetworkViewModel +import io.github.openflocon.flocondesktop.features.network.detail.NetworkDetailDelegate import io.github.openflocon.flocondesktop.features.network.list.NetworkViewModel import io.github.openflocon.flocondesktop.features.network.list.delegate.HeaderDelegate import io.github.openflocon.flocondesktop.features.network.list.delegate.OpenBodyDelegate @@ -25,4 +26,6 @@ internal val networkModule = module { viewModelOf(::BadQualityNetworkViewModel) viewModelOf(::NetworkWebsocketMockViewModel) + + factoryOf(::NetworkDetailDelegate) } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/NetworkDetailDelegate.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/NetworkDetailDelegate.kt new file mode 100644 index 000000000..dcef18a20 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/NetworkDetailDelegate.kt @@ -0,0 +1,67 @@ +package io.github.openflocon.flocondesktop.features.network.detail + +import io.github.openflocon.domain.common.DispatcherProvider +import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel +import io.github.openflocon.domain.network.usecase.ObserveNetworkRequestsByIdUseCase +import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableDelegate +import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableScoped +import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed +import io.github.openflocon.flocondesktop.features.network.detail.mapper.toDetailUi +import io.github.openflocon.flocondesktop.features.network.detail.model.NetworkDetailViewState +import io.github.openflocon.flocondesktop.features.network.list.model.NetworkAction +import io.github.openflocon.flocondesktop.features.network.list.model.NetworkMethodUi +import io.github.openflocon.flocondesktop.features.network.list.model.NetworkStatusUi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.update + +class NetworkDetailDelegate( + private val closeableDelegate: CloseableDelegate, + observeNetworkRequestsByIdUseCase: ObserveNetworkRequestsByIdUseCase, + dispatcherProvider: DispatcherProvider +) : CloseableScoped by closeableDelegate { + + private val _requestId = MutableStateFlow("") + + val uiState: StateFlow = _requestId.flatMapLatest { + observeNetworkRequestsByIdUseCase(it) + } + .distinctUntilChanged() + .filterNotNull() + .map(FloconNetworkCallDomainModel::toDetailUi) + .flowOn(dispatcherProvider.viewModel) + .stateInWhileSubscribed( + NetworkDetailViewState( + callId = "", + fullUrl = "", + requestTimeFormatted = "", + durationFormatted = "", + method = NetworkDetailViewState.Method.Http(NetworkMethodUi.Http.GET), + statusLabel = "", + status = NetworkStatusUi( + text = "", + status = NetworkStatusUi.Status.SUCCESS, + ), + graphQlSection = null, + requestBodyTitle = "", + requestBody = "", + requestSize = "", + requestHeaders = emptyList(), + response = null + ) + ) + + fun setRequestId(requestId: String) { + _requestId.update { requestId } + } + + fun onAction(action: NetworkAction) { + + } + +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/NetworkDetailViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/NetworkDetailViewModel.kt new file mode 100644 index 000000000..6358d77b3 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/NetworkDetailViewModel.kt @@ -0,0 +1,22 @@ +package io.github.openflocon.flocondesktop.features.network.detail + +import androidx.lifecycle.ViewModel +import io.github.openflocon.flocondesktop.features.network.list.model.NetworkAction +import org.koin.core.component.KoinComponent + +class NetworkDetailViewModel( + requestId: String, + delegate: NetworkDetailDelegate +) : ViewModel(), KoinComponent { + + val uiState = delegate.uiState + + init { + delegate.setRequestId(requestId) + } + + fun onAction(action: NetworkAction) { + + } + +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/mapper/NetworkDetailUiMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/mapper/NetworkDetailUiMapper.kt index 93c27e6c3..414aef195 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/mapper/NetworkDetailUiMapper.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/mapper/NetworkDetailUiMapper.kt @@ -54,11 +54,11 @@ fun toDetailUi( headers = toNetworkHeadersUi(it.headers), ) - } + } - }, - graphQlSection = graphQlSection(request), - ) + }, + graphQlSection = graphQlSection(this), +) private fun toDetailStatusLabel(request: FloconNetworkCallDomainModel): String = when (request.request.specificInfos) { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailHeaderUi.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailHeaderUi.kt index aa1e7ab4f..e7b3a64c8 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailHeaderUi.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailHeaderUi.kt @@ -1,8 +1,10 @@ package io.github.openflocon.flocondesktop.features.network.detail.model import androidx.compose.runtime.Immutable +import kotlinx.serialization.Serializable @Immutable +@Serializable data class NetworkDetailHeaderUi( val name: String, val value: String, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailViewState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailViewState.kt index 6ff0339a7..82a92efa5 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailViewState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailViewState.kt @@ -3,8 +3,10 @@ package io.github.openflocon.flocondesktop.features.network.detail.model import androidx.compose.runtime.Immutable import io.github.openflocon.flocondesktop.features.network.list.model.NetworkMethodUi import io.github.openflocon.flocondesktop.features.network.list.model.NetworkStatusUi +import kotlinx.serialization.Serializable @Immutable +@Serializable data class NetworkDetailViewState( val callId: String, val fullUrl: String, @@ -30,8 +32,10 @@ data class NetworkDetailViewState( val response: Response?, ) { @Immutable + @Serializable sealed interface Response { @Immutable + @Serializable data class Success( val body: String, val responseBodyIsNotBlank: Boolean, @@ -40,12 +44,14 @@ data class NetworkDetailViewState( val headers: List?, ) : Response @Immutable + @Serializable data class Error( val issue: String, ) : Response } @Immutable + @Serializable data class GraphQlSection( val queryName: String, val method: NetworkMethodUi, @@ -53,11 +59,14 @@ data class NetworkDetailViewState( ) @Immutable + @Serializable sealed interface Method { @Immutable + @Serializable data class Http(val method: NetworkMethodUi) : Method @Immutable + @Serializable data class MethodName(val name: String) : Method } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/NetworkDetailView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/NetworkDetailView.kt index 5fea0c3f0..274a5cf5f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/NetworkDetailView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/NetworkDetailView.kt @@ -20,15 +20,13 @@ import androidx.compose.material.icons.outlined.OpenInFull import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import coil3.compose.AsyncImage +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import io.github.openflocon.flocondesktop.features.network.detail.NetworkDetailViewModel import io.github.openflocon.flocondesktop.features.network.detail.model.NetworkDetailViewState import io.github.openflocon.flocondesktop.features.network.detail.model.previewNetworkDetailHeaderUi import io.github.openflocon.flocondesktop.features.network.detail.view.components.DetailHeadersView @@ -47,29 +45,39 @@ import io.github.openflocon.library.designsystem.components.FloconSection import io.github.openflocon.library.designsystem.components.FloconVerticalScrollbar import io.github.openflocon.library.designsystem.components.rememberFloconScrollbarAdapter import org.jetbrains.compose.ui.tooling.preview.Preview +import org.koin.compose.viewmodel.koinViewModel +import org.koin.core.parameter.parametersOf private const val LARGE_BODY_LENGHT = 30_000 @Composable -fun NetworkDetailView( - state: NetworkDetailViewState, +fun NetworkDetailScreen( + requestId: String +) { + val viewModel = koinViewModel { + parametersOf(requestId) + } + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + NetworkDetailContent( + uiState = uiState, + onAction = viewModel::onAction + ) +} + +@Composable +fun NetworkDetailContent( + uiState: NetworkDetailViewState, onAction: (NetworkAction) -> Unit, - modifier: Modifier = Modifier, + modifier: Modifier = Modifier ) { val scrollState: ScrollState = rememberScrollState() - val scrollAdapter = rememberFloconScrollbarAdapter(scrollState) - val linesLabelWidth: Dp = 130.dp val headersLabelWidth: Dp = 150.dp -// EscapeHandler { -// onAction(NetworkAction.ClosePanel) -// true // consumed -// } - Box( - modifier + modifier = modifier .background(FloconTheme.colorPalette.primary) ) { Column( @@ -80,7 +88,7 @@ fun NetworkDetailView( Request( modifier = Modifier .fillMaxWidth(), - state = state, + state = uiState, onAction = onAction, linesLabelWidth = linesLabelWidth, headersLabelWidth = headersLabelWidth, @@ -94,7 +102,7 @@ fun NetworkDetailView( Response( modifier = Modifier .fillMaxWidth(), - state = state, + state = uiState, onAction = onAction, headersLabelWidth = headersLabelWidth, ) @@ -523,8 +531,8 @@ private fun Response( @Composable private fun NetworkDetailViewPreview() { FloconTheme { - NetworkDetailView( - state = NetworkDetailViewState( + NetworkDetailContent( + uiState = NetworkDetailViewState( callId = "", fullUrl = "http://www.google.com", method = NetworkDetailViewState.Method.Http(NetworkMethodUi.Http.GET), @@ -587,8 +595,7 @@ private fun NetworkDetailViewPreview() { canOpenRequestBody = true, requestBodyIsNotBlank = true, ), - modifier = Modifier.padding(16.dp), // Padding pour la preview - onAction = {}, + onAction = {} ) } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt index 0aac43440..f1ada2c3f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt @@ -31,14 +31,16 @@ import io.github.openflocon.domain.network.usecase.RemoveOldSessionsNetworkReque import io.github.openflocon.domain.network.usecase.ResetCurrentDeviceHttpRequestsUseCase import io.github.openflocon.domain.network.usecase.badquality.ObserveAllNetworkBadQualitiesUseCase import io.github.openflocon.domain.network.usecase.mocks.ObserveNetworkMocksUseCase +import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed +import io.github.openflocon.flocondesktop.core.data.settings.usecase.ObserveNetworkSettingsUseCase +import io.github.openflocon.flocondesktop.features.network.NetworkRoutes import io.github.openflocon.domain.network.usecase.mocks.ObserveNetworkWebsocketIdsUseCase import io.github.openflocon.domain.network.usecase.settings.ObserveNetworkSettingsUseCase import io.github.openflocon.domain.network.usecase.settings.UpdateNetworkSettingsUseCase import io.github.openflocon.flocondesktop.common.utils.OpenFile import io.github.openflocon.flocondesktop.features.network.body.model.ContentUiState import io.github.openflocon.flocondesktop.features.network.body.model.MockDisplayed -import io.github.openflocon.flocondesktop.features.network.detail.mapper.toDetailUi -import io.github.openflocon.flocondesktop.features.network.detail.model.NetworkDetailViewState +import io.github.openflocon.flocondesktop.features.network.detail.NetworkDetailDelegate import io.github.openflocon.flocondesktop.features.network.list.delegate.HeaderDelegate import io.github.openflocon.flocondesktop.features.network.list.delegate.OpenBodyDelegate import io.github.openflocon.flocondesktop.features.network.list.mapper.toDomain @@ -51,15 +53,15 @@ import io.github.openflocon.flocondesktop.features.network.list.model.TopBarUiSt import io.github.openflocon.flocondesktop.features.network.list.model.header.columns.base.filter.TextFilterStateUiModel import io.github.openflocon.flocondesktop.features.network.model.NetworkBodyDetailUi import io.github.openflocon.library.designsystem.common.copyToClipboard +import io.github.openflocon.navigation.MainFloconNavigationState +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -84,6 +86,9 @@ class NetworkViewModel( private val exportNetworkCallsToCsv: ExportNetworkCallsToCsvUseCase, private val decodeJwtTokenUseCase: DecodeJwtTokenUseCase, private val removeOldSessionsNetworkRequestUseCase: RemoveOldSessionsNetworkRequestUseCase, + private val navigationState: MainFloconNavigationState, + private val detailDelegate: NetworkDetailDelegate, + private val observeNetworkSettingsUseCase: ObserveNetworkSettingsUseCase private val observeNetworkSettingsUseCase: ObserveNetworkSettingsUseCase, private val updateNetworkSettingsUseCase: UpdateNetworkSettingsUseCase, private val observeNetworkWebsocketIdsUseCase: ObserveNetworkWebsocketIdsUseCase, @@ -141,20 +146,6 @@ class NetworkViewModel( ) ) - private val detailState: StateFlow = - contentState.map { it.selectedRequestId } - .flatMapLatest { id -> - if (id == null) { - flowOf(null) - } else { - observeNetworkRequestsByIdUseCase(id) - .distinctUntilChanged() - .map { it?.let { toDetailUi(it) } } - } - } - .flowOn(dispatcherProvider.viewModel) - .stateIn(viewModelScope, started = SharingStarted.WhileSubscribed(5_000), null) - private val filter = combines( snapshotFlow { _filterText.value }.map { it.takeIf { it.isNotBlank() } } .distinctUntilChanged(), @@ -174,7 +165,8 @@ class NetworkViewModel( private val sortAndFilter = combines( headerDelegate.sorted.map { it?.toDomain() }.distinctUntilChanged(), filter, - ).distinctUntilChanged() + ) + .distinctUntilChanged() val items: Flow> = observeCurrentDeviceIdAndPackageNameUseCase() @@ -196,6 +188,15 @@ class NetworkViewModel( .flowOn(dispatcherProvider.viewModel) .cachedIn(viewModelScope) + private val detailState = combine( + detailDelegate.uiState, + contentState, + observeNetworkSettingsUseCase() + ) { state, content, settings -> + state.takeIf { settings.pinnedDetails && content.selectedRequestId != null } + } + .stateInWhileSubscribed(null) + val uiState = combine( contentState, detailState, @@ -216,7 +217,7 @@ class NetworkViewModel( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), initialValue = NetworkUiState( - detailState = detailState.value, + detailState = detailDelegate.uiState.value, contentState = contentState.value, filterState = filterUiState.value, headerState = headerDelegate.headerUiState.value, @@ -311,16 +312,28 @@ class NetworkViewModel( } } + private var selectRequestJob: Job? = null private fun onSelectRequest(action: NetworkAction.SelectRequest) { - contentState.update { state -> - state.copy( - selectedRequestId = if (state.selectedRequestId == action.id) { - null + contentState.update { it.copy(selectedRequestId = action.id) } + selectRequestJob?.cancel() + selectRequestJob = viewModelScope.launch { + observeNetworkSettingsUseCase().collect { + if (it.pinnedDetails) { + detailDelegate.setRequestId(action.id) } else { - action.id - }, - ) + navigationState.navigate(NetworkRoutes.Panel(action.id)) + } + } } +// contentState.update { state -> +// state.copy( +// selectedRequestId = if (state.selectedRequestId == action.id) { +// null +// } else { +// action.id +// }, +// ) +// } } private fun openMocks(callId: String?) { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkStatusUi.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkStatusUi.kt index 4478dfdc1..a8b563e26 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkStatusUi.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkStatusUi.kt @@ -1,8 +1,10 @@ package io.github.openflocon.flocondesktop.features.network.list.model import androidx.compose.runtime.Immutable +import kotlinx.serialization.Serializable @Immutable +@Serializable data class NetworkStatusUi( val text: String, val status: Status, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkUiState.kt index 6dcf5f9e0..4e0514682 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkUiState.kt @@ -2,10 +2,10 @@ package io.github.openflocon.flocondesktop.features.network.list.model import androidx.compose.runtime.Immutable import io.github.openflocon.flocondesktop.features.network.body.model.ContentUiState +import io.github.openflocon.flocondesktop.features.network.body.model.previewContentUiState import io.github.openflocon.flocondesktop.features.network.detail.model.NetworkDetailViewState import io.github.openflocon.flocondesktop.features.network.list.model.header.NetworkHeaderUiState import io.github.openflocon.flocondesktop.features.network.list.model.header.previewNetworkHeaderUiState -import io.github.openflocon.flocondesktop.features.network.body.model.previewContentUiState @Immutable data class NetworkUiState( @@ -13,7 +13,7 @@ data class NetworkUiState( val settings: NetworkSettingsUiModel, val detailState: NetworkDetailViewState?, val filterState: TopBarUiState, - val headerState: NetworkHeaderUiState, + val headerState: NetworkHeaderUiState ) fun previewNetworkUiState() = NetworkUiState( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt index 9975c5c7b..26f55640d 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt @@ -5,11 +5,14 @@ import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons @@ -19,7 +22,7 @@ import androidx.compose.material.icons.outlined.CleaningServices import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.History import androidx.compose.material.icons.outlined.ImportExport -import androidx.compose.material.icons.outlined.Outbox +import androidx.compose.material.icons.outlined.PinEnd import androidx.compose.material.icons.outlined.PlayCircle import androidx.compose.material.icons.outlined.Podcasts import androidx.compose.material.icons.outlined.SignalWifiStatusbarConnectedNoInternet4 @@ -39,19 +42,17 @@ import androidx.compose.ui.input.key.KeyEventType import androidx.compose.ui.input.key.key import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.input.key.type -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.paging.PagingData import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.itemKey -import com.composeunstyled.Text +import io.github.openflocon.domain.settings.repository.SettingsRepository import io.github.openflocon.flocondesktop.common.ui.window.FloconWindowState import io.github.openflocon.flocondesktop.common.ui.window.createFloconWindowState import io.github.openflocon.flocondesktop.features.network.badquality.list.view.BadNetworkQualityWindow -import io.github.openflocon.flocondesktop.features.network.detail.view.NetworkDetailView +import io.github.openflocon.flocondesktop.features.network.detail.view.NetworkDetailContent import io.github.openflocon.flocondesktop.features.network.list.NetworkViewModel import io.github.openflocon.flocondesktop.features.network.list.model.NetworkAction import io.github.openflocon.flocondesktop.features.network.list.model.NetworkItemColumnWidths @@ -67,6 +68,7 @@ import io.github.openflocon.flocondesktop.features.network.model.NetworkBodyDeta import io.github.openflocon.flocondesktop.features.network.view.NetworkBodyWindow import io.github.openflocon.flocondesktop.features.network.websocket.NetworkWebsocketMockWindow import io.github.openflocon.library.designsystem.FloconTheme +import io.github.openflocon.library.designsystem.components.FloconAnimateVisibility import io.github.openflocon.library.designsystem.components.FloconDropdownMenuItem import io.github.openflocon.library.designsystem.components.FloconDropdownSeparator import io.github.openflocon.library.designsystem.components.FloconFeature @@ -74,14 +76,14 @@ import io.github.openflocon.library.designsystem.components.FloconHorizontalDivi import io.github.openflocon.library.designsystem.components.FloconIcon import io.github.openflocon.library.designsystem.components.FloconIconButton import io.github.openflocon.library.designsystem.components.FloconIconToggleButton +import io.github.openflocon.library.designsystem.components.FloconIconTonalButton import io.github.openflocon.library.designsystem.components.FloconOverflow import io.github.openflocon.library.designsystem.components.FloconPageTopBar import io.github.openflocon.library.designsystem.components.FloconVerticalScrollbar -import io.github.openflocon.library.designsystem.components.panel.FloconPanel import io.github.openflocon.library.designsystem.components.rememberFloconScrollbarAdapter import kotlinx.coroutines.flow.MutableStateFlow import org.koin.compose.viewmodel.koinViewModel - +import org.koin.mp.KoinPlatform @Composable fun NetworkScreen( @@ -111,8 +113,7 @@ fun NetworkScreen( ) { val lazyListState = rememberLazyListState() val scrollAdapter = rememberFloconScrollbarAdapter(lazyListState) - val columnWidths: NetworkItemColumnWidths = - remember { NetworkItemColumnWidths() } // Default widths provided + val columnWidths: NetworkItemColumnWidths = remember { NetworkItemColumnWidths() } // Default widths provided LaunchedEffect(uiState.settings.autoScroll, rows.itemCount) { if (uiState.settings.autoScroll && rows.itemCount != -1) { @@ -120,95 +121,81 @@ fun NetworkScreen( } } - FloconFeature( - modifier = modifier + Row( + modifier = Modifier .fillMaxSize() - .clickable( - interactionSource = null, - indication = null, - enabled = uiState.detailState != null, - onClick = { onAction(NetworkAction.ClosePanel) }, - ) - .onPreviewKeyEvent { event -> - if (event.type != KeyEventType.KeyDown) - return@onPreviewKeyEvent false + ) { + FloconFeature( + contentPadding = PaddingValues(0.dp), + modifier = modifier + .fillMaxHeight() + .weight(1f) + .clickable( + interactionSource = null, + indication = null, + enabled = uiState.detailState != null, + onClick = { onAction(NetworkAction.ClosePanel) }, + ) + .onPreviewKeyEvent { event -> + if (event.type != KeyEventType.KeyDown) + return@onPreviewKeyEvent false - when (event.key) { - Key.DirectionUp -> { - selectPreviousRow(rows, uiState) - ?.let { - onAction(NetworkAction.Up(it.uuid)) - } + when (event.key) { + Key.DirectionUp -> { + selectPreviousRow(rows, uiState) + ?.let { + onAction(NetworkAction.Up(it.uuid)) + } - true - } + true + } - Key.DirectionDown -> { - selectNextRow(rows, uiState) - ?.let { - onAction(NetworkAction.Down(it.uuid)) - } - true - } + Key.DirectionDown -> { + selectNextRow(rows, uiState) + ?.let { + onAction(NetworkAction.Down(it.uuid)) + } + true + } - else -> false + else -> false + } } - } - ) { - FloconPageTopBar( - modifier = Modifier.fillMaxWidth(), - filterBar = { - FilterBar( - filterText = filterText, - placeholderText = "Filter route", - onTextChange = { onAction(NetworkAction.FilterQuery(it)) }, - modifier = Modifier.fillMaxWidth(.7f), - ) - }, - actions = { - if (uiState.filterState.hasWebsockets) { + ) { + FloconPageTopBar( + modifier = Modifier.fillMaxWidth(), + filterBar = { + FilterBar( + filterText = filterText, + placeholderText = "Filter route", + onTextChange = { onAction(NetworkAction.FilterQuery(it)) }, + modifier = Modifier.fillMaxWidth(.7f), + ) + }, + actions = { FloconIconToggleButton( - value = true, - tooltip = "Websocket Mocks", - onValueChange = { onAction(NetworkAction.OpenWebsocketMocks) } + value = uiState.filterState.hasMocks, + tooltip = "Mocks", + onValueChange = { onAction(NetworkAction.OpenMocks) } ) { FloconIcon( - imageVector = Icons.Outlined.Outbox + imageVector = Icons.Outlined.WifiTethering ) } - } - FloconIconToggleButton( - value = uiState.filterState.displayOldSessions, - tooltip = "Display old sessions", - onValueChange = { onAction(NetworkAction.UpdateDisplayOldSessions(it)) } - ) { - FloconIcon( - imageVector = Icons.Outlined.History - ) - } - FloconIconToggleButton( - value = uiState.filterState.hasMocks, - tooltip = "Mocks", - onValueChange = { onAction(NetworkAction.OpenMocks) } - ) { - FloconIcon( - imageVector = Icons.Outlined.WifiTethering - ) - } - FloconIconToggleButton( - value = uiState.filterState.hasBadNetwork, - tooltip = "Bad network", - onValueChange = { onAction(NetworkAction.OpenBadNetworkQuality) } - ) { - FloconIcon( - imageVector = Icons.Outlined.SignalWifiStatusbarConnectedNoInternet4 + FloconIconToggleButton( + value = uiState.filterState.hasBadNetwork, + tooltip = "Bad network", + onValueChange = { onAction(NetworkAction.OpenBadNetworkQuality) } + ) { + FloconIcon( + imageVector = Icons.Outlined.SignalWifiStatusbarConnectedNoInternet4 + ) + } + FloconIconButton( + imageVector = Icons.Outlined.Delete, + onClick = { onAction(NetworkAction.Reset) } ) - } - FloconIconButton( - imageVector = Icons.Outlined.Delete, - onClick = { onAction(NetworkAction.Reset) } - ) - // TODO Later + // TODO Later // FloconDropdownMenu( // expanded = expandedColumn, // anchorContent = { @@ -251,99 +238,123 @@ fun NetworkScreen( // onCheckedChange = {} // ) // } - FloconOverflow { - FloconDropdownMenuItem( - text = "Export CSV", - leadingIcon = Icons.Outlined.ImportExport, - onClick = { onAction(NetworkAction.ExportCsv) } - ) - FloconDropdownMenuItem( - checked = uiState.settings.autoScroll, - text = "Auto scroll", - leadingIcon = Icons.Outlined.PlayCircle, - onCheckedChange = { onAction(NetworkAction.ToggleAutoScroll(it)) } - ) - FloconDropdownMenuItem( - checked = uiState.settings.invertList, - text = "Invert list", - leadingIcon = Icons.AutoMirrored.Outlined.List, - onCheckedChange = { onAction(NetworkAction.InvertList(it)) } - ) - FloconDropdownSeparator() - FloconDropdownMenuItem( - text = "Clear old sessions", - leadingIcon = Icons.Outlined.CleaningServices, - onClick = { onAction(NetworkAction.ClearOldSession) } - ) - } - }, - ) - Column( - modifier = Modifier - .fillMaxSize() - .clip(FloconTheme.shapes.medium) - .background(FloconTheme.colorPalette.primary) - ) { - NetworkItemHeaderView( - columnWidths = columnWidths, - modifier = Modifier - .fillMaxWidth() - .background(FloconTheme.colorPalette.primary), - clickOnSort = { type, sort -> - onAction(NetworkAction.HeaderAction.ClickOnSort(type, sort)) - }, - onFilterAction = { - onAction(NetworkAction.HeaderAction.FilterAction(it)) + FloconOverflow { + FloconDropdownMenuItem( + text = "Export CSV", + leadingIcon = Icons.Outlined.ImportExport, + onClick = { onAction(NetworkAction.ExportCsv) } + ) + FloconDropdownMenuItem( + checked = uiState.contentState.autoScroll, + text = "Auto scroll", + leadingIcon = Icons.Outlined.PlayCircle, + onCheckedChange = { onAction(NetworkAction.ToggleAutoScroll) } + ) + FloconDropdownMenuItem( + checked = uiState.contentState.invertList, + text = "Invert list", + leadingIcon = Icons.AutoMirrored.Outlined.List, + onCheckedChange = { onAction(NetworkAction.InvertList(it)) } + ) + FloconDropdownSeparator() + FloconDropdownMenuItem( + text = "Clear old sessions", + leadingIcon = Icons.Outlined.CleaningServices, + onClick = { onAction(NetworkAction.ClearOldSession) } + ) + } }, - state = uiState.headerState, ) - FloconHorizontalDivider() - Row( - Modifier.fillMaxSize() + Column( + modifier = Modifier + .fillMaxSize() + .clip(FloconTheme.shapes.medium) + .background(FloconTheme.colorPalette.primary) ) { - LazyColumn( - state = lazyListState, - reverseLayout = uiState.settings.invertList, + NetworkItemHeaderView( + columnWidths = columnWidths, modifier = Modifier - .fillMaxHeight() - .weight(1f) + .fillMaxWidth() + .background(FloconTheme.colorPalette.primary), + clickOnSort = { type, sort -> + onAction(NetworkAction.HeaderAction.ClickOnSort(type, sort)) + }, + onFilterAction = { + onAction(NetworkAction.HeaderAction.FilterAction(it)) + }, + state = uiState.headerState, + ) + FloconHorizontalDivider() + Row( + Modifier.fillMaxSize() ) { - items( - count = rows.itemCount, - key = rows.itemKey { it.uuid }, - ) { index -> - val item = rows[index] - if (item != null) { - NetworkItemView( - state = item, - selected = item.uuid == uiState.contentState.selectedRequestId, - columnWidths = columnWidths, - onAction = onAction, - modifier = Modifier - .fillMaxWidth() - .animateItem(), - ) - } else { - Box(Modifier) // display nothing during load + LazyColumn( + state = lazyListState, + reverseLayout = uiState.contentState.invertList, + modifier = Modifier + .fillMaxHeight() + .weight(1f) + ) { + items( + count = rows.itemCount, + key = rows.itemKey { it.uuid }, + ) { index -> + val item = rows[index] + if (item != null) { + NetworkItemView( + state = item, + selected = item.uuid == uiState.contentState.selectedRequestId, + columnWidths = columnWidths, + onAction = onAction, + modifier = Modifier + .fillMaxWidth() + .animateItem(), + ) + } else { + Box(Modifier) // display nothing during load + } } } + FloconVerticalScrollbar( + adapter = scrollAdapter, + modifier = Modifier.fillMaxHeight(), + ) } - FloconVerticalScrollbar( - adapter = scrollAdapter, - modifier = Modifier.fillMaxHeight(), + } + } + FloconAnimateVisibility( + uiState.detailState + ) { + Row { + Spacer(Modifier.width(8.dp)) + NetworkDetailContent( + uiState = it, + onAction = onAction, + modifier = Modifier + .width(300.dp) // TODO Change, settings ? + .clip(FloconTheme.shapes.medium) ) } } } - FloconPanel( - contentState = uiState.detailState, - onClose = { onAction(NetworkAction.ClosePanel) } + + // TODO Change + Box( + contentAlignment = Alignment.TopEnd, + modifier = Modifier.fillMaxSize() ) { - NetworkDetailView( - state = it, - onAction = onAction, - modifier = Modifier.matchParentSize() - ) + FloconIconTonalButton( + onClick = { + val repository = KoinPlatform.getKoin().get() + + repository.networkSettings = repository.networkSettings.copy(pinnedDetails = false) + }, + modifier = Modifier.align(Alignment.BottomStart) + ) { + FloconIcon( + Icons.Outlined.PinEnd + ) + } } val states = remember { mutableStateMapOf() } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/di/MainModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/di/MainModule.kt deleted file mode 100644 index f280cb15a..000000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/di/MainModule.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.openflocon.flocondesktop.main.di - -import io.github.openflocon.flocondesktop.main.ui.di.mainUiModule -import org.koin.dsl.module - -val mainModule = - module { - includes( - mainUiModule, - ) - } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/di/MainUiModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/di/MainUiModule.kt deleted file mode 100644 index 69483969a..000000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/di/MainUiModule.kt +++ /dev/null @@ -1,17 +0,0 @@ -package io.github.openflocon.flocondesktop.main.ui.di - -import io.github.openflocon.flocondesktop.main.ui.MainViewModel -import io.github.openflocon.flocondesktop.main.ui.delegates.DevicesDelegate -import io.github.openflocon.flocondesktop.main.ui.delegates.RecordVideoDelegate -import io.github.openflocon.flocondesktop.main.ui.settings.SettingsViewModel -import org.koin.core.module.dsl.factoryOf -import org.koin.core.module.dsl.viewModelOf -import org.koin.dsl.module - -val mainUiModule = - module { - viewModelOf(::MainViewModel) - factoryOf(::DevicesDelegate) - factoryOf(::RecordVideoDelegate) - viewModelOf(::SettingsViewModel) - } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/SubScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/SubScreen.kt deleted file mode 100644 index d0fb1dfa6..000000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/SubScreen.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.openflocon.flocondesktop.main.ui.model - -enum class SubScreen { - Dashboard, - - // TODO group network, grpc, networkImages - Network, - Images, // network images - - // storage - Database, - Files, // device files (context.cache, context.files) - SharedPreferences, - - Analytics, - Tables, - - Settings, - - Deeplinks, - - ; - - companion object { - fun fromId(id: String): SubScreen = SubScreen.valueOf(id) - } -} - -val SubScreen.id: String - get() { - return this.name - } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt new file mode 100644 index 000000000..2cb3744b6 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt @@ -0,0 +1,42 @@ +package io.github.openflocon.flocondesktop.menu + +import androidx.navigation3.runtime.EntryProviderBuilder +import io.github.openflocon.flocondesktop.menu.ui.MenuScreen +import io.github.openflocon.navigation.FloconRoute +import io.github.openflocon.navigation.scene.WindowSceneStrategy +import kotlinx.serialization.Serializable +import org.koin.core.Koin +import org.koin.core.component.KoinScopeComponent +import org.koin.core.component.createScope +import org.koin.core.qualifier.Qualifier +import org.koin.core.qualifier.QualifierValue +import org.koin.core.scope.Scope + +internal sealed interface MainRoutes : FloconRoute { + + @Serializable + data object Main : MainRoutes + + @Serializable + data class Sub( + val id: String + ) : MainRoutes, KoinScopeComponent { + override val scope: Scope + get() = createScope(scopeId = id) + + companion object { + val Main = Sub(id = "main") + } + } + +} + +internal fun Koin.createFloconScope(sub: MainRoutes.Sub) = createScope(sub) + +fun EntryProviderBuilder.menuRoutes() { + entry { MenuScreen() } + // TODO Scope VM on this + entry(metadata = WindowSceneStrategy.window()) { + MenuScreen() // TODO Remove toolbar + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/di/MainModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/di/MainModule.kt new file mode 100644 index 000000000..06a9ee36b --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/di/MainModule.kt @@ -0,0 +1,10 @@ +package io.github.openflocon.flocondesktop.menu.di + +import io.github.openflocon.flocondesktop.menu.ui.di.mainUiModule +import org.koin.dsl.module + +val mainModule = module { + includes( + mainUiModule + ) +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuNavigationState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuNavigationState.kt new file mode 100644 index 000000000..3d2b194ab --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuNavigationState.kt @@ -0,0 +1,19 @@ +package io.github.openflocon.flocondesktop.menu.ui + +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.snapshots.SnapshotStateList +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +import io.github.openflocon.navigation.FloconNavigationState + +class MenuNavigationState(initialScreen: SubScreen) : FloconNavigationState { + private val _stack = mutableStateListOf(initialScreen) + override val stack: SnapshotStateList = _stack + + override fun navigate(route: SubScreen) { + _stack.add(route) + } + + override fun back(count: Int) { + repeat(count) { _stack.removeLast() } + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt similarity index 50% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainScreen.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt index 0d915dd43..979f0d6e3 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt @@ -1,6 +1,6 @@ @file:OptIn(ExperimentalMaterial3Api::class) -package io.github.openflocon.flocondesktop.main.ui +package io.github.openflocon.flocondesktop.menu.ui import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateFloatAsState @@ -9,10 +9,11 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons @@ -32,8 +33,8 @@ import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp -import androidx.compose.ui.zIndex import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation3.runtime.EntryProviderBuilder import io.github.openflocon.flocondesktop.features.analytics.view.AnalyticsScreen import io.github.openflocon.flocondesktop.features.dashboard.view.DashboardScreen import io.github.openflocon.flocondesktop.features.database.view.DatabaseScreen @@ -43,57 +44,56 @@ import io.github.openflocon.flocondesktop.features.images.view.ImagesScreen import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen import io.github.openflocon.flocondesktop.features.sharedpreferences.view.SharedPreferencesScreen import io.github.openflocon.flocondesktop.features.table.view.TableScreen -import io.github.openflocon.flocondesktop.main.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DeviceItemUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.main.ui.model.RecordVideoStateUiModel -import io.github.openflocon.flocondesktop.main.ui.model.SubScreen -import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPanelItem -import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPanelState -import io.github.openflocon.flocondesktop.main.ui.settings.SettingsScreen -import io.github.openflocon.flocondesktop.main.ui.view.leftpannel.LeftPanelView -import io.github.openflocon.flocondesktop.main.ui.view.leftpannel.PanelMaxWidth -import io.github.openflocon.flocondesktop.main.ui.view.leftpannel.PanelMinWidth -import io.github.openflocon.flocondesktop.main.ui.view.topbar.MainScreenTopBar +import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelItem +import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelState +import io.github.openflocon.flocondesktop.menu.ui.settings.SettingsScreen +import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.LeftPanelView +import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.PanelMaxWidth +import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.PanelMinWidth +import io.github.openflocon.flocondesktop.menu.ui.view.topbar.MainScreenTopBar import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconIcon +import io.github.openflocon.navigation.FloconNavigation +import org.koin.compose.currentKoinScope import org.koin.compose.viewmodel.koinViewModel @Composable -fun MainScreen( - modifier: Modifier = Modifier, +fun MenuScreen( + modifier: Modifier = Modifier ) { - val viewModel: MainViewModel = koinViewModel() + val viewModel: MainViewModel = currentKoinScope().get() val leftPanelState by viewModel.leftPanelState.collectAsStateWithLifecycle() - val subScreen by viewModel.subScreen.collectAsStateWithLifecycle() val devicesState by viewModel.devicesState.collectAsStateWithLifecycle() val appsState by viewModel.appsState.collectAsStateWithLifecycle() val recordState by viewModel.recordState.collectAsStateWithLifecycle() - Box(modifier = modifier) { - MainScreen( - subScreen = subScreen, - modifier = Modifier.fillMaxSize(), - devicesState = devicesState, - appsState = appsState, - recordState = recordState, - onDeviceSelected = viewModel::onDeviceSelected, - deleteDevice = viewModel::deleteDevice, - deleteApp = viewModel::deleteApp, - onAppSelected = viewModel::onAppSelected, - leftPanelState = leftPanelState, - onClickLeftPanelItem = viewModel::onClickLeftPanelItem, - onTakeScreenshotClicked = viewModel::onTakeScreenshotClicked, - onRecordClicked = viewModel::onRecordClicked, - onRestartClicked = viewModel::onRestartClicked, - ) - } + MenuScreen( + navigationState = viewModel.menuNavigationState, + modifier = modifier, + devicesState = devicesState, + appsState = appsState, + recordState = recordState, + onDeviceSelected = viewModel::onDeviceSelected, + deleteDevice = viewModel::deleteDevice, + deleteApp = viewModel::deleteApp, + onAppSelected = viewModel::onAppSelected, + leftPanelState = leftPanelState, + onClickLeftPanelItem = viewModel::onClickLeftPanelItem, + onTakeScreenshotClicked = viewModel::onTakeScreenshotClicked, + onRecordClicked = viewModel::onRecordClicked, + onRestartClicked = viewModel::onRestartClicked, + ) } @Composable -private fun MainScreen( - subScreen: SubScreen, +private fun MenuScreen( + navigationState: MenuNavigationState, leftPanelState: LeftPanelState, onClickLeftPanelItem: (LeftPanelItem) -> Unit, devicesState: DevicesStateUiModel, @@ -117,112 +117,44 @@ private fun MainScreen( val rotate by animateFloatAsState(targetValue = if (expanded) 180f else 0f) Column( - modifier = modifier + modifier = modifier.fillMaxSize() ) { MainScreenTopBar( - modifier = Modifier - .fillMaxWidth() - .zIndex(10f), - devicesState = devicesState, appsState = appsState, - onDeviceSelected = onDeviceSelected, + devicesState = devicesState, + recordState = recordState, + deleteApp = deleteApp, deleteDevice = deleteDevice, onAppSelected = onAppSelected, - deleteApp = deleteApp, - onTakeScreenshotClicked = onTakeScreenshotClicked, - recordState = recordState, onRecordClicked = onRecordClicked, onRestartClicked = onRestartClicked, + onDeviceSelected = onDeviceSelected, + onTakeScreenshotClicked = onTakeScreenshotClicked ) - Box( + Row( modifier = Modifier .fillMaxSize() - .onGloballyPositioned { - windowSize = it.size // TODO Add windowsize lib - }, + .padding(8.dp) ) { - Row( + LeftPanelView( + modifier = Modifier + .width(width) + .fillMaxHeight(), + expanded = expanded, + onClickItem = onClickLeftPanelItem, + state = leftPanelState, + ) + Spacer(Modifier.width(8.dp)) + FloconNavigation( + navigationState = navigationState, modifier = Modifier - .fillMaxSize(), + .weight(1f) + .fillMaxHeight() + .onGloballyPositioned { + windowSize = it.size // TODO Add windowsize lib + }, ) { - LeftPanelView( - modifier = Modifier - .width(width) - .fillMaxHeight(), - expanded = expanded, - onClickItem = onClickLeftPanelItem, - state = leftPanelState, - ) - Box( - modifier = Modifier - .fillMaxSize() - ) { - when (subScreen) { - SubScreen.Network -> - NetworkScreen( - modifier = Modifier - .fillMaxSize(), - ) - - SubScreen.Database -> - DatabaseScreen( - modifier = Modifier - .fillMaxSize(), - ) - - SubScreen.Images -> - ImagesScreen( - modifier = Modifier - .fillMaxSize(), - ) - - SubScreen.Files -> - FilesScreen( - modifier = Modifier - .fillMaxSize(), - ) - - SubScreen.Tables -> - TableScreen( - modifier = Modifier - .fillMaxSize(), - ) - - SubScreen.SharedPreferences -> - SharedPreferencesScreen( - modifier = Modifier - .fillMaxSize(), - ) - - SubScreen.Dashboard -> - DashboardScreen( - modifier = Modifier - .fillMaxSize(), - ) - - SubScreen.Settings -> { - SettingsScreen( - modifier = Modifier.fillMaxSize(), - ) - } - - SubScreen.Deeplinks -> { - DeeplinkScreen( - modifier = - Modifier - .fillMaxSize(), - ) - } - - SubScreen.Analytics -> { - AnalyticsScreen( - modifier = - Modifier - .fillMaxSize(), - ) - } - } - } + menus() } Box( contentAlignment = Alignment.Center, @@ -246,3 +178,16 @@ private fun MainScreen( } } } + +private fun EntryProviderBuilder.menus() { + entry { NetworkScreen() } + entry { DashboardScreen() } + entry { AnalyticsScreen() } + entry { TableScreen() } + entry { ImagesScreen() } + entry { FilesScreen() } + entry { SharedPreferencesScreen() } + entry { DatabaseScreen() } + entry { DeeplinkScreen() } + entry { SettingsScreen() } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuViewModel.kt similarity index 79% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainViewModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuViewModel.kt index 0fa63477e..a5698cfa5 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuViewModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui +package io.github.openflocon.flocondesktop.menu.ui import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -10,19 +10,20 @@ import io.github.openflocon.domain.device.usecase.RestartAppUseCase import io.github.openflocon.domain.device.usecase.TakeScreenshotUseCase import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.app.InitialSetupStateHolder -import io.github.openflocon.flocondesktop.main.ui.delegates.DevicesDelegate -import io.github.openflocon.flocondesktop.main.ui.delegates.RecordVideoDelegate -import io.github.openflocon.flocondesktop.main.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DeviceItemUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.main.ui.model.RecordVideoStateUiModel -import io.github.openflocon.flocondesktop.main.ui.model.SubScreen -import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPanelItem -import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPanelState -import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPannelSection -import io.github.openflocon.flocondesktop.main.ui.view.displayName -import io.github.openflocon.flocondesktop.main.ui.view.icon +import io.github.openflocon.flocondesktop.menu.ui.delegates.DevicesDelegate +import io.github.openflocon.flocondesktop.menu.ui.delegates.RecordVideoDelegate +import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelItem +import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelState +import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPannelSection +import io.github.openflocon.flocondesktop.menu.ui.view.displayName +import io.github.openflocon.flocondesktop.menu.ui.view.icon +import io.github.openflocon.navigation.MainFloconNavigationState import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -32,6 +33,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import org.koin.core.component.KoinComponent class MainViewModel( private val devicesDelegate: DevicesDelegate, @@ -42,11 +44,14 @@ class MainViewModel( private val recordVideoDelegate: RecordVideoDelegate, private val feedbackDisplayer: FeedbackDisplayer, private val observeCurrentDeviceCapabilitiesUseCase: ObserveCurrentDeviceCapabilitiesUseCase, + private val mainNavigationState: MainFloconNavigationState ) : ViewModel( devicesDelegate, recordVideoDelegate, -) { - val subScreen = MutableStateFlow(SubScreen.Network) +), KoinComponent { + + // TODO Remove + val subScreen = MutableStateFlow(SubScreen.Network) val recordState: StateFlow = recordVideoDelegate.state @@ -67,7 +72,8 @@ class MainViewModel( buildLeftPanelState( current = subScreen, ) - }.flowOn(dispatcherProvider.ui) + } + .flowOn(dispatcherProvider.ui) .stateIn( scope = viewModelScope, started = SharingStarted.Eagerly, @@ -77,6 +83,7 @@ class MainViewModel( val devicesState: StateFlow = devicesDelegate.devicesState val appsState: StateFlow = devicesDelegate.appsState + fun onDeviceSelected(device: DeviceItemUiModel) { viewModelScope.launch(dispatcherProvider.viewModel) { devicesDelegate.select(device.id) @@ -102,10 +109,12 @@ class MainViewModel( } fun onClickLeftPanelItem(leftPanelItem: LeftPanelItem) { - this.subScreen.update { leftPanelItem.screen } + menuNavigationState.navigate(leftPanelItem.screen) } fun onRecordClicked() { + // TODO Needs scoped vm +// mainNavigationState.navigate(MenuRoutes.App("zfjzhefoezf")) viewModelScope.launch(dispatcherProvider.viewModel) { recordVideoDelegate.toggleRecording() } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/delegates/DevicesDelegate.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/DevicesDelegate.kt similarity index 95% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/delegates/DevicesDelegate.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/DevicesDelegate.kt index 7e4980e28..cde372f68 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/delegates/DevicesDelegate.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/DevicesDelegate.kt @@ -1,6 +1,5 @@ -package io.github.openflocon.flocondesktop.main.ui.delegates +package io.github.openflocon.flocondesktop.menu.ui.delegates -import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel import io.github.openflocon.domain.device.usecase.DeleteDeviceApplicationUseCase import io.github.openflocon.domain.device.usecase.DeleteDeviceUseCase import io.github.openflocon.domain.device.usecase.GetCurrentDeviceIdAndPackageNameUseCase @@ -14,8 +13,8 @@ import io.github.openflocon.domain.device.usecase.SelectDeviceAppUseCase import io.github.openflocon.domain.device.usecase.SelectDeviceUseCase import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableDelegate import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableScoped -import io.github.openflocon.flocondesktop.main.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine @@ -23,7 +22,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.launch class DevicesDelegate( private val selectDeviceUseCase: SelectDeviceUseCase, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/delegates/Mapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/Mapper.kt similarity index 90% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/delegates/Mapper.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/Mapper.kt index ce27c5ede..48de72144 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/delegates/Mapper.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/Mapper.kt @@ -1,11 +1,11 @@ -package io.github.openflocon.flocondesktop.main.ui.delegates +package io.github.openflocon.flocondesktop.menu.ui.delegates import io.github.openflocon.domain.device.models.DeviceAppDomainModel import io.github.openflocon.domain.device.models.DeviceCapabilitiesDomainModel import io.github.openflocon.domain.device.models.DeviceDomainModel import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel -import io.github.openflocon.flocondesktop.main.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel internal fun mapListToUi( devices: List, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/delegates/RecordVideoDelegate.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/RecordVideoDelegate.kt similarity index 95% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/delegates/RecordVideoDelegate.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/RecordVideoDelegate.kt index efb910dff..052fe1d38 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/delegates/RecordVideoDelegate.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/RecordVideoDelegate.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.delegates +package io.github.openflocon.flocondesktop.menu.ui.delegates import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.device.models.RecordingDomainModel @@ -7,7 +7,7 @@ import io.github.openflocon.domain.device.usecase.StopRecordingVideoUseCase import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableDelegate import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableScoped -import io.github.openflocon.flocondesktop.main.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed import kotlinx.coroutines.flow.StateFlow diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/di/MainUiModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/di/MainUiModule.kt new file mode 100644 index 000000000..b0ac8e21c --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/di/MainUiModule.kt @@ -0,0 +1,25 @@ +package io.github.openflocon.flocondesktop.menu.ui.di + +import io.github.openflocon.flocondesktop.features.network.detail.NetworkDetailViewModel +import io.github.openflocon.flocondesktop.menu.MainRoutes +import io.github.openflocon.flocondesktop.menu.ui.MainViewModel +import io.github.openflocon.flocondesktop.menu.ui.MenuNavigationState +import io.github.openflocon.flocondesktop.menu.ui.delegates.DevicesDelegate +import io.github.openflocon.flocondesktop.menu.ui.delegates.RecordVideoDelegate +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +import io.github.openflocon.flocondesktop.menu.ui.settings.SettingsViewModel +import org.koin.core.module.dsl.factoryOf +import org.koin.core.module.dsl.viewModelOf +import org.koin.dsl.module + +val mainUiModule = module { + scope { + scoped { MenuNavigationState(SubScreen.Network) } + viewModelOf(::MainViewModel) + factoryOf(::DevicesDelegate) + factoryOf(::RecordVideoDelegate) + viewModelOf(::SettingsViewModel) + + viewModelOf(::NetworkDetailViewModel) + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/DeviceAppUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DeviceAppUiModel.kt similarity index 84% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/DeviceAppUiModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DeviceAppUiModel.kt index 037c859d4..fe2a83a3b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/DeviceAppUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DeviceAppUiModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.model +package io.github.openflocon.flocondesktop.menu.ui.model import androidx.compose.runtime.Immutable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/DeviceItemUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DeviceItemUiModel.kt similarity index 91% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/DeviceItemUiModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DeviceItemUiModel.kt index be8acdee3..f054a4feb 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/DeviceItemUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DeviceItemUiModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.model +package io.github.openflocon.flocondesktop.menu.ui.model import androidx.compose.runtime.Immutable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/DevicesStateUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DevicesStateUiModel.kt similarity index 97% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/DevicesStateUiModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DevicesStateUiModel.kt index f7f881fb8..0187530bb 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/DevicesStateUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DevicesStateUiModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.model +package io.github.openflocon.flocondesktop.menu.ui.model import androidx.compose.runtime.Immutable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/RecordVideoStateUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/RecordVideoStateUiModel.kt similarity index 53% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/RecordVideoStateUiModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/RecordVideoStateUiModel.kt index b70b23ef1..a08293303 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/RecordVideoStateUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/RecordVideoStateUiModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.model +package io.github.openflocon.flocondesktop.menu.ui.model enum class RecordVideoStateUiModel { Idle, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/SubScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/SubScreen.kt new file mode 100644 index 000000000..81f97ea97 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/SubScreen.kt @@ -0,0 +1,26 @@ +package io.github.openflocon.flocondesktop.menu.ui.model + +sealed interface SubScreen { + data object Dashboard : SubScreen + + // TODO group network, grpc, networkImages + data object Network : SubScreen + data object Images : SubScreen // network images + + // storage + data object Database : SubScreen + data object Files : SubScreen // device files (context.cache, context.files) + data object SharedPreferences : SubScreen + + data object Analytics : SubScreen + data object Tables : SubScreen + + data object Settings : SubScreen + + data object Deeplinks : SubScreen +} + +val SubScreen.id: String + get() { + return javaClass.simpleName + } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/LeftPanelItem.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/LeftPanelItem.kt similarity index 68% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/LeftPanelItem.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/LeftPanelItem.kt index 2f989ebdb..6b61924dc 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/LeftPanelItem.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/LeftPanelItem.kt @@ -1,8 +1,8 @@ -package io.github.openflocon.flocondesktop.main.ui.model.leftpanel +package io.github.openflocon.flocondesktop.menu.ui.model.leftpanel import androidx.compose.runtime.Immutable import androidx.compose.ui.graphics.vector.ImageVector -import io.github.openflocon.flocondesktop.main.ui.model.SubScreen +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen @Immutable data class LeftPanelItem( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/LeftPannelSection.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/LeftPannelSection.kt similarity index 59% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/LeftPannelSection.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/LeftPannelSection.kt index fe17ab05c..ece731ff1 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/LeftPannelSection.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/LeftPannelSection.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.model.leftpanel +package io.github.openflocon.flocondesktop.menu.ui.model.leftpanel data class LeftPannelSection( val title: String, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/MenuUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/MenuUiState.kt similarity index 94% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/MenuUiState.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/MenuUiState.kt index 91706972a..9eb6ac25f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/model/leftpanel/MenuUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/MenuUiState.kt @@ -1,8 +1,9 @@ -package io.github.openflocon.flocondesktop.main.ui.model.leftpanel +package io.github.openflocon.flocondesktop.menu.ui.model.leftpanel import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Analytics import androidx.compose.material.icons.outlined.Settings -import io.github.openflocon.flocondesktop.main.ui.model.SubScreen +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen data class LeftPanelState( val current: SubScreen, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/AboutScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/AboutScreen.kt similarity index 97% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/AboutScreen.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/AboutScreen.kt index 04d06296b..0dc692724 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/AboutScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/AboutScreen.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.settings +package io.github.openflocon.flocondesktop.menu.ui.settings import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/Navigation.kt new file mode 100644 index 000000000..9ab9e9661 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/Navigation.kt @@ -0,0 +1,12 @@ +package io.github.openflocon.flocondesktop.menu.ui.settings + +import androidx.navigation3.runtime.EntryProviderBuilder +import io.github.openflocon.navigation.FloconRoute + +data object SettingsRoute : FloconRoute + +fun EntryProviderBuilder.settingsRoutes() { + entry { + SettingsScreen() + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsAction.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsAction.kt similarity index 65% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsAction.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsAction.kt index b568f0ba8..8be8fdce9 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsAction.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsAction.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.settings +package io.github.openflocon.flocondesktop.menu.ui.settings sealed interface SettingsAction { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsScreen.kt similarity index 99% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsScreen.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsScreen.kt index 179d4e676..18552b1fe 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsScreen.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.settings +package io.github.openflocon.flocondesktop.menu.ui.settings import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsUiState.kt similarity index 76% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsUiState.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsUiState.kt index dc5c2f0b3..cfd182879 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsUiState.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.settings +package io.github.openflocon.flocondesktop.menu.ui.settings import androidx.compose.runtime.Immutable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsViewModel.kt similarity index 98% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsViewModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsViewModel.kt index dd9cf88ae..9decbe722 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsViewModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.settings +package io.github.openflocon.flocondesktop.menu.ui.settings import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/SubScreenSelectorItem.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/SubScreenSelectorItem.kt similarity index 93% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/SubScreenSelectorItem.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/SubScreenSelectorItem.kt index 011e4098e..961d7cb98 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/SubScreenSelectorItem.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/SubScreenSelectorItem.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.view +package io.github.openflocon.flocondesktop.menu.ui.view import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Link @@ -12,7 +12,7 @@ import androidx.compose.material.icons.outlined.StackedBarChart import androidx.compose.material.icons.outlined.Storage import androidx.compose.material.icons.outlined.TableView import androidx.compose.ui.graphics.vector.ImageVector -import io.github.openflocon.flocondesktop.main.ui.model.SubScreen +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen // Extension function to get the display name for each SubScreen fun SubScreen.displayName(): String = when (this) { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/LeftPannelDivider.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelDivider.kt similarity index 88% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/LeftPannelDivider.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelDivider.kt index 346e0f27d..b5c6fdb1c 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/LeftPannelDivider.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelDivider.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.view.leftpannel +package io.github.openflocon.flocondesktop.menu.ui.view.leftpannel import androidx.compose.foundation.layout.padding import androidx.compose.material3.HorizontalDivider diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/LeftPannelView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelView.kt similarity index 82% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/LeftPannelView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelView.kt index e2ba05bb8..e3e1bc46c 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/LeftPannelView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelView.kt @@ -1,6 +1,6 @@ @file:Suppress("UnusedReceiverParameter") -package io.github.openflocon.flocondesktop.main.ui.view.leftpannel +package io.github.openflocon.flocondesktop.menu.ui.view.leftpannel import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -15,15 +15,16 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.fastForEachIndexed -import io.github.openflocon.flocondesktop.main.ui.model.SubScreen -import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPanelItem -import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPanelState -import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.LeftPannelSection -import io.github.openflocon.flocondesktop.main.ui.model.leftpanel.previewLeftPannelState +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelItem +import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelState +import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPannelSection +import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.previewLeftPannelState import io.github.openflocon.library.designsystem.FloconTheme import org.jetbrains.compose.ui.tooling.preview.Preview @@ -40,9 +41,11 @@ fun LeftPanelView( ) { Column( modifier = modifier - .background(FloconTheme.colorPalette.surface) - .padding(bottom = 16.dp, top = 8.dp) - .padding(horizontal = 12.dp), + .clip(FloconTheme.shapes.medium) + .background(FloconTheme.colorPalette.primary) + .padding(8.dp) +// .padding(bottom = 16.dp, top = 8.dp) +// .padding(horizontal = 12.dp), ) { MenuSection( current = state.current, @@ -116,7 +119,7 @@ private fun LeftPanelViewPreview() { current = selectedItem.value, ), onClickItem = { - selectedItem.value = it.screen +// selectedItem.value = it.screen }, modifier = Modifier.wrapContentHeight(), expanded = false, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/PannelLabel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelLabel.kt similarity index 96% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/PannelLabel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelLabel.kt index e4fd62df2..8b6849197 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/PannelLabel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelLabel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.view.leftpannel +package io.github.openflocon.flocondesktop.menu.ui.view.leftpannel import androidx.compose.animation.Crossfade import androidx.compose.foundation.layout.Box diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/PannelView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelView.kt similarity index 95% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/PannelView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelView.kt index 38789d4f3..e683b1ead 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/leftpannel/PannelView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelView.kt @@ -1,6 +1,6 @@ @file:OptIn(ExperimentalSharedTransitionApi::class) -package io.github.openflocon.flocondesktop.main.ui.view.leftpannel +package io.github.openflocon.flocondesktop.menu.ui.view.leftpannel import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.ExperimentalSharedTransitionApi @@ -58,7 +58,7 @@ fun PanelView( ) val color by animateColorAsState( targetValue = when { - isSelected -> FloconTheme.colorPalette.primary + isSelected -> FloconTheme.colorPalette.accent hovered -> FloconTheme.colorPalette.secondary else -> FloconTheme.colorPalette.surface.copy(alpha = 0f) }, @@ -67,8 +67,8 @@ fun PanelView( val iconColor by animateColorAsState( targetValue = when { isSelected -> FloconTheme.colorPalette.onAccent - hovered -> FloconTheme.colorPalette.onSurface - else -> FloconTheme.colorPalette.onSurface + hovered -> FloconTheme.colorPalette.onSecondary + else -> FloconTheme.colorPalette.onPrimary } ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/MainScreenTopBar.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/MainScreenTopBar.kt similarity index 77% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/MainScreenTopBar.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/MainScreenTopBar.kt index e517db650..dfab7c49e 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/MainScreenTopBar.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/MainScreenTopBar.kt @@ -1,40 +1,30 @@ -package io.github.openflocon.flocondesktop.main.ui.view.topbar +package io.github.openflocon.flocondesktop.menu.ui.view.topbar import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.CameraAlt -import androidx.compose.material.icons.outlined.Stop -import androidx.compose.material.icons.outlined.Videocam import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import flocondesktop.composeapp.generated.resources.Res import flocondesktop.composeapp.generated.resources.app_icon_small -import io.github.openflocon.flocondesktop.main.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DeviceItemUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.main.ui.model.RecordVideoStateUiModel -import io.github.openflocon.flocondesktop.main.ui.view.topbar.actions.TopBarActions +import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.view.topbar.actions.TopBarActions import io.github.openflocon.library.designsystem.FloconTheme import org.jetbrains.compose.resources.painterResource diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/TopBarDeviceAndAppView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/TopBarDeviceAndAppView.kt similarity index 55% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/TopBarDeviceAndAppView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/TopBarDeviceAndAppView.kt index ce70b3d8a..6f99e4f66 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/TopBarDeviceAndAppView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/TopBarDeviceAndAppView.kt @@ -1,39 +1,22 @@ @file:OptIn(ExperimentalMaterial3Api::class) @file:Suppress("UnusedReceiverParameter") -package io.github.openflocon.flocondesktop.main.ui.view.topbar +package io.github.openflocon.flocondesktop.menu.ui.view.topbar import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.CameraAlt import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import io.github.openflocon.flocondesktop.main.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DeviceItemUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.main.ui.view.topbar.app.TopBarAppDropdown -import io.github.openflocon.flocondesktop.main.ui.view.topbar.device.TopBarDeviceDropdown -import io.github.openflocon.library.designsystem.FloconTheme +import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.view.topbar.app.TopBarAppDropdown +import io.github.openflocon.flocondesktop.menu.ui.view.topbar.device.TopBarDeviceDropdown @Composable internal fun TopBarDeviceAndAppView( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/TopBarSelector.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/TopBarSelector.kt similarity index 96% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/TopBarSelector.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/TopBarSelector.kt index f99d9b04e..5c5b6d211 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/TopBarSelector.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/TopBarSelector.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.view.topbar +package io.github.openflocon.flocondesktop.menu.ui.view.topbar import androidx.compose.foundation.Image diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/actions/TopBarActions.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/actions/TopBarActions.kt similarity index 89% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/actions/TopBarActions.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/actions/TopBarActions.kt index 9967d3059..d9f65d9e1 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/actions/TopBarActions.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/actions/TopBarActions.kt @@ -1,10 +1,9 @@ -package io.github.openflocon.flocondesktop.main.ui.view.topbar.actions +package io.github.openflocon.flocondesktop.menu.ui.view.topbar.actions import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.CameraAlt -import androidx.compose.material.icons.outlined.PlayCircle import androidx.compose.material.icons.outlined.RestartAlt import androidx.compose.material.icons.outlined.StopCircle import androidx.compose.material.icons.outlined.Videocam @@ -12,8 +11,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import io.github.openflocon.flocondesktop.main.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.main.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel @Composable internal fun TopBarActions( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/actions/TopBarButton.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/actions/TopBarButton.kt similarity index 93% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/actions/TopBarButton.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/actions/TopBarButton.kt index ef3ab8381..396208b65 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/actions/TopBarButton.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/actions/TopBarButton.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.view.topbar.actions +package io.github.openflocon.flocondesktop.menu.ui.view.topbar.actions import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/app/TopBarAppDropdown.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppDropdown.kt similarity index 91% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/app/TopBarAppDropdown.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppDropdown.kt index a3113e525..d8078e503 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/app/TopBarAppDropdown.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppDropdown.kt @@ -1,6 +1,6 @@ @file:OptIn(ExperimentalMaterial3Api::class) -package io.github.openflocon.flocondesktop.main.ui.view.topbar.app +package io.github.openflocon.flocondesktop.menu.ui.view.topbar.app import androidx.compose.foundation.clickable @@ -14,10 +14,10 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.util.fastForEach -import io.github.openflocon.flocondesktop.main.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.main.ui.view.topbar.TopBarSelector +import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.view.topbar.TopBarSelector import io.github.openflocon.library.designsystem.components.FloconExposedDropdownMenu import io.github.openflocon.library.designsystem.components.FloconExposedDropdownMenuBox diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/app/TopBarAppView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppView.kt similarity index 96% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/app/TopBarAppView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppView.kt index 237bb3a36..8368e37fd 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/app/TopBarAppView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppView.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.view.topbar.app +package io.github.openflocon.flocondesktop.menu.ui.view.topbar.app import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -31,8 +31,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import flocondesktop.composeapp.generated.resources.Res import flocondesktop.composeapp.generated.resources.smartphone -import io.github.openflocon.flocondesktop.main.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconIcon import org.jetbrains.compose.resources.painterResource diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/device/TopBarDeviceDropdown.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/device/TopBarDeviceDropdown.kt similarity index 92% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/device/TopBarDeviceDropdown.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/device/TopBarDeviceDropdown.kt index 8ad0a26c6..ea4c393f3 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/device/TopBarDeviceDropdown.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/device/TopBarDeviceDropdown.kt @@ -1,6 +1,6 @@ @file:OptIn(ExperimentalMaterial3Api::class) -package io.github.openflocon.flocondesktop.main.ui.view.topbar.device +package io.github.openflocon.flocondesktop.menu.ui.view.topbar.device import androidx.compose.foundation.layout.padding @@ -16,9 +16,9 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import io.github.openflocon.flocondesktop.main.ui.model.DeviceItemUiModel -import io.github.openflocon.flocondesktop.main.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.main.ui.view.topbar.TopBarSelector +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.view.topbar.TopBarSelector import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconCircularProgressIndicator diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/device/TopBarDeviceView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/device/TopBarDeviceView.kt similarity index 98% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/device/TopBarDeviceView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/device/TopBarDeviceView.kt index 5e2b3d10f..82b64f8de 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/view/topbar/device/TopBarDeviceView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/device/TopBarDeviceView.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.main.ui.view.topbar.device +package io.github.openflocon.flocondesktop.menu.ui.view.topbar.device import androidx.compose.desktop.ui.tooling.preview.Preview @@ -34,7 +34,7 @@ import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import io.github.openflocon.flocondesktop.main.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconIcon import io.github.openflocon.library.designsystem.components.FloconSurface diff --git a/FloconDesktop/composeApp/src/desktopMain/kotlin/io/github/openflocon/flocondesktop/Main.kt b/FloconDesktop/composeApp/src/desktopMain/kotlin/io/github/openflocon/flocondesktop/Main.kt index 7f2fd4887..37155916e 100644 --- a/FloconDesktop/composeApp/src/desktopMain/kotlin/io/github/openflocon/flocondesktop/Main.kt +++ b/FloconDesktop/composeApp/src/desktopMain/kotlin/io/github/openflocon/flocondesktop/Main.kt @@ -145,7 +145,7 @@ private fun FrameWindowScope.FloconMenu() { alwaysOnTop = true, onCloseRequest = { openLicenses = false }, ) { - io.github.openflocon.flocondesktop.main.ui.settings.AboutScreen( + io.github.openflocon.flocondesktop.menu.ui.settings.AboutScreen( modifier = Modifier .fillMaxSize() .background(FloconTheme.colorPalette.primary), diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/models/settings/NetworkSettings.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/models/settings/NetworkSettings.kt new file mode 100644 index 000000000..27cef52f3 --- /dev/null +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/models/settings/NetworkSettings.kt @@ -0,0 +1,5 @@ +package io.github.openflocon.domain.models.settings + +data class NetworkSettings( + val pinnedDetails: Boolean +) diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/settings/repository/SettingsRepository.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/settings/repository/SettingsRepository.kt index 2c59a6c1f..f20aa2a3d 100644 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/settings/repository/SettingsRepository.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/settings/repository/SettingsRepository.kt @@ -1,9 +1,13 @@ package io.github.openflocon.domain.settings.repository +import io.github.openflocon.domain.models.settings.NetworkSettings import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow interface SettingsRepository { + var networkSettings: NetworkSettings + val networkSettingsFlow: Flow + fun getAdbPath(): String? suspend fun setAdbPath(path: String) diff --git a/FloconDesktop/gradle/libs.versions.toml b/FloconDesktop/gradle/libs.versions.toml index 7d5c76753..a21437ba2 100644 --- a/FloconDesktop/gradle/libs.versions.toml +++ b/FloconDesktop/gradle/libs.versions.toml @@ -37,8 +37,9 @@ buildconfig = "5.6.8" paging = "3.3.2" # TODO Sort -nav3Core = "1.0.0+dev3004" +nav3Core = "1.0.0+dev3064" navEvent = "1.0.0-alpha09" +material3-adaptive = "1.0.0-alpha03" lifecycleViewmodelNav3 = "2.10.0-alpha04" kotlinxSerializationCore = "1.8.1" @@ -101,6 +102,8 @@ ui-tooling-preview-desktop = { module = "org.jetbrains.compose.ui:ui-tooling-pre #compose-navigation3-runtime = { module = "org.jetbrains.androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" } compose-navigation3-ui = { module = "org.jetbrains.androidx.navigation3:navigation3-ui", version.ref = "nav3Core" } +material3-adaptive = { module = "org.jetbrains.compose.material3.adaptive:adaptive-navigation3", version.ref = "material3-adaptive" } + # Optional add-on libraries androidx-lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "lifecycleViewmodelNav3" } kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinxSerializationCore" } diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt new file mode 100644 index 000000000..fa8b24241 --- /dev/null +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt @@ -0,0 +1,32 @@ +package io.github.openflocon.library.designsystem.components + +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.AnimatedContentScope +import androidx.compose.animation.AnimatedContentTransitionScope +import androidx.compose.animation.ContentTransform +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleIn +import androidx.compose.animation.togetherWith +import androidx.compose.runtime.Composable + +@Composable +fun FloconAnimateVisibility( + state: T?, + transitionSpec: AnimatedContentTransitionScope.() -> ContentTransform = { + (fadeIn(animationSpec = tween(220, delayMillis = 90)) + + scaleIn(initialScale = 0.92f, animationSpec = tween(220, delayMillis = 90))) + .togetherWith(fadeOut(animationSpec = tween(90))) + }, + content: @Composable AnimatedContentScope.(T & Any) -> Unit +) { + AnimatedContent( + targetState = state, + transitionSpec = transitionSpec + ) { + if (it != null) { + content(it) + } + } +} diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconFeature.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconFeature.kt index d1ae5aa63..ea7508ccc 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconFeature.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconFeature.kt @@ -3,6 +3,7 @@ package io.github.openflocon.library.designsystem.components import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -11,11 +12,12 @@ import androidx.compose.ui.unit.dp @Composable fun FloconFeature( modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(8.dp), // TODO Remove content: @Composable ColumnScope.() -> Unit ) { Column( verticalArrangement = Arrangement.spacedBy(8.dp), - modifier = modifier.padding(8.dp), + modifier = modifier.padding(contentPadding), content = content ) } diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconScaffold.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconScaffold.kt index b210a3218..ce91a5874 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconScaffold.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconScaffold.kt @@ -1,6 +1,9 @@ package io.github.openflocon.library.designsystem.components import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.systemBars import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -25,6 +28,7 @@ fun FloconScaffold( snackbarHost = snackbarHost, containerColor = containerColor, contentColor = contentColor, + contentWindowInsets = WindowInsets.systemBars, content = content ) } diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt index 09785f8d6..bb03191ba 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt @@ -6,16 +6,18 @@ import androidx.compose.animation.core.VectorConverter import androidx.compose.animation.core.animateTo import androidx.compose.animation.core.tween import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Close +import androidx.compose.material.icons.outlined.Pin import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -28,16 +30,16 @@ import androidx.compose.ui.unit.dp import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconIcon import io.github.openflocon.library.designsystem.components.FloconIconTonalButton -import io.github.openflocon.library.designsystem.components.escape.EscapeHandler -import io.github.openflocon.library.designsystem.components.panel.LocalFloconPanelController private const val AnimDuration = 500 private val PanelWidth = 500.dp +// TODO Rework @Composable fun FloconPanel( expanded: Boolean, onClose: (() -> Unit)? = null, + onPin: (() -> Unit)? = null, content: @Composable BoxScope.() -> Unit ) { var innerExpanded by remember { mutableStateOf(expanded) } @@ -57,6 +59,54 @@ fun FloconPanel( } } + Row( + modifier = Modifier + .fillMaxHeight() + ) { + if (onClose != null) { + Column( + verticalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier.padding(8.dp) + ) { + FloconIconTonalButton( + onClick = onClose, + modifier = Modifier + .graphicsLayer { + this.alpha = 1f - translationX.value.div(PanelWidth) + } + ) { + FloconIcon( + Icons.Outlined.Close + ) + } + if (onPin != null) { + FloconIconTonalButton( + onClick = onPin, + modifier = Modifier + .graphicsLayer { + this.alpha = 1f - translationX.value.div(PanelWidth) + } + ) { + FloconIcon( + Icons.Outlined.Pin + ) + } + } + } + } + Box( + modifier = Modifier + .width(PanelWidth) + .fillMaxHeight() + .graphicsLayer { + this.translationX = translationX.value.toPx() + } + .border(width = 1.dp, color = FloconTheme.colorPalette.surface), + content = content + ) + } +} + // val floconPanelController = LocalFloconPanelController.current // if (innerExpanded) { @@ -69,43 +119,11 @@ fun FloconPanel( // } // } // -// Row( -// modifier = Modifier -// .fillMaxHeight() -// ) { -// if (onClose != null) { -// Box( -// modifier = Modifier.padding(8.dp) -// ) { -// FloconIconTonalButton( -// onClick = onClose, -// modifier = Modifier -// .graphicsLayer { -// this.alpha = 1f - translationX.value.div(PanelWidth) -// } -// ) { -// FloconIcon( -// Icons.Outlined.Close -// ) -// } -// } -// } -// Box( -// modifier = Modifier -// .width(PanelWidth) -// .fillMaxHeight() -// .graphicsLayer { -// this.translationX = translationX.value.toPx() -// } -// .border(width = 1.dp, color = FloconTheme.colorPalette.surface), -// content = content -// ) -// } -// } + // onDispose { floconPanelController.hide() } // } // } -} +//} @Composable fun FloconPanel( diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/DI.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/DI.kt deleted file mode 100644 index e232bebc9..000000000 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/DI.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.github.openflocon.navigation - -import org.koin.dsl.module - -val navigationModule = module { - // Add qualifier ? - single { FloconNavigationState() } -} diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt index d77a2dbb9..581eefa82 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt @@ -3,58 +3,37 @@ package io.github.openflocon.navigation import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith -import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.navigation3.runtime.EntryProviderBuilder import androidx.navigation3.runtime.entryProvider import androidx.navigation3.runtime.rememberSavedStateNavEntryDecorator -import androidx.navigation3.scene.DialogSceneStrategy import androidx.navigation3.scene.SceneStrategy import androidx.navigation3.scene.SinglePaneSceneStrategy import androidx.navigation3.scene.rememberSceneSetupNavEntryDecorator import androidx.navigation3.ui.NavDisplay -import androidx.navigationevent.NavigationEventDispatcher -import androidx.navigationevent.NavigationEventDispatcherOwner -import androidx.navigationevent.compose.LocalNavigationEventDispatcherOwner -import androidx.navigationevent.compose.NavigationEventDispatcherOwner @Composable -fun FloconNavigation( - navigationState: FloconNavigationState, +fun FloconNavigation( + navigationState: FloconNavigationState, modifier: Modifier = Modifier, - sceneStrategy: SceneStrategy = SinglePaneSceneStrategy(), - builder: EntryProviderBuilder.() -> Unit + sceneStrategy: SceneStrategy = SinglePaneSceneStrategy(), + builder: EntryProviderBuilder.() -> Unit ) { - val dispatcher = remember { NavigationEventDispatcher() } - val parent = remember { - object : NavigationEventDispatcherOwner { - override val navigationEventDispatcher: NavigationEventDispatcher = dispatcher - } - } - - LocalNavigationEventDispatcherOwner.provides(parent) - - NavigationEventDispatcherOwner(parent = parent) { - NavDisplay( - backStack = navigationState.stack, - transitionSpec = { fadeIn() togetherWith fadeOut() }, - popTransitionSpec = { fadeIn() togetherWith fadeOut() }, - predictivePopTransitionSpec = { fadeIn() togetherWith fadeOut() }, - entryDecorators = listOf( - rememberSceneSetupNavEntryDecorator(), - rememberSavedStateNavEntryDecorator() - ), - sceneStrategy = sceneStrategy, - onBack = { navigationState.back(it) }, - entryProvider = entryProvider { - entry { - Box(Modifier) - } - builder() - }, - modifier = modifier - ) - } + NavDisplay( + backStack = navigationState.stack, + transitionSpec = { fadeIn() togetherWith fadeOut() }, + popTransitionSpec = { fadeIn() togetherWith fadeOut() }, + predictivePopTransitionSpec = { fadeIn() togetherWith fadeOut() }, + entryDecorators = listOf( + rememberSceneSetupNavEntryDecorator(), + rememberSavedStateNavEntryDecorator() + ), + sceneStrategy = sceneStrategy, + onBack = { navigationState.back(it) }, + entryProvider = entryProvider { + builder() + }, + modifier = modifier + ) } diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt index b6945ae47..63308611a 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt @@ -1,17 +1,26 @@ package io.github.openflocon.navigation import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.snapshots.SnapshotStateList -class FloconNavigationState internal constructor() { +interface FloconNavigationState { + val stack: SnapshotStateList - private val _stack = mutableStateListOf(LoadingRoute) - val stack: List = _stack + fun navigate(route: T) - fun navigate(route: FloconRoute) { + fun back(count: Int = 1) +} + +class MainFloconNavigationState(initialScreen: FloconRoute = LoadingRoute) : FloconNavigationState { + + private val _stack = mutableStateListOf(initialScreen) + override val stack: SnapshotStateList = _stack + + override fun navigate(route: FloconRoute) { _stack.add(route) } - fun back(count: Int = 1) { + override fun back(count: Int) { repeat(count) { _stack.removeLast() } } diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt deleted file mode 100644 index 63bdb933c..000000000 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/MenuScene.kt +++ /dev/null @@ -1,59 +0,0 @@ -package io.github.openflocon.navigation.scene - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row -import androidx.compose.runtime.Composable -import androidx.navigation3.runtime.NavEntry -import androidx.navigation3.scene.Scene -import androidx.navigation3.scene.SceneStrategy -import io.github.openflocon.navigation.FloconRoute - -class MenuScene( - override val key: String, - override val previousEntries: List>, - private val entry: NavEntry, - private val menuContent: @Composable () -> Unit, - private val expander: @Composable (() -> Unit)? = null -) : Scene { - override val entries: List> = listOf(entry) - override val content: @Composable (() -> Unit) = { - Box { - Row { - menuContent() - entry.Content() - } - expander?.invoke() - } - } - - companion object { - const val MENU_KEY = "menu" - } -} - -class MenuSceneStrategy( - private val menuContent: @Composable () -> Unit, - private val expander: @Composable (() -> Unit)? = null -) : SceneStrategy { - - @Composable - override fun calculateScene( - entries: List>, - onBack: (Int) -> Unit - ): Scene? { - val lastEntry = entries.last() - - return if (lastEntry.metadata.containsKey(MenuScene.MENU_KEY) && lastEntry.metadata[MenuScene.MENU_KEY] == true) { - MenuScene( - key = MenuScene.MENU_KEY, - previousEntries = entries.dropLast(1), - entry = lastEntry, - menuContent = menuContent, - expander = expander - ) - } else { - null - } - } - -} diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt new file mode 100644 index 000000000..e96367a76 --- /dev/null +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt @@ -0,0 +1,103 @@ +package io.github.openflocon.navigation.scene + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.navigation3.runtime.NavEntry +import androidx.navigation3.scene.OverlayScene +import androidx.navigation3.scene.Scene +import androidx.navigation3.scene.SceneStrategy +import io.github.openflocon.library.designsystem.components.panel.FloconPanel +import io.github.openflocon.navigation.FloconRoute +import org.koin.core.component.KoinComponent + +class PanelScene( + override val overlaidEntries: List>, + override val key: Any, + override val previousEntries: List>, + private val entry: NavEntry, + private val properties: PaneProperties, + private val onPin: OnPin?, + private val onBack: (count: Int) -> Unit, +) : OverlayScene, KoinComponent { + + override val entries: List> = listOf(entry) + + override val content: @Composable (() -> Unit) = { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.TopEnd + ) { + FloconPanel( + expanded = true, + onClose = { onBack(1) }, + onPin = { onPin?.onPin(); onBack(1) } + ) { + entry.Content() + } + } + } + +} + +class PanelSceneStrategy() : SceneStrategy { + + @Composable + override fun calculateScene( + entries: List>, + onBack: (Int) -> Unit + ): Scene? { + val lastEntry = entries.lastOrNull() ?: return null + val properties = lastEntry.metadata[PANEL_KEY] ?: return null + + if (properties is PaneProperties) { + return PanelScene( + key = lastEntry.contentKey, + previousEntries = entries.dropLast(1), + overlaidEntries = entries.dropLast(1), + entry = lastEntry, + properties = properties, + onPin = lastEntry.metadata[ON_PIN] as? OnPin, + onBack = onBack + ) + } + + return null + } + + companion object { + private const val PANEL_KEY = "panel_key" + private const val ON_PIN = "on_pin" + + fun panel( + pinnable: Boolean, + closable: Boolean, + onPin: OnPin = OnPin.Empty + ): Map = mapOf( + PANEL_KEY to PaneProperties( + pinnable = pinnable, + closable = closable + ), + ON_PIN to onPin + ) + + } + +} + +fun interface OnPin { + + fun onPin() + + companion object { + val Empty = OnPin {} + } + +} + +data class PaneProperties( + val pinnable: Boolean = false, + val closable: Boolean = false +) diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/WindowScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/WindowScene.kt new file mode 100644 index 000000000..9c3422cb2 --- /dev/null +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/WindowScene.kt @@ -0,0 +1,57 @@ +package io.github.openflocon.navigation.scene + +import androidx.compose.runtime.Composable +import androidx.compose.ui.window.Window +import androidx.navigation3.runtime.NavEntry +import androidx.navigation3.scene.OverlayScene +import androidx.navigation3.scene.Scene +import androidx.navigation3.scene.SceneStrategy +import io.github.openflocon.navigation.FloconRoute + +class WindowScene( + private val entry: NavEntry, + override val previousEntries: List>, + private val onBack: () -> Unit +) : OverlayScene { + + override val key: Any = entry.contentKey + override val overlaidEntries: List> = previousEntries + override val entries: List> = listOf(entry) + + override val content: @Composable (() -> Unit) = { + Window( + onCloseRequest = onBack + ) { + entry.Content() + } + } + +} + +class WindowSceneStrategy : SceneStrategy { + + @Composable + override fun calculateScene( + entries: List>, + onBack: (Int) -> Unit + ): Scene? { + val entry = entries.last() + + if (entry.metadata[IS_WINDOW] == true) { + return WindowScene( + entry = entry, + previousEntries = entries.dropLast(1), + onBack = { onBack(1) } + ) + } + + return null + } + + companion object { + private const val IS_WINDOW = "is_window" + + fun window() = mapOf(IS_WINDOW to true) + } + +} From bd67ef5619288fd164ed568110d19d810ce0acc4 Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 22 Oct 2025 12:54:09 +0200 Subject: [PATCH 10/28] feature: Clean --- .../openflocon/flocondesktop/AppWindow.kt | 28 ++++----- .../flocondesktop/menu/MenuRoutes.kt | 3 +- .../menu/ui/MenuNavigationState.kt | 2 +- .../flocondesktop/menu/ui/MenuScreen.kt | 30 +++------ .../flocondesktop/menu/ui/MenuUiState.kt | 24 +++++++ .../flocondesktop/menu/ui/MenuViewModel.kt | 63 +++++++++---------- .../flocondesktop/menu/ui/di/MainUiModule.kt | 19 +++--- .../menu/ui/model/leftpanel/MenuUiState.kt | 2 + 8 files changed, 87 insertions(+), 84 deletions(-) create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuUiState.kt diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt index 2a3267d92..15120e772 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt @@ -38,7 +38,6 @@ import io.github.openflocon.navigation.scene.PanelSceneStrategy import io.github.openflocon.navigation.scene.WindowSceneStrategy import org.koin.compose.KoinApplication import org.koin.compose.koinInject -import org.koin.compose.scope.KoinScope import org.koin.compose.viewmodel.koinViewModel import org.koin.core.module.dsl.singleOf import org.koin.dsl.bind @@ -62,9 +61,10 @@ fun App() { dataRemoteModule, // Temporary module { - scope { - scoped { MainFloconNavigationState(MainRoutes.Main) } - } +// scope { +// scoped { MainFloconNavigationState(MainRoutes.Main) } +// } + single { MainFloconNavigationState(MainRoutes.Main) } singleOf(::AdbRepositoryImpl) bind AdbRepository::class }, ) @@ -73,19 +73,19 @@ fun App() { val fontSizeMultiplier by koinInject()() .collectAsStateWithLifecycle() - KoinScope( - scopeDefinition = { createScope(MainRoutes.Sub.Main) } +// KoinScope( +// scopeDefinition = { createScope(MainRoutes.Sub.Main) } +// ) { + FloconTheme( + fontSizeMultiplier = fontSizeMultiplier ) { - FloconTheme( - fontSizeMultiplier = fontSizeMultiplier - ) { - val viewModel: AppViewModel = koinViewModel() + val viewModel: AppViewModel = koinViewModel() - Content( - navigationState = viewModel.navigationState, - ) - } + Content( + navigationState = viewModel.navigationState, + ) } +// } } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt index 2cb3744b6..b3b18297e 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt @@ -8,8 +8,6 @@ import kotlinx.serialization.Serializable import org.koin.core.Koin import org.koin.core.component.KoinScopeComponent import org.koin.core.component.createScope -import org.koin.core.qualifier.Qualifier -import org.koin.core.qualifier.QualifierValue import org.koin.core.scope.Scope internal sealed interface MainRoutes : FloconRoute { @@ -17,6 +15,7 @@ internal sealed interface MainRoutes : FloconRoute { @Serializable data object Main : MainRoutes + // For later @Serializable data class Sub( val id: String diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuNavigationState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuNavigationState.kt index 3d2b194ab..aa4e43c35 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuNavigationState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuNavigationState.kt @@ -10,7 +10,7 @@ class MenuNavigationState(initialScreen: SubScreen) : FloconNavigationState = _stack override fun navigate(route: SubScreen) { - _stack.add(route) + _stack[0] = route } override fun back(count: Int) { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt index 979f0d6e3..b000ccf85 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt @@ -44,14 +44,10 @@ import io.github.openflocon.flocondesktop.features.images.view.ImagesScreen import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen import io.github.openflocon.flocondesktop.features.sharedpreferences.view.SharedPreferencesScreen import io.github.openflocon.flocondesktop.features.table.view.TableScreen -import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelItem -import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelState import io.github.openflocon.flocondesktop.menu.ui.settings.SettingsScreen import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.LeftPanelView import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.PanelMaxWidth @@ -60,30 +56,23 @@ import io.github.openflocon.flocondesktop.menu.ui.view.topbar.MainScreenTopBar import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconIcon import io.github.openflocon.navigation.FloconNavigation -import org.koin.compose.currentKoinScope import org.koin.compose.viewmodel.koinViewModel @Composable fun MenuScreen( modifier: Modifier = Modifier ) { - val viewModel: MainViewModel = currentKoinScope().get() - val leftPanelState by viewModel.leftPanelState.collectAsStateWithLifecycle() - val devicesState by viewModel.devicesState.collectAsStateWithLifecycle() - val appsState by viewModel.appsState.collectAsStateWithLifecycle() - val recordState by viewModel.recordState.collectAsStateWithLifecycle() + val viewModel: MenuViewModel = koinViewModel() + val uiState by viewModel.uiState.collectAsStateWithLifecycle() MenuScreen( + uiState = uiState, navigationState = viewModel.menuNavigationState, modifier = modifier, - devicesState = devicesState, - appsState = appsState, - recordState = recordState, onDeviceSelected = viewModel::onDeviceSelected, deleteDevice = viewModel::deleteDevice, deleteApp = viewModel::deleteApp, onAppSelected = viewModel::onAppSelected, - leftPanelState = leftPanelState, onClickLeftPanelItem = viewModel::onClickLeftPanelItem, onTakeScreenshotClicked = viewModel::onTakeScreenshotClicked, onRecordClicked = viewModel::onRecordClicked, @@ -93,17 +82,14 @@ fun MenuScreen( @Composable private fun MenuScreen( + uiState: MenuUiState, navigationState: MenuNavigationState, - leftPanelState: LeftPanelState, onClickLeftPanelItem: (LeftPanelItem) -> Unit, - devicesState: DevicesStateUiModel, - appsState: AppsStateUiModel, onDeviceSelected: (DeviceItemUiModel) -> Unit, deleteDevice: (DeviceItemUiModel) -> Unit, onAppSelected: (DeviceAppUiModel) -> Unit, deleteApp: (DeviceAppUiModel) -> Unit, onTakeScreenshotClicked: () -> Unit, - recordState: RecordVideoStateUiModel, onRecordClicked: () -> Unit, onRestartClicked: () -> Unit, modifier: Modifier = Modifier, @@ -120,9 +106,9 @@ private fun MenuScreen( modifier = modifier.fillMaxSize() ) { MainScreenTopBar( - appsState = appsState, - devicesState = devicesState, - recordState = recordState, + appsState = uiState.appsStateUiModel, + devicesState = uiState.devicesStateUiModel, + recordState = uiState.recordVideoState, deleteApp = deleteApp, deleteDevice = deleteDevice, onAppSelected = onAppSelected, @@ -142,7 +128,7 @@ private fun MenuScreen( .fillMaxHeight(), expanded = expanded, onClickItem = onClickLeftPanelItem, - state = leftPanelState, + state = uiState.leftPanelState, ) Spacer(Modifier.width(8.dp)) FloconNavigation( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuUiState.kt new file mode 100644 index 000000000..69e1d6c0c --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuUiState.kt @@ -0,0 +1,24 @@ +package io.github.openflocon.flocondesktop.menu.ui + +import androidx.compose.runtime.Immutable +import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelState +import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.previewLeftPannelState + +@Immutable +data class MenuUiState( + val leftPanelState: LeftPanelState, + val recordVideoState: RecordVideoStateUiModel, + val appsStateUiModel: AppsStateUiModel, + val devicesStateUiModel: DevicesStateUiModel +) + +fun previewMenuUiState() = MenuUiState( + leftPanelState = previewLeftPannelState(SubScreen.Network), + recordVideoState = RecordVideoStateUiModel.Idle, + appsStateUiModel = AppsStateUiModel.Empty, + devicesStateUiModel = DevicesStateUiModel.Empty +) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuViewModel.kt index a5698cfa5..dbc536f90 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuViewModel.kt @@ -10,13 +10,11 @@ import io.github.openflocon.domain.device.usecase.RestartAppUseCase import io.github.openflocon.domain.device.usecase.TakeScreenshotUseCase import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.app.InitialSetupStateHolder +import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed import io.github.openflocon.flocondesktop.menu.ui.delegates.DevicesDelegate import io.github.openflocon.flocondesktop.menu.ui.delegates.RecordVideoDelegate -import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelItem import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelState @@ -25,17 +23,12 @@ import io.github.openflocon.flocondesktop.menu.ui.view.displayName import io.github.openflocon.flocondesktop.menu.ui.view.icon import io.github.openflocon.navigation.MainFloconNavigationState import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import org.koin.core.component.KoinComponent -class MainViewModel( +class MenuViewModel( private val devicesDelegate: DevicesDelegate, private val dispatcherProvider: DispatcherProvider, private val initialSetupStateHolder: InitialSetupStateHolder, @@ -50,40 +43,41 @@ class MainViewModel( recordVideoDelegate, ), KoinComponent { - // TODO Remove - val subScreen = MutableStateFlow(SubScreen.Network) - - val recordState: StateFlow = recordVideoDelegate.state + private val leftPanelState = MutableStateFlow(buildLeftPanelState(current = SubScreen.Network)) + + val uiState = combine( + leftPanelState, + recordVideoDelegate.state, + devicesDelegate.devicesState, + devicesDelegate.appsState + ) { content, record, device, apps -> + MenuUiState( + leftPanelState = content, + recordVideoState = record, + appsStateUiModel = apps, + devicesStateUiModel = device + ) + } + .stateInWhileSubscribed( + MenuUiState( + leftPanelState = leftPanelState.value, + recordVideoState = recordVideoDelegate.state.value, + devicesStateUiModel = devicesDelegate.devicesState.value, + appsStateUiModel = devicesDelegate.appsState.value + ) + ) init { viewModelScope.launch(dispatcherProvider.viewModel) { initialSetupStateHolder.needsAdbSetup.collect { if (it) { - subScreen.update { SubScreen.Settings } + menuNavigationState.navigate(SubScreen.Settings) + leftPanelState.update { state -> state.copy(current = SubScreen.Settings) } } } } } - val leftPanelState = combines( - subScreen, - observeCurrentDeviceCapabilitiesUseCase(), - ).map { (subScreen, capabilities) -> - buildLeftPanelState( - current = subScreen, - ) - } - .flowOn(dispatcherProvider.ui) - .stateIn( - scope = viewModelScope, - started = SharingStarted.Eagerly, - initialValue = buildLeftPanelState(subScreen.value), - ) - - val devicesState: StateFlow = devicesDelegate.devicesState - val appsState: StateFlow = devicesDelegate.appsState - - fun onDeviceSelected(device: DeviceItemUiModel) { viewModelScope.launch(dispatcherProvider.viewModel) { devicesDelegate.select(device.id) @@ -109,12 +103,11 @@ class MainViewModel( } fun onClickLeftPanelItem(leftPanelItem: LeftPanelItem) { + leftPanelState.update { state -> state.copy(current = leftPanelItem.screen) } menuNavigationState.navigate(leftPanelItem.screen) } fun onRecordClicked() { - // TODO Needs scoped vm -// mainNavigationState.navigate(MenuRoutes.App("zfjzhefoezf")) viewModelScope.launch(dispatcherProvider.viewModel) { recordVideoDelegate.toggleRecording() } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/di/MainUiModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/di/MainUiModule.kt index b0ac8e21c..93e4d9a6e 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/di/MainUiModule.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/di/MainUiModule.kt @@ -1,8 +1,7 @@ package io.github.openflocon.flocondesktop.menu.ui.di import io.github.openflocon.flocondesktop.features.network.detail.NetworkDetailViewModel -import io.github.openflocon.flocondesktop.menu.MainRoutes -import io.github.openflocon.flocondesktop.menu.ui.MainViewModel +import io.github.openflocon.flocondesktop.menu.ui.MenuViewModel import io.github.openflocon.flocondesktop.menu.ui.MenuNavigationState import io.github.openflocon.flocondesktop.menu.ui.delegates.DevicesDelegate import io.github.openflocon.flocondesktop.menu.ui.delegates.RecordVideoDelegate @@ -13,13 +12,13 @@ import org.koin.core.module.dsl.viewModelOf import org.koin.dsl.module val mainUiModule = module { - scope { - scoped { MenuNavigationState(SubScreen.Network) } - viewModelOf(::MainViewModel) - factoryOf(::DevicesDelegate) - factoryOf(::RecordVideoDelegate) - viewModelOf(::SettingsViewModel) +// scope { + single { MenuNavigationState(SubScreen.Network) } + viewModelOf(::MenuViewModel) + factoryOf(::DevicesDelegate) + factoryOf(::RecordVideoDelegate) + viewModelOf(::SettingsViewModel) - viewModelOf(::NetworkDetailViewModel) - } + viewModelOf(::NetworkDetailViewModel) +// } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/MenuUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/MenuUiState.kt index 9eb6ac25f..0b5163bb3 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/MenuUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/MenuUiState.kt @@ -3,8 +3,10 @@ package io.github.openflocon.flocondesktop.menu.ui.model.leftpanel import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Analytics import androidx.compose.material.icons.outlined.Settings +import androidx.compose.runtime.Immutable import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +@Immutable data class LeftPanelState( val current: SubScreen, val sections: List, From 2bb67a94e8d1f957537cfc889273c881632e4603 Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 22 Oct 2025 13:26:03 +0200 Subject: [PATCH 11/28] feature: Rework flocon panel --- .../database/view/DatabaseResultView.kt | 8 +- .../network/list/view/NetworkScreen.kt | 7 +- .../components/FloconAnimateVisibility.kt | 12 +- .../components/FloconIconButton.kt | 2 + .../components/panel/FloconPanel.kt | 200 +++++++++++------- .../openflocon/navigation/scene/PanelScene.kt | 44 +++- 6 files changed, 186 insertions(+), 87 deletions(-) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/view/DatabaseResultView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/view/DatabaseResultView.kt index e6e903d56..28df12e0f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/view/DatabaseResultView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/view/DatabaseResultView.kt @@ -20,13 +20,7 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.CallMade import androidx.compose.material.icons.automirrored.outlined.DriveFileMove -import androidx.compose.material.icons.filled.FileUpload -import androidx.compose.material.icons.outlined.Download -import androidx.compose.material.icons.outlined.ImportExport -import androidx.compose.material.icons.outlined.Save -import androidx.compose.material.icons.outlined.SaveAs import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -200,7 +194,7 @@ fun DatabaseResultView( } ) { DatabaseRowDetailView( - modifier = Modifier.matchParentSize(), + modifier = Modifier.fillMaxSize(), state = it, columns = result.columns, ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt index 26f55640d..e1d5c17ce 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt @@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState @@ -80,6 +79,7 @@ import io.github.openflocon.library.designsystem.components.FloconIconTonalButto import io.github.openflocon.library.designsystem.components.FloconOverflow import io.github.openflocon.library.designsystem.components.FloconPageTopBar import io.github.openflocon.library.designsystem.components.FloconVerticalScrollbar +import io.github.openflocon.library.designsystem.components.panel.PanelWidth import io.github.openflocon.library.designsystem.components.rememberFloconScrollbarAdapter import kotlinx.coroutines.flow.MutableStateFlow import org.koin.compose.viewmodel.koinViewModel @@ -323,7 +323,8 @@ fun NetworkScreen( } } FloconAnimateVisibility( - uiState.detailState + state = uiState.detailState, + modifier = Modifier.fillMaxHeight() ) { Row { Spacer(Modifier.width(8.dp)) @@ -331,7 +332,7 @@ fun NetworkScreen( uiState = it, onAction = onAction, modifier = Modifier - .width(300.dp) // TODO Change, settings ? + .width(PanelWidth) .clip(FloconTheme.shapes.medium) ) } diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt index fa8b24241..d82ad5857 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt @@ -7,23 +7,29 @@ import androidx.compose.animation.ContentTransform import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.animation.scaleIn import androidx.compose.animation.togetherWith import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier @Composable fun FloconAnimateVisibility( state: T?, + modifier: Modifier = Modifier, transitionSpec: AnimatedContentTransitionScope.() -> ContentTransform = { (fadeIn(animationSpec = tween(220, delayMillis = 90)) + - scaleIn(initialScale = 0.92f, animationSpec = tween(220, delayMillis = 90))) + slideIntoContainer( + towards = AnimatedContentTransitionScope.SlideDirection.Start, + animationSpec = tween(220, delayMillis = 90) + ) + ) .togetherWith(fadeOut(animationSpec = tween(90))) }, content: @Composable AnimatedContentScope.(T & Any) -> Unit ) { AnimatedContent( targetState = state, - transitionSpec = transitionSpec + transitionSpec = transitionSpec, + modifier = modifier ) { if (it != null) { content(it) diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconIconButton.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconIconButton.kt index 3b4ddcb5a..943b02e7b 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconIconButton.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconIconButton.kt @@ -16,6 +16,8 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.selection.toggleable +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Close import androidx.compose.material3.LocalContentColor import androidx.compose.material3.Text import androidx.compose.runtime.Composable diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt index bb03191ba..061aa1993 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt @@ -8,7 +8,6 @@ import androidx.compose.animation.core.tween import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight @@ -16,12 +15,13 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Close -import androidx.compose.material.icons.outlined.Pin import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer @@ -30,106 +30,152 @@ import androidx.compose.ui.unit.dp import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconIcon import io.github.openflocon.library.designsystem.components.FloconIconTonalButton +import io.github.openflocon.library.designsystem.components.escape.EscapeHandler +import kotlinx.coroutines.launch private const val AnimDuration = 500 -private val PanelWidth = 500.dp +val PanelWidth = 500.dp + +@Stable +class FloconPanelState internal constructor(initialValue: Boolean) { + + internal var expanded by mutableStateOf(initialValue) + + val translationX = AnimationState(typeConverter = Dp.VectorConverter, PanelWidth) + + suspend fun show() { + expanded = true + translationX.animateTo(0.dp, animationSpec = tween(AnimDuration, easing = EaseOutExpo)) + } + + suspend fun hide() { + translationX.animateTo(PanelWidth, animationSpec = tween(AnimDuration, easing = EaseOutExpo)) + expanded = false + } + +} + +@Composable +fun rememberFloconPanelState(initialValue: Boolean = false): FloconPanelState { + return remember { FloconPanelState(initialValue) } +} + + +interface FloconPanelScope { + val state: FloconPanelState + + fun Modifier.animatePanelAction(): Modifier + +} + +private class FloconPanelScopeImpl( + override val state: FloconPanelState +) : FloconPanelScope { + + @Stable + override fun Modifier.animatePanelAction(): Modifier = graphicsLayer { + this.alpha = 1f - state.translationX.value.div(PanelWidth) + } + +} + -// TODO Rework @Composable fun FloconPanel( - expanded: Boolean, - onClose: (() -> Unit)? = null, - onPin: (() -> Unit)? = null, - content: @Composable BoxScope.() -> Unit + state: FloconPanelState, + onDismissRequest: () -> Unit, + actions: @Composable FloconPanelScope.() -> Unit = {}, + content: @Composable FloconPanelScope.() -> Unit ) { - var innerExpanded by remember { mutableStateOf(expanded) } - val translationX = remember { AnimationState(typeConverter = Dp.VectorConverter, PanelWidth) } + val scope = remember(state) { FloconPanelScopeImpl(state) } + val coroutineScope = rememberCoroutineScope() - suspend fun hide() { - translationX.animateTo(PanelWidth, animationSpec = tween(AnimDuration, easing = EaseOutExpo)) - innerExpanded = false + LaunchedEffect(Unit) { + if (state.expanded) { + state.show() + } } - LaunchedEffect(expanded) { - if (expanded) { - innerExpanded = true - translationX.animateTo(0.dp, animationSpec = tween(AnimDuration, easing = EaseOutExpo)) - } else { - hide() + LaunchedEffect(state.expanded) { + if (!state.expanded) { + onDismissRequest() } } + EscapeHandler { + coroutineScope.launch { + state.hide() + onDismissRequest() + } + true + } + Row( modifier = Modifier .fillMaxHeight() ) { - if (onClose != null) { - Column( - verticalArrangement = Arrangement.spacedBy(8.dp), - modifier = Modifier.padding(8.dp) - ) { - FloconIconTonalButton( - onClick = onClose, - modifier = Modifier - .graphicsLayer { - this.alpha = 1f - translationX.value.div(PanelWidth) - } - ) { - FloconIcon( - Icons.Outlined.Close - ) - } - if (onPin != null) { - FloconIconTonalButton( - onClick = onPin, - modifier = Modifier - .graphicsLayer { - this.alpha = 1f - translationX.value.div(PanelWidth) - } - ) { - FloconIcon( - Icons.Outlined.Pin - ) - } - } - } - } + Column( + verticalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier.padding(8.dp), + content = { scope.actions() } + ) Box( modifier = Modifier .width(PanelWidth) .fillMaxHeight() .graphicsLayer { - this.translationX = translationX.value.toPx() + this.translationX = state.translationX.value.toPx() } - .border(width = 1.dp, color = FloconTheme.colorPalette.surface), - content = content - ) + .border(width = 1.dp, color = FloconTheme.colorPalette.surface) + ) { + scope.content() + } } } -// val floconPanelController = LocalFloconPanelController.current +// TODO Rework +@Composable +fun FloconPanel( + expanded: Boolean, + onDismissRequest: () -> Unit, + actions: @Composable FloconPanelScope.() -> Unit = {}, + content: @Composable FloconPanelScope.() -> Unit +) { + var innerExpand by remember { mutableStateOf(expanded) } + val state = rememberFloconPanelState(expanded) + val scope = rememberCoroutineScope() -// if (innerExpanded) { -// DisposableEffect(Unit) { -// floconPanelController.display { -// if (onClose != null) { -// EscapeHandler { -// onClose() -// true -// } -// } -// + LaunchedEffect(expanded) { + if (expanded) { + innerExpand = true + state.show() + } else { + state.hide() + innerExpand = false + } + } -// onDispose { floconPanelController.hide() } -// } -// } -//} + if (innerExpand) { + FloconPanel( + state = state, + onDismissRequest = { + scope.launch { + state.hide() + innerExpand = false + onDismissRequest() + } + }, + actions = actions, + content = content + ) + } +} @Composable fun FloconPanel( contentState: T, onClose: (() -> Unit)? = null, - content: @Composable BoxScope.(T & Any) -> Unit + content: @Composable FloconPanelScope.(T & Any) -> Unit ) { var rememberTarget by remember { mutableStateOf(contentState) } @@ -141,7 +187,19 @@ fun FloconPanel( FloconPanel( expanded = contentState != null, - onClose = onClose, + onDismissRequest = { onClose?.invoke() }, + actions = { + if (onClose != null) { + FloconIconTonalButton( + onClick = onClose, + modifier = Modifier + ) { + FloconIcon( + Icons.Outlined.Close + ) + } + } + }, ) { rememberTarget?.let { content(this, it) } } diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt index e96367a76..60ef31849 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt @@ -2,15 +2,23 @@ package io.github.openflocon.navigation.scene import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Close +import androidx.compose.material.icons.outlined.Pin import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.navigation3.runtime.NavEntry import androidx.navigation3.scene.OverlayScene import androidx.navigation3.scene.Scene import androidx.navigation3.scene.SceneStrategy +import io.github.openflocon.library.designsystem.components.FloconIcon +import io.github.openflocon.library.designsystem.components.FloconIconTonalButton import io.github.openflocon.library.designsystem.components.panel.FloconPanel +import io.github.openflocon.library.designsystem.components.panel.rememberFloconPanelState import io.github.openflocon.navigation.FloconRoute +import kotlinx.coroutines.launch import org.koin.core.component.KoinComponent class PanelScene( @@ -26,14 +34,44 @@ class PanelScene( override val entries: List> = listOf(entry) override val content: @Composable (() -> Unit) = { + val state = rememberFloconPanelState(initialValue = true) + val scope = rememberCoroutineScope() + Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.TopEnd ) { FloconPanel( - expanded = true, - onClose = { onBack(1) }, - onPin = { onPin?.onPin(); onBack(1) } + state = state, + onDismissRequest = { onBack(1) }, + actions = { + FloconIconTonalButton( + onClick = { onBack(1) }, + modifier = Modifier + .animatePanelAction() + ) { + FloconIcon( + Icons.Outlined.Close + ) + } + if (onPin != null) { + FloconIconTonalButton( + onClick = { + scope.launch { + onPin.onPin() + state.hide() + onBack(1) + } + }, + modifier = Modifier + .animatePanelAction() + ) { + FloconIcon( + Icons.Outlined.Pin + ) + } + } + } ) { entry.Content() } From 2ec37775761c2713ae37d79f95ee04483174cb5a Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Fri, 24 Oct 2025 16:29:50 +0200 Subject: [PATCH 12/28] feature: Rework --- .../flocondesktop/core/data/settings/DI.kt | 2 + .../usecase/SaveNetworkSettingsUseCase.kt | 15 +++ .../features/analytics/Navigation.kt | 4 +- .../deeplinks/view/DeeplinkItemView.kt | 2 +- .../features/network/Navigation.kt | 4 +- .../network/body/model/ContentUiState.kt | 7 +- .../view/components/DetailHeadersView.kt | 1 + .../features/network/list/NetworkViewModel.kt | 25 +++- .../network/list/model/NetworkAction.kt | 4 +- .../network/list/view/NetworkScreen.kt | 35 ++---- .../flocondesktop/menu/MenuRoutes.kt | 4 +- .../flocondesktop/menu/ui/MenuScreen.kt | 114 +++++++++--------- .../menu/ui/settings/Navigation.kt | 6 +- .../menu/ui/view/leftpannel/LeftPannelView.kt | 9 +- .../menu/ui/view/leftpannel/PannelView.kt | 16 +-- FloconDesktop/gradle/libs.versions.toml | 10 +- .../components/FloconAnimateVisibility.kt | 13 +- .../designsystem/components/FloconOverflow.kt | 9 +- FloconDesktop/navigation/build.gradle.kts | 2 + .../openflocon/navigation/FloconNavigation.kt | 14 +-- .../openflocon/navigation/scene/PanelScene.kt | 28 +++-- .../navigation/scene/WindowScene.kt | 13 +- 22 files changed, 184 insertions(+), 153 deletions(-) create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/usecase/SaveNetworkSettingsUseCase.kt diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/DI.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/DI.kt index d44084a7f..0a0122555 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/DI.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/DI.kt @@ -1,9 +1,11 @@ package io.github.openflocon.flocondesktop.core.data.settings import io.github.openflocon.flocondesktop.core.data.settings.usecase.ObserveNetworkSettingsUseCase +import io.github.openflocon.flocondesktop.core.data.settings.usecase.SaveNetworkSettingsUseCase import org.koin.core.module.dsl.factoryOf import org.koin.dsl.module internal val settingsModule = module { factoryOf(::ObserveNetworkSettingsUseCase) + factoryOf(::SaveNetworkSettingsUseCase) } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/usecase/SaveNetworkSettingsUseCase.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/usecase/SaveNetworkSettingsUseCase.kt new file mode 100644 index 000000000..c220e9e2c --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/usecase/SaveNetworkSettingsUseCase.kt @@ -0,0 +1,15 @@ +package io.github.openflocon.flocondesktop.core.data.settings.usecase + +import io.github.openflocon.domain.models.settings.NetworkSettings +import io.github.openflocon.domain.settings.repository.SettingsRepository + +class SaveNetworkSettingsUseCase( + private val settingsRepository: SettingsRepository +) { + operator fun invoke( + settings: NetworkSettings + ): Result = runCatching { + settingsRepository.networkSettings = settings + } + +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt index 0736c2dbc..3d5d34f18 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt @@ -1,8 +1,8 @@ package io.github.openflocon.flocondesktop.features.analytics -import androidx.navigation3.runtime.EntryProviderBuilder +import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.navigation.FloconRoute -fun EntryProviderBuilder.analyticsRoutes() { +fun EntryProviderScope.analyticsRoutes() { // TODO } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/view/DeeplinkItemView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/view/DeeplinkItemView.kt index 96c998a02..6b382cc34 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/view/DeeplinkItemView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/view/DeeplinkItemView.kt @@ -17,8 +17,8 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.Send import androidx.compose.material.icons.filled.Delete import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExposedDropdownMenuAnchorType.Companion.PrimaryEditable import androidx.compose.material3.ExposedDropdownMenuBox -import androidx.compose.material3.MenuAnchorType.Companion.PrimaryEditable import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt index 2468a027f..0b29483bf 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt @@ -1,6 +1,6 @@ package io.github.openflocon.flocondesktop.features.network -import androidx.navigation3.runtime.EntryProviderBuilder +import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.domain.settings.repository.SettingsRepository import io.github.openflocon.flocondesktop.features.network.detail.view.NetworkDetailScreen import io.github.openflocon.navigation.FloconRoute @@ -15,7 +15,7 @@ internal sealed interface NetworkRoutes : FloconRoute { } -fun EntryProviderBuilder.networkRoutes() { +fun EntryProviderScope.networkRoutes() { entry( metadata = PanelSceneStrategy.panel( pinnable = true, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/body/model/ContentUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/body/model/ContentUiState.kt index 0f1fcbd68..05edc682a 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/body/model/ContentUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/body/model/ContentUiState.kt @@ -11,6 +11,9 @@ data class ContentUiState( val mocksDisplayed: MockDisplayed?, val websocketMocksDisplayed: Boolean, val badNetworkQualityDisplayed: Boolean, + val invertList: Boolean, + val autoScroll: Boolean, + val pinPanel: Boolean ) @Immutable @@ -24,5 +27,7 @@ fun previewContentUiState() = ContentUiState( detailJsons = emptySet(), mocksDisplayed = null, badNetworkQualityDisplayed = false, - websocketMocksDisplayed = false, + invertList = false, + autoScroll = false, + pinPanel = false ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/components/DetailHeadersView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/components/DetailHeadersView.kt index 884a7a0be..d618d4c3b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/components/DetailHeadersView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/components/DetailHeadersView.kt @@ -64,6 +64,7 @@ fun DetailHeadersView( label = item.name, value = item.value, labelWidth = labelWidth, + contentColor = FloconTheme.colorPalette.onPrimary, modifier = Modifier.fillMaxWidth() ) } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt index f1ada2c3f..5cb4e682c 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt @@ -13,6 +13,7 @@ import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.common.combines import io.github.openflocon.domain.device.usecase.ObserveCurrentDeviceIdAndPackageNameUseCase import io.github.openflocon.domain.feedback.FeedbackDisplayer +import io.github.openflocon.domain.models.settings.NetworkSettings import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel import io.github.openflocon.domain.network.models.MockNetworkDomainModel import io.github.openflocon.domain.network.models.NetworkFilterDomainModel @@ -33,6 +34,7 @@ import io.github.openflocon.domain.network.usecase.badquality.ObserveAllNetworkB import io.github.openflocon.domain.network.usecase.mocks.ObserveNetworkMocksUseCase import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed import io.github.openflocon.flocondesktop.core.data.settings.usecase.ObserveNetworkSettingsUseCase +import io.github.openflocon.flocondesktop.core.data.settings.usecase.SaveNetworkSettingsUseCase import io.github.openflocon.flocondesktop.features.network.NetworkRoutes import io.github.openflocon.domain.network.usecase.mocks.ObserveNetworkWebsocketIdsUseCase import io.github.openflocon.domain.network.usecase.settings.ObserveNetworkSettingsUseCase @@ -93,6 +95,8 @@ class NetworkViewModel( private val updateNetworkSettingsUseCase: UpdateNetworkSettingsUseCase, private val observeNetworkWebsocketIdsUseCase: ObserveNetworkWebsocketIdsUseCase, private val openBodyDelegate: OpenBodyDelegate, + private val observeNetworkSettingsUseCase: ObserveNetworkSettingsUseCase, + private val saveNetworkSettingsUseCase: SaveNetworkSettingsUseCase ) : ViewModel(headerDelegate) { private val contentState = MutableStateFlow( @@ -146,6 +150,9 @@ class NetworkViewModel( ) ) + private val settings = observeNetworkSettingsUseCase() + .stateInWhileSubscribed(NetworkSettings(pinnedDetails = false)) + private val filter = combines( snapshotFlow { _filterText.value }.map { it.takeIf { it.isNotBlank() } } .distinctUntilChanged(), @@ -191,7 +198,7 @@ class NetworkViewModel( private val detailState = combine( detailDelegate.uiState, contentState, - observeNetworkSettingsUseCase() + settings ) { state, content, settings -> state.takeIf { settings.pinnedDetails && content.selectedRequestId != null } } @@ -205,7 +212,9 @@ class NetworkViewModel( settings.map { it.toUi() }, ) { content, detail, filter, header, settings -> NetworkUiState( - contentState = content, + contentState = content.copy( + pinPanel = settings.pinnedDetails + ), detailState = detail, filterState = filter, headerState = header, @@ -217,7 +226,7 @@ class NetworkViewModel( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), initialValue = NetworkUiState( - detailState = detailDelegate.uiState.value, + detailState = detailState.value, contentState = contentState.value, filterState = filterUiState.value, headerState = headerDelegate.headerUiState.value, @@ -270,6 +279,16 @@ class NetworkViewModel( } } + private fun onPinned(action: NetworkAction.Pinned) { + viewModelScope.launch { + saveNetworkSettingsUseCase( + settings.value.copy( + pinnedDetails = action.value + ) + ) + } + } + private fun onClearSession() { viewModelScope.launch(dispatcherProvider.viewModel) { removeOldSessionsNetworkRequestUseCase() diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkAction.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkAction.kt index b76b2ece2..53ae0a6d9 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkAction.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkAction.kt @@ -46,7 +46,9 @@ sealed interface NetworkAction { data class InvertList(val value: Boolean) : NetworkAction - data class ToggleAutoScroll(val value: Boolean) : NetworkAction + data class Pinned(val value: Boolean) : NetworkAction + + data object ToggleAutoScroll : NetworkAction data object ClearOldSession : NetworkAction diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt index e1d5c17ce..d63cf1a1f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt @@ -1,6 +1,5 @@ package io.github.openflocon.flocondesktop.features.network.list.view -import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box @@ -21,11 +20,11 @@ import androidx.compose.material.icons.outlined.CleaningServices import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.History import androidx.compose.material.icons.outlined.ImportExport -import androidx.compose.material.icons.outlined.PinEnd import androidx.compose.material.icons.outlined.PlayCircle import androidx.compose.material.icons.outlined.Podcasts import androidx.compose.material.icons.outlined.SignalWifiStatusbarConnectedNoInternet4 import androidx.compose.material.icons.outlined.WifiTethering +import androidx.compose.material.icons.sharp.PushPin import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State @@ -33,7 +32,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.input.key.Key @@ -41,13 +39,13 @@ import androidx.compose.ui.input.key.KeyEventType import androidx.compose.ui.input.key.key import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.input.key.type +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.paging.PagingData import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.itemKey -import io.github.openflocon.domain.settings.repository.SettingsRepository import io.github.openflocon.flocondesktop.common.ui.window.FloconWindowState import io.github.openflocon.flocondesktop.common.ui.window.createFloconWindowState import io.github.openflocon.flocondesktop.features.network.badquality.list.view.BadNetworkQualityWindow @@ -75,7 +73,6 @@ import io.github.openflocon.library.designsystem.components.FloconHorizontalDivi import io.github.openflocon.library.designsystem.components.FloconIcon import io.github.openflocon.library.designsystem.components.FloconIconButton import io.github.openflocon.library.designsystem.components.FloconIconToggleButton -import io.github.openflocon.library.designsystem.components.FloconIconTonalButton import io.github.openflocon.library.designsystem.components.FloconOverflow import io.github.openflocon.library.designsystem.components.FloconPageTopBar import io.github.openflocon.library.designsystem.components.FloconVerticalScrollbar @@ -83,7 +80,6 @@ import io.github.openflocon.library.designsystem.components.panel.PanelWidth import io.github.openflocon.library.designsystem.components.rememberFloconScrollbarAdapter import kotlinx.coroutines.flow.MutableStateFlow import org.koin.compose.viewmodel.koinViewModel -import org.koin.mp.KoinPlatform @Composable fun NetworkScreen( @@ -254,7 +250,13 @@ fun NetworkScreen( checked = uiState.contentState.invertList, text = "Invert list", leadingIcon = Icons.AutoMirrored.Outlined.List, - onCheckedChange = { onAction(NetworkAction.InvertList(it)) } + onCheckedChange = { checked -> onAction(NetworkAction.InvertList(checked)) } + ) + FloconDropdownMenuItem( + checked = uiState.contentState.pinPanel, + text = "Pin panel", + leadingIcon = Icons.Sharp.PushPin, + onCheckedChange = { checked -> onAction(NetworkAction.Pinned(checked)); it() } ) FloconDropdownSeparator() FloconDropdownMenuItem( @@ -339,25 +341,6 @@ fun NetworkScreen( } } - // TODO Change - Box( - contentAlignment = Alignment.TopEnd, - modifier = Modifier.fillMaxSize() - ) { - FloconIconTonalButton( - onClick = { - val repository = KoinPlatform.getKoin().get() - - repository.networkSettings = repository.networkSettings.copy(pinnedDetails = false) - }, - modifier = Modifier.align(Alignment.BottomStart) - ) { - FloconIcon( - Icons.Outlined.PinEnd - ) - } - } - val states = remember { mutableStateMapOf() } LaunchedEffect(uiState.contentState.detailJsons) { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt index b3b18297e..beab06a87 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt @@ -1,6 +1,6 @@ package io.github.openflocon.flocondesktop.menu -import androidx.navigation3.runtime.EntryProviderBuilder +import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.flocondesktop.menu.ui.MenuScreen import io.github.openflocon.navigation.FloconRoute import io.github.openflocon.navigation.scene.WindowSceneStrategy @@ -32,7 +32,7 @@ internal sealed interface MainRoutes : FloconRoute { internal fun Koin.createFloconScope(sub: MainRoutes.Sub) = createScope(sub) -fun EntryProviderBuilder.menuRoutes() { +fun EntryProviderScope.menuRoutes() { entry { MenuScreen() } // TODO Scope VM on this entry(metadata = WindowSceneStrategy.window()) { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt index b000ccf85..24e43454b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt @@ -34,7 +34,7 @@ import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation3.runtime.EntryProviderBuilder +import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.flocondesktop.features.analytics.view.AnalyticsScreen import io.github.openflocon.flocondesktop.features.dashboard.view.DashboardScreen import io.github.openflocon.flocondesktop.features.database.view.DatabaseScreen @@ -102,70 +102,76 @@ private fun MenuScreen( ) val rotate by animateFloatAsState(targetValue = if (expanded) 180f else 0f) - Column( - modifier = modifier.fillMaxSize() + Box( + modifier = Modifier + .fillMaxSize() + .onGloballyPositioned { + windowSize = it.size // TODO Add windowsize lib + } ) { - MainScreenTopBar( - appsState = uiState.appsStateUiModel, - devicesState = uiState.devicesStateUiModel, - recordState = uiState.recordVideoState, - deleteApp = deleteApp, - deleteDevice = deleteDevice, - onAppSelected = onAppSelected, - onRecordClicked = onRecordClicked, - onRestartClicked = onRestartClicked, - onDeviceSelected = onDeviceSelected, - onTakeScreenshotClicked = onTakeScreenshotClicked - ) - Row( - modifier = Modifier - .fillMaxSize() - .padding(8.dp) + Column( + modifier = modifier + .matchParentSize() ) { - LeftPanelView( - modifier = Modifier - .width(width) - .fillMaxHeight(), - expanded = expanded, - onClickItem = onClickLeftPanelItem, - state = uiState.leftPanelState, + MainScreenTopBar( + appsState = uiState.appsStateUiModel, + devicesState = uiState.devicesStateUiModel, + recordState = uiState.recordVideoState, + deleteApp = deleteApp, + deleteDevice = deleteDevice, + onAppSelected = onAppSelected, + onRecordClicked = onRecordClicked, + onRestartClicked = onRestartClicked, + onDeviceSelected = onDeviceSelected, + onTakeScreenshotClicked = onTakeScreenshotClicked ) - Spacer(Modifier.width(8.dp)) - FloconNavigation( - navigationState = navigationState, - modifier = Modifier - .weight(1f) - .fillMaxHeight() - .onGloballyPositioned { - windowSize = it.size // TODO Add windowsize lib - }, - ) { - menus() - } - Box( - contentAlignment = Alignment.Center, + Row( modifier = Modifier - .width(20.dp) - .height(60.dp) - .graphicsLayer { - translationX = position.toPx() - size.width / 2 - 8.dp.toPx() - translationY = (windowSize.height / 2) - (size.height / 2) - } - .clip(RoundedCornerShape(4.dp)) - .background(FloconTheme.colorPalette.primary) - .clickable(onClick = { expanded = !expanded }), + .fillMaxSize() + .padding(8.dp) ) { - FloconIcon( - imageVector = Icons.Outlined.ChevronRight, - tint = Color.LightGray, - modifier = Modifier.rotate(rotate), + LeftPanelView( + modifier = Modifier + .width(width) + .fillMaxHeight(), + expanded = expanded, + onClickItem = onClickLeftPanelItem, + state = uiState.leftPanelState, ) + Spacer(Modifier.width(8.dp)) + FloconNavigation( + navigationState = navigationState, + modifier = Modifier + .weight(1f) + .fillMaxHeight(), + ) { + menus() + } } } + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .width(20.dp) + .height(60.dp) + .graphicsLayer { + translationX = position.toPx() - size.width / 2 - 2.dp.toPx() + translationY = (windowSize.height / 2) - (size.height / 2) + } + .clip(RoundedCornerShape(topStart = 4.dp, bottomStart = 4.dp)) + .background(FloconTheme.colorPalette.secondary) + .clickable(onClick = { expanded = !expanded }), + ) { + FloconIcon( + imageVector = Icons.Outlined.ChevronRight, + tint = Color.LightGray, + modifier = Modifier.rotate(rotate), + ) + } } } -private fun EntryProviderBuilder.menus() { +private fun EntryProviderScope.menus() { entry { NetworkScreen() } entry { DashboardScreen() } entry { AnalyticsScreen() } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/Navigation.kt index 9ab9e9661..495028ae4 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/Navigation.kt @@ -1,11 +1,13 @@ package io.github.openflocon.flocondesktop.menu.ui.settings -import androidx.navigation3.runtime.EntryProviderBuilder +import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.navigation.FloconRoute +import kotlinx.serialization.Serializable +@Serializable data object SettingsRoute : FloconRoute -fun EntryProviderBuilder.settingsRoutes() { +fun EntryProviderScope.settingsRoutes() { entry { SettingsScreen() } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelView.kt index e3e1bc46c..4cbce45f6 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelView.kt @@ -17,8 +17,8 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.fastForEachIndexed import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelItem @@ -26,7 +26,6 @@ import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelState import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPannelSection import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.previewLeftPannelState import io.github.openflocon.library.designsystem.FloconTheme -import org.jetbrains.compose.ui.tooling.preview.Preview val PanelMaxWidth = 275.dp val PanelMinWidth = 64.dp @@ -44,8 +43,6 @@ fun LeftPanelView( .clip(FloconTheme.shapes.medium) .background(FloconTheme.colorPalette.primary) .padding(8.dp) -// .padding(bottom = 16.dp, top = 8.dp) -// .padding(horizontal = 12.dp), ) { MenuSection( current = state.current, @@ -92,7 +89,7 @@ private fun ColumnScope.MenuItems( expanded: Boolean, onClickItem: (LeftPanelItem) -> Unit, ) { - items.fastForEach { item -> + items.fastForEachIndexed { index, item -> PanelView( modifier = Modifier .height(PanelContentMinSize) @@ -104,6 +101,8 @@ private fun ColumnScope.MenuItems( isEnabled = item.isEnabled, onClick = { onClickItem(item) }, ) + if (index != items.lastIndex) + Spacer(Modifier.height(4.dp)) } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelView.kt index e683b1ead..ccea6895a 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelView.kt @@ -5,8 +5,6 @@ package io.github.openflocon.flocondesktop.menu.ui.view.leftpannel import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.ExperimentalSharedTransitionApi import androidx.compose.animation.animateColorAsState -import androidx.compose.animation.core.animateDpAsState -import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -27,9 +25,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha -import androidx.compose.ui.draw.shadow -import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp import io.github.openflocon.library.designsystem.FloconTheme @@ -48,14 +44,6 @@ fun PanelView( val interactionSource = remember { MutableInteractionSource() } val hovered by interactionSource.collectIsHoveredAsState() val shape = FloconTheme.shapes.medium - val shadow by animateDpAsState( - targetValue = when { - isSelected -> 6.dp - hovered -> 2.dp - else -> 0.dp - }, - label = "shadow", - ) val color by animateColorAsState( targetValue = when { isSelected -> FloconTheme.colorPalette.accent @@ -81,7 +69,7 @@ fun PanelView( Row( modifier = modifier .height(28.dp) - .shadow(elevation = shadow, shape = shape, clip = true, ambientColor = color, spotColor = color) + .clip(shape) .background(color) .graphicsLayer { alpha = lineAlpha diff --git a/FloconDesktop/gradle/libs.versions.toml b/FloconDesktop/gradle/libs.versions.toml index a21437ba2..f63b1399b 100644 --- a/FloconDesktop/gradle/libs.versions.toml +++ b/FloconDesktop/gradle/libs.versions.toml @@ -8,11 +8,11 @@ androidx-appcompat = "1.7.1" androidx-constraintlayout = "2.2.1" androidx-core = "1.17.0" androidx-espresso = "3.7.0" -androidx-lifecycle = "2.9.2" +androidx-lifecycle = "2.10.0-alpha03" androidx-testExt = "1.3.0" coil = "3.3.0" composeHotReload = "1.0.0-beta05" -composeMultiplatform = "1.9.0" +composeMultiplatform = "1.10.0-alpha03" junit = "4.13.2" kermit = "2.0.8" koin = "4.1.0" @@ -37,10 +37,8 @@ buildconfig = "5.6.8" paging = "3.3.2" # TODO Sort -nav3Core = "1.0.0+dev3064" -navEvent = "1.0.0-alpha09" +nav3Core = "1.0.0-alpha04+dev3147"#"1.0.0-alpha03" material3-adaptive = "1.0.0-alpha03" -lifecycleViewmodelNav3 = "2.10.0-alpha04" kotlinxSerializationCore = "1.8.1" [libraries] @@ -56,6 +54,7 @@ androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayo androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" } androidx-lifecycle-viewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel", version.ref = "androidx-lifecycle" } androidx-lifecycle-runtimeCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidx-lifecycle" } +androidx-lifecycle-nav3 = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "androidx-lifecycle" } coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" } kotlinx-coroutinesCore = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } kotlinx-coroutinesSwing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" } @@ -105,7 +104,6 @@ compose-navigation3-ui = { module = "org.jetbrains.androidx.navigation3:navigati material3-adaptive = { module = "org.jetbrains.compose.material3.adaptive:adaptive-navigation3", version.ref = "material3-adaptive" } # Optional add-on libraries -androidx-lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "lifecycleViewmodelNav3" } kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinxSerializationCore" } androidx-paging-common = { module = "androidx.paging:paging-common", version.ref = "paging" } diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt index d82ad5857..ca8b604a9 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt @@ -8,6 +8,7 @@ import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith +import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -16,12 +17,10 @@ fun FloconAnimateVisibility( state: T?, modifier: Modifier = Modifier, transitionSpec: AnimatedContentTransitionScope.() -> ContentTransform = { - (fadeIn(animationSpec = tween(220, delayMillis = 90)) + - slideIntoContainer( - towards = AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(220, delayMillis = 90) - ) - ) + (fadeIn(animationSpec = tween(220, delayMillis = 90)) + slideIntoContainer( + towards = AnimatedContentTransitionScope.SlideDirection.Start, + animationSpec = tween(220, delayMillis = 90) + )) .togetherWith(fadeOut(animationSpec = tween(90))) }, content: @Composable AnimatedContentScope.(T & Any) -> Unit @@ -33,6 +32,8 @@ fun FloconAnimateVisibility( ) { if (it != null) { content(it) + } else { + Box(Modifier) } } } diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconOverflow.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconOverflow.kt index 4f970d478..ba13595fc 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconOverflow.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconOverflow.kt @@ -4,7 +4,9 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.MoreVert import androidx.compose.material3.Icon +import androidx.compose.material3.LocalContentColor import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.Immutable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -12,6 +14,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import com.composeunstyled.DropdownPanelAnchor +import io.github.openflocon.library.designsystem.FloconTheme @Immutable data class FloconOverflowItem( @@ -35,7 +38,7 @@ data class FloconOverflowItem( @Composable fun FloconOverflow( modifier: Modifier = Modifier, - content: @Composable ColumnScope.() -> Unit + content: @Composable ColumnScope.(close: () -> Unit) -> Unit ) { var expanded by remember { mutableStateOf(false) } @@ -56,6 +59,8 @@ fun FloconOverflow( onDismissRequest = { expanded = false }, modifier = modifier ) { - content() + CompositionLocalProvider(LocalContentColor provides FloconTheme.colorPalette.onPrimary) { + content { expanded = false } + } } } diff --git a/FloconDesktop/navigation/build.gradle.kts b/FloconDesktop/navigation/build.gradle.kts index eb6c077ac..b5e0dda84 100644 --- a/FloconDesktop/navigation/build.gradle.kts +++ b/FloconDesktop/navigation/build.gradle.kts @@ -41,6 +41,8 @@ kotlin { implementation(libs.koin.core) implementation(libs.koin.compose.viewmodel) + implementation(libs.androidx.lifecycle.nav3) + api(libs.kotlinx.serialization.core) } } diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt index 581eefa82..4d1e4aef6 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigation.kt @@ -5,12 +5,12 @@ import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.navigation3.runtime.EntryProviderBuilder +import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator +import androidx.navigation3.runtime.EntryProviderScope import androidx.navigation3.runtime.entryProvider -import androidx.navigation3.runtime.rememberSavedStateNavEntryDecorator +import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator import androidx.navigation3.scene.SceneStrategy import androidx.navigation3.scene.SinglePaneSceneStrategy -import androidx.navigation3.scene.rememberSceneSetupNavEntryDecorator import androidx.navigation3.ui.NavDisplay @Composable @@ -18,7 +18,7 @@ fun FloconNavigation( navigationState: FloconNavigationState, modifier: Modifier = Modifier, sceneStrategy: SceneStrategy = SinglePaneSceneStrategy(), - builder: EntryProviderBuilder.() -> Unit + builder: EntryProviderScope.() -> Unit ) { NavDisplay( backStack = navigationState.stack, @@ -26,11 +26,11 @@ fun FloconNavigation( popTransitionSpec = { fadeIn() togetherWith fadeOut() }, predictivePopTransitionSpec = { fadeIn() togetherWith fadeOut() }, entryDecorators = listOf( - rememberSceneSetupNavEntryDecorator(), - rememberSavedStateNavEntryDecorator() + rememberSaveableStateHolderNavEntryDecorator(), + rememberViewModelStoreNavEntryDecorator() ), sceneStrategy = sceneStrategy, - onBack = { navigationState.back(it) }, + onBack = { navigationState.back(1) }, // TODO entryProvider = entryProvider { builder() }, diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt index 60ef31849..0eb7a5667 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt @@ -5,7 +5,11 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Close import androidx.compose.material.icons.outlined.Pin +import androidx.compose.material.icons.sharp.Pin +import androidx.compose.material.icons.sharp.PinInvoke +import androidx.compose.material.icons.sharp.PushPin import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -13,6 +17,7 @@ import androidx.navigation3.runtime.NavEntry import androidx.navigation3.scene.OverlayScene import androidx.navigation3.scene.Scene import androidx.navigation3.scene.SceneStrategy +import androidx.navigation3.scene.SceneStrategyScope import io.github.openflocon.library.designsystem.components.FloconIcon import io.github.openflocon.library.designsystem.components.FloconIconTonalButton import io.github.openflocon.library.designsystem.components.panel.FloconPanel @@ -21,14 +26,15 @@ import io.github.openflocon.navigation.FloconRoute import kotlinx.coroutines.launch import org.koin.core.component.KoinComponent -class PanelScene( +@Immutable +data class PanelScene( override val overlaidEntries: List>, override val key: Any, override val previousEntries: List>, private val entry: NavEntry, private val properties: PaneProperties, private val onPin: OnPin?, - private val onBack: (count: Int) -> Unit, + private val onBack: () -> Unit, ) : OverlayScene, KoinComponent { override val entries: List> = listOf(entry) @@ -43,10 +49,10 @@ class PanelScene( ) { FloconPanel( state = state, - onDismissRequest = { onBack(1) }, + onDismissRequest = onBack, actions = { FloconIconTonalButton( - onClick = { onBack(1) }, + onClick = onBack, modifier = Modifier .animatePanelAction() ) { @@ -60,14 +66,14 @@ class PanelScene( scope.launch { onPin.onPin() state.hide() - onBack(1) + onBack() } }, modifier = Modifier .animatePanelAction() ) { FloconIcon( - Icons.Outlined.Pin + Icons.Sharp.PushPin ) } } @@ -80,12 +86,10 @@ class PanelScene( } -class PanelSceneStrategy() : SceneStrategy { +class PanelSceneStrategy : SceneStrategy { - @Composable - override fun calculateScene( - entries: List>, - onBack: (Int) -> Unit + override fun SceneStrategyScope.calculateScene( + entries: List> ): Scene? { val lastEntry = entries.lastOrNull() ?: return null val properties = lastEntry.metadata[PANEL_KEY] ?: return null @@ -98,7 +102,7 @@ class PanelSceneStrategy() : SceneStrategy { entry = lastEntry, properties = properties, onPin = lastEntry.metadata[ON_PIN] as? OnPin, - onBack = onBack + onBack = { onBack() } ) } diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/WindowScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/WindowScene.kt index 9c3422cb2..7a7588069 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/WindowScene.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/WindowScene.kt @@ -1,14 +1,17 @@ package io.github.openflocon.navigation.scene import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable import androidx.compose.ui.window.Window import androidx.navigation3.runtime.NavEntry import androidx.navigation3.scene.OverlayScene import androidx.navigation3.scene.Scene import androidx.navigation3.scene.SceneStrategy +import androidx.navigation3.scene.SceneStrategyScope import io.github.openflocon.navigation.FloconRoute -class WindowScene( +@Immutable +data class WindowScene( private val entry: NavEntry, override val previousEntries: List>, private val onBack: () -> Unit @@ -30,18 +33,14 @@ class WindowScene( class WindowSceneStrategy : SceneStrategy { - @Composable - override fun calculateScene( - entries: List>, - onBack: (Int) -> Unit - ): Scene? { + override fun SceneStrategyScope.calculateScene(entries: List>): Scene? { val entry = entries.last() if (entry.metadata[IS_WINDOW] == true) { return WindowScene( entry = entry, previousEntries = entries.dropLast(1), - onBack = { onBack(1) } + onBack = onBack ) } From 3b6c70d8d001bf64929880acec3cb11352f3702e Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Fri, 24 Oct 2025 16:58:00 +0200 Subject: [PATCH 13/28] fix: Rebase --- .gitignore | 2 + FloconAndroid/.idea/.gitignore | 3 - FloconAndroid/.idea/.name | 1 - FloconAndroid/.idea/AndroidProjectSystem.xml | 6 - FloconAndroid/.idea/compiler.xml | 6 - .../.idea/deploymentTargetSelector.xml | 13 --- FloconAndroid/.idea/deviceManager.xml | 13 --- FloconAndroid/.idea/gradle.xml | 31 ------ .../inspectionProfiles/Project_Default.xml | 50 --------- FloconAndroid/.idea/migrations.xml | 10 -- FloconAndroid/.idea/misc.xml | 9 -- FloconAndroid/.idea/runConfigurations.xml | 17 --- .../FloconAndroid__app_assembleDebug_.xml | 33 ------ FloconAndroid/.idea/vcs.xml | 7 -- FloconAndroid/.idea/xcode.xml | 4 - .../settings/models/NetworkSettingsLocal.kt | 21 +++- .../network/body/model/ContentUiState.kt | 9 +- .../network/detail/NetworkDetailDelegate.kt | 5 +- .../detail/mapper/NetworkDetailUiMapper.kt | 66 ++++++----- .../network/detail/view/NetworkDetailView.kt | 16 ++- .../features/network/list/NetworkViewModel.kt | 75 +++++-------- ...{SettingsMapper.kt => SettingsUiMapper.kt} | 7 +- .../network/list/model/NetworkAction.kt | 2 +- .../list/model/NetworkSettingsUiModel.kt | 4 +- .../network/list/view/NetworkScreen.kt | 13 +-- .../menu/ui/view/topbar/app/TopBarAppView.kt | 6 +- .../github/openflocon/data/core/network/DI.kt | 2 - .../NetworkSettingsLocalDataSource.kt | 18 --- .../repository/NetworkRepositoryImpl.kt | 37 +------ .../openflocon/data/local/network/DI.kt | 3 - .../NetworkSettingsLocalDataSourceRoom.kt | 103 ------------------ .../domain/models/settings/NetworkSettings.kt | 5 +- .../io/github/openflocon/domain/network/DI.kt | 13 +-- .../models/NetworkSettingsDomainModel.kt | 7 -- .../repository/NetworkSettingsRepository.kt | 18 --- .../settings/GetNetworkSettingsUseCase.kt | 21 ---- .../settings/ObserveNetworkSettingsUseCase.kt | 24 ---- .../settings/UpdateNetworkSettingsUseCase.kt | 24 ---- 38 files changed, 124 insertions(+), 580 deletions(-) delete mode 100644 FloconAndroid/.idea/.gitignore delete mode 100644 FloconAndroid/.idea/.name delete mode 100644 FloconAndroid/.idea/AndroidProjectSystem.xml delete mode 100644 FloconAndroid/.idea/compiler.xml delete mode 100644 FloconAndroid/.idea/deploymentTargetSelector.xml delete mode 100644 FloconAndroid/.idea/deviceManager.xml delete mode 100644 FloconAndroid/.idea/gradle.xml delete mode 100644 FloconAndroid/.idea/inspectionProfiles/Project_Default.xml delete mode 100644 FloconAndroid/.idea/migrations.xml delete mode 100644 FloconAndroid/.idea/misc.xml delete mode 100644 FloconAndroid/.idea/runConfigurations.xml delete mode 100644 FloconAndroid/.idea/runConfigurations/FloconAndroid__app_assembleDebug_.xml delete mode 100644 FloconAndroid/.idea/vcs.xml delete mode 100644 FloconAndroid/.idea/xcode.xml rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/{SettingsMapper.kt => SettingsUiMapper.kt} (57%) delete mode 100644 FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/datasource/NetworkSettingsLocalDataSource.kt delete mode 100644 FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/datasource/NetworkSettingsLocalDataSourceRoom.kt delete mode 100644 FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/models/NetworkSettingsDomainModel.kt delete mode 100644 FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/repository/NetworkSettingsRepository.kt delete mode 100644 FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/settings/GetNetworkSettingsUseCase.kt delete mode 100644 FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/settings/ObserveNetworkSettingsUseCase.kt delete mode 100644 FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/settings/UpdateNetworkSettingsUseCase.kt diff --git a/.gitignore b/.gitignore index 654033cd5..25add166c 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ local.properties # Kotlin Multiplatform .kotlin/ kotlin-js-store/ + +FloconAndroid/.idea/ diff --git a/FloconAndroid/.idea/.gitignore b/FloconAndroid/.idea/.gitignore deleted file mode 100644 index 26d33521a..000000000 --- a/FloconAndroid/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/FloconAndroid/.idea/.name b/FloconAndroid/.idea/.name deleted file mode 100644 index b3405b3b3..000000000 --- a/FloconAndroid/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -My Application \ No newline at end of file diff --git a/FloconAndroid/.idea/AndroidProjectSystem.xml b/FloconAndroid/.idea/AndroidProjectSystem.xml deleted file mode 100644 index 4a53bee8c..000000000 --- a/FloconAndroid/.idea/AndroidProjectSystem.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/FloconAndroid/.idea/compiler.xml b/FloconAndroid/.idea/compiler.xml deleted file mode 100644 index b86273d94..000000000 --- a/FloconAndroid/.idea/compiler.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/FloconAndroid/.idea/deploymentTargetSelector.xml b/FloconAndroid/.idea/deploymentTargetSelector.xml deleted file mode 100644 index 3c55daf52..000000000 --- a/FloconAndroid/.idea/deploymentTargetSelector.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/FloconAndroid/.idea/deviceManager.xml b/FloconAndroid/.idea/deviceManager.xml deleted file mode 100644 index 91f95584d..000000000 --- a/FloconAndroid/.idea/deviceManager.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/FloconAndroid/.idea/gradle.xml b/FloconAndroid/.idea/gradle.xml deleted file mode 100644 index 3d505e396..000000000 --- a/FloconAndroid/.idea/gradle.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/FloconAndroid/.idea/inspectionProfiles/Project_Default.xml b/FloconAndroid/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index f0c6ad08e..000000000 --- a/FloconAndroid/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - \ No newline at end of file diff --git a/FloconAndroid/.idea/migrations.xml b/FloconAndroid/.idea/migrations.xml deleted file mode 100644 index f8051a6f9..000000000 --- a/FloconAndroid/.idea/migrations.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/FloconAndroid/.idea/misc.xml b/FloconAndroid/.idea/misc.xml deleted file mode 100644 index b2c751a35..000000000 --- a/FloconAndroid/.idea/misc.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/FloconAndroid/.idea/runConfigurations.xml b/FloconAndroid/.idea/runConfigurations.xml deleted file mode 100644 index 16660f1d8..000000000 --- a/FloconAndroid/.idea/runConfigurations.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/FloconAndroid/.idea/runConfigurations/FloconAndroid__app_assembleDebug_.xml b/FloconAndroid/.idea/runConfigurations/FloconAndroid__app_assembleDebug_.xml deleted file mode 100644 index 6dbf78c0e..000000000 --- a/FloconAndroid/.idea/runConfigurations/FloconAndroid__app_assembleDebug_.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - true - true - - false - false - - false - false - - - \ No newline at end of file diff --git a/FloconAndroid/.idea/vcs.xml b/FloconAndroid/.idea/vcs.xml deleted file mode 100644 index 9bad34491..000000000 --- a/FloconAndroid/.idea/vcs.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/FloconAndroid/.idea/xcode.xml b/FloconAndroid/.idea/xcode.xml deleted file mode 100644 index 4eb324224..000000000 --- a/FloconAndroid/.idea/xcode.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/models/NetworkSettingsLocal.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/models/NetworkSettingsLocal.kt index 517f040cc..632ba204e 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/models/NetworkSettingsLocal.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/core/data/settings/models/NetworkSettingsLocal.kt @@ -8,14 +8,29 @@ import kotlinx.serialization.Serializable internal data class NetworkSettingsLocal( @SerialName("pinned_detail") - val pinnedDetails: Boolean = false + val pinnedDetails: Boolean = false, + + @SerialName("display_old_sessions") + val displayOldSessions: Boolean = false, + + @SerialName("auto_scroll") + val autoScroll: Boolean = false, + + @SerialName("invert_list") + val invertList: Boolean = false ) internal fun NetworkSettingsLocal.toDomain() = NetworkSettings( - pinnedDetails = pinnedDetails + pinnedDetails = pinnedDetails, + displayOldSessions = displayOldSessions, + autoScroll = autoScroll, + invertList = invertList ) internal fun NetworkSettings.toLocal() = NetworkSettingsLocal( - pinnedDetails = pinnedDetails + pinnedDetails = pinnedDetails, + displayOldSessions = displayOldSessions, + autoScroll = autoScroll, + invertList = invertList ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/body/model/ContentUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/body/model/ContentUiState.kt index 05edc682a..c8a13543f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/body/model/ContentUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/body/model/ContentUiState.kt @@ -10,10 +10,7 @@ data class ContentUiState( val detailJsons: Set, val mocksDisplayed: MockDisplayed?, val websocketMocksDisplayed: Boolean, - val badNetworkQualityDisplayed: Boolean, - val invertList: Boolean, - val autoScroll: Boolean, - val pinPanel: Boolean + val badNetworkQualityDisplayed: Boolean ) @Immutable @@ -27,7 +24,5 @@ fun previewContentUiState() = ContentUiState( detailJsons = emptySet(), mocksDisplayed = null, badNetworkQualityDisplayed = false, - invertList = false, - autoScroll = false, - pinPanel = false + websocketMocksDisplayed = false ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/NetworkDetailDelegate.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/NetworkDetailDelegate.kt index dcef18a20..a87ca8158 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/NetworkDetailDelegate.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/NetworkDetailDelegate.kt @@ -52,7 +52,10 @@ class NetworkDetailDelegate( requestBody = "", requestSize = "", requestHeaders = emptyList(), - response = null + response = null, + requestBodyIsNotBlank = false, + canOpenRequestBody = false, + imageUrl = null ) ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/mapper/NetworkDetailUiMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/mapper/NetworkDetailUiMapper.kt index 414aef195..4ba5301e7 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/mapper/NetworkDetailUiMapper.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/mapper/NetworkDetailUiMapper.kt @@ -8,7 +8,6 @@ import io.github.openflocon.flocondesktop.features.network.detail.model.NetworkD import io.github.openflocon.flocondesktop.features.network.detail.model.NetworkDetailViewState import io.github.openflocon.flocondesktop.features.network.detail.model.NetworkDetailViewState.Method.Http import io.github.openflocon.flocondesktop.features.network.detail.model.NetworkDetailViewState.Method.MethodName -import io.github.openflocon.flocondesktop.features.network.list.delegate.OpenBodyDelegate import io.github.openflocon.flocondesktop.features.network.list.mapper.getMethodUi import io.github.openflocon.flocondesktop.features.network.list.mapper.loadingStatus import io.github.openflocon.flocondesktop.features.network.list.mapper.toGraphQlNetworkStatusUi @@ -19,40 +18,37 @@ import io.github.openflocon.flocondesktop.features.network.list.model.NetworkMet import io.github.openflocon.flocondesktop.features.network.list.model.NetworkStatusUi import io.github.openflocon.library.designsystem.common.isImageUrl -fun toDetailUi( - request: FloconNetworkCallDomainModel, -): NetworkDetailViewState = - NetworkDetailViewState( - callId = request.callId, - fullUrl = request.request.url, - method = toDetailMethodUi(request), - statusLabel = toDetailStatusLabel(request), - status = toDetailHttpStatusUi(request), - requestTimeFormatted = request.request.startTimeFormatted, - durationFormatted = request.response?.durationFormatted, - imageUrl = request.request.url.takeIf { request.response?.isImage() == true || it.isImageUrl() }, - // request - requestBodyTitle = requestBodyTitle(request), - requestBody = httpBodyToUi(request.request.body), - requestBodyIsNotBlank = request.request.body.isNullOrBlank().not(), - canOpenRequestBody = canOpenExternal(request.request.body), - // headers., - requestHeaders = toNetworkHeadersUi(request.request.headers), - requestSize = request.request.byteSizeFormatted, - // response - response = request.response?.let { - when (it) { - is FloconNetworkCallDomainModel.Response.Failure -> NetworkDetailViewState.Response.Error( - issue = it.issue, - ) +fun FloconNetworkCallDomainModel.toDetailUi(): NetworkDetailViewState = NetworkDetailViewState( + callId = callId, + fullUrl = request.url, + method = toDetailMethodUi(this), + statusLabel = toDetailStatusLabel(this), + status = toDetailHttpStatusUi(this), + requestTimeFormatted = request.startTimeFormatted, + durationFormatted = response?.durationFormatted, + imageUrl = request.url.takeIf { response?.isImage() == true || it.isImageUrl() }, + // request + requestBodyTitle = requestBodyTitle(this), + requestBody = httpBodyToUi(request.body), + requestBodyIsNotBlank = request.body.isNullOrBlank().not(), + canOpenRequestBody = canOpenExternal(request.body), + // headers., + requestHeaders = toNetworkHeadersUi(request.headers), + requestSize = request.byteSizeFormatted, + // response + response = response?.let { + when (it) { + is FloconNetworkCallDomainModel.Response.Failure -> NetworkDetailViewState.Response.Error( + issue = it.issue, + ) - is FloconNetworkCallDomainModel.Response.Success -> NetworkDetailViewState.Response.Success( - body = httpBodyToUi(it.body), - size = it.byteSizeFormatted, - canOpenResponseBody = canOpenExternal(it.body), - responseBodyIsNotBlank = it.body.isNullOrBlank().not(), - headers = toNetworkHeadersUi(it.headers), - ) + is FloconNetworkCallDomainModel.Response.Success -> NetworkDetailViewState.Response.Success( + body = httpBodyToUi(it.body), + size = it.byteSizeFormatted, + canOpenResponseBody = canOpenExternal(it.body), + responseBodyIsNotBlank = it.body.isNullOrBlank().not(), + headers = toNetworkHeadersUi(it.headers), + ) } @@ -168,6 +164,6 @@ fun toDetailMethodUi(request: FloconNetworkCallDomainModel): NetworkDetailViewSt ) } -private fun canOpenExternal(body: String?) : Boolean { +private fun canOpenExternal(body: String?): Boolean { return body != null && body.isNotBlank() && OpenFile.isSupported() } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/NetworkDetailView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/NetworkDetailView.kt index 274a5cf5f..214d2f69d 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/NetworkDetailView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/view/NetworkDetailView.kt @@ -20,12 +20,16 @@ import androidx.compose.material.icons.outlined.OpenInFull import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import coil3.compose.AsyncImage import io.github.openflocon.flocondesktop.features.network.detail.NetworkDetailViewModel import io.github.openflocon.flocondesktop.features.network.detail.model.NetworkDetailViewState import io.github.openflocon.flocondesktop.features.network.detail.model.previewNetworkDetailHeaderUi @@ -280,7 +284,7 @@ private fun Request( title = state.requestBodyTitle, initialValue = true, actions = { - if(state.requestBodyIsNotBlank) { + if (state.requestBodyIsNotBlank) { FloconIconButton( tooltip = "View in app", imageVector = Icons.Outlined.OpenInFull, @@ -294,7 +298,7 @@ private fun Request( } ) } - if(state.canOpenRequestBody) { + if (state.canOpenRequestBody) { FloconIconButton( tooltip = "Open in external editor", imageVector = Icons.AutoMirrored.Outlined.OpenInNew, @@ -307,7 +311,7 @@ private fun Request( } ) } - if(state.requestBodyIsNotBlank) { + if (state.requestBodyIsNotBlank) { FloconIconButton( tooltip = "Copy", imageVector = Icons.Outlined.CopyAll, @@ -443,7 +447,7 @@ private fun Response( title = "Response - Body", initialValue = true, actions = { - if(response.responseBodyIsNotBlank) { + if (response.responseBodyIsNotBlank) { FloconIconButton( tooltip = "View body in app", imageVector = Icons.Outlined.OpenInFull, @@ -457,7 +461,7 @@ private fun Response( } ) } - if(response.canOpenResponseBody) { + if (response.canOpenResponseBody) { FloconIconButton( tooltip = "Open in external editor", imageVector = Icons.AutoMirrored.Outlined.OpenInNew, @@ -470,7 +474,7 @@ private fun Response( } ) } - if(response.responseBodyIsNotBlank) { + if (response.responseBodyIsNotBlank) { FloconIconButton( tooltip = "Copy", imageVector = Icons.Outlined.CopyAll, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt index 5cb4e682c..fd180050f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt @@ -8,7 +8,6 @@ import androidx.lifecycle.viewModelScope import androidx.paging.PagingData import androidx.paging.cachedIn import androidx.paging.map -import co.touchlab.kermit.Logger import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.common.combines import io.github.openflocon.domain.device.usecase.ObserveCurrentDeviceIdAndPackageNameUseCase @@ -18,7 +17,6 @@ import io.github.openflocon.domain.network.models.BadQualityConfigDomainModel import io.github.openflocon.domain.network.models.MockNetworkDomainModel import io.github.openflocon.domain.network.models.NetworkFilterDomainModel import io.github.openflocon.domain.network.models.NetworkFilterDomainModel.Filters -import io.github.openflocon.domain.network.models.NetworkSettingsDomainModel import io.github.openflocon.domain.network.models.NetworkTextFilterColumns import io.github.openflocon.domain.network.usecase.DecodeJwtTokenUseCase import io.github.openflocon.domain.network.usecase.ExportNetworkCallsToCsvUseCase @@ -32,14 +30,11 @@ import io.github.openflocon.domain.network.usecase.RemoveOldSessionsNetworkReque import io.github.openflocon.domain.network.usecase.ResetCurrentDeviceHttpRequestsUseCase import io.github.openflocon.domain.network.usecase.badquality.ObserveAllNetworkBadQualitiesUseCase import io.github.openflocon.domain.network.usecase.mocks.ObserveNetworkMocksUseCase +import io.github.openflocon.domain.network.usecase.mocks.ObserveNetworkWebsocketIdsUseCase import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed import io.github.openflocon.flocondesktop.core.data.settings.usecase.ObserveNetworkSettingsUseCase import io.github.openflocon.flocondesktop.core.data.settings.usecase.SaveNetworkSettingsUseCase import io.github.openflocon.flocondesktop.features.network.NetworkRoutes -import io.github.openflocon.domain.network.usecase.mocks.ObserveNetworkWebsocketIdsUseCase -import io.github.openflocon.domain.network.usecase.settings.ObserveNetworkSettingsUseCase -import io.github.openflocon.domain.network.usecase.settings.UpdateNetworkSettingsUseCase -import io.github.openflocon.flocondesktop.common.utils.OpenFile import io.github.openflocon.flocondesktop.features.network.body.model.ContentUiState import io.github.openflocon.flocondesktop.features.network.body.model.MockDisplayed import io.github.openflocon.flocondesktop.features.network.detail.NetworkDetailDelegate @@ -60,6 +55,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.firstOrNull @@ -69,7 +65,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import java.io.File class NetworkViewModel( observeNetworkRequestsUseCase: ObserveNetworkRequestsUseCase, @@ -90,12 +85,9 @@ class NetworkViewModel( private val removeOldSessionsNetworkRequestUseCase: RemoveOldSessionsNetworkRequestUseCase, private val navigationState: MainFloconNavigationState, private val detailDelegate: NetworkDetailDelegate, - private val observeNetworkSettingsUseCase: ObserveNetworkSettingsUseCase private val observeNetworkSettingsUseCase: ObserveNetworkSettingsUseCase, - private val updateNetworkSettingsUseCase: UpdateNetworkSettingsUseCase, private val observeNetworkWebsocketIdsUseCase: ObserveNetworkWebsocketIdsUseCase, private val openBodyDelegate: OpenBodyDelegate, - private val observeNetworkSettingsUseCase: ObserveNetworkSettingsUseCase, private val saveNetworkSettingsUseCase: SaveNetworkSettingsUseCase ) : ViewModel(headerDelegate) { @@ -105,27 +97,23 @@ class NetworkViewModel( detailJsons = emptySet(), mocksDisplayed = null, badNetworkQualityDisplayed = false, - websocketMocksDisplayed = false, - ), + websocketMocksDisplayed = false + ) ) private val _filterText = mutableStateOf("") val filterText: State = _filterText - private val defaultNetworkSettings = NetworkSettingsDomainModel( + private val defaultNetworkSettings = NetworkSettings( displayOldSessions = true, autoScroll = false, invertList = false, + pinnedDetails = false ) - private val settings: StateFlow = observeNetworkSettingsUseCase() + private val settings: StateFlow = observeNetworkSettingsUseCase() .flowOn(dispatcherProvider.viewModel) - .map { it ?: defaultNetworkSettings } - .stateIn( - viewModelScope, - SharingStarted.WhileSubscribed(5_000), - initialValue = defaultNetworkSettings - ) + .stateInWhileSubscribed(defaultNetworkSettings) private val filterUiState = combine( mocksUseCase().map { it.any(MockNetworkDomainModel::isEnabled) }.distinctUntilChanged(), @@ -140,18 +128,15 @@ class NetworkViewModel( displayOldSessions = settings.displayOldSessions, hasWebsockets = hasWebsockets, ) - }.stateIn( - viewModelScope, SharingStarted.WhileSubscribed(5_000), - TopBarUiState( - hasBadNetwork = false, - hasMocks = false, - displayOldSessions = false, - hasWebsockets = false, + } + .stateInWhileSubscribed( + TopBarUiState( + hasBadNetwork = false, + hasMocks = false, + displayOldSessions = false, + hasWebsockets = false, + ) ) - ) - - private val settings = observeNetworkSettingsUseCase() - .stateInWhileSubscribed(NetworkSettings(pinnedDetails = false)) private val filter = combines( snapshotFlow { _filterText.value }.map { it.takeIf { it.isNotBlank() } } @@ -160,14 +145,15 @@ class NetworkViewModel( headerDelegate.allowedMethods().map { items -> methodsToDomain(items) } .distinctUntilChanged(), settings, - ).map { (textFilters, filterOnAllColumns, methods, settings) -> - NetworkFilterDomainModel( - filterOnAllColumns = textFilters, - textsFilters = filterOnAllColumns, - methodFilter = methods, - displayOldSessions = settings.displayOldSessions, - ) - } + ) + .map { (textFilters, filterOnAllColumns, methods, settings) -> + NetworkFilterDomainModel( + filterOnAllColumns = textFilters, + textsFilters = filterOnAllColumns, + methodFilter = methods, + displayOldSessions = settings.displayOldSessions, + ) + } private val sortAndFilter = combines( headerDelegate.sorted.map { it?.toDomain() }.distinctUntilChanged(), @@ -212,9 +198,7 @@ class NetworkViewModel( settings.map { it.toUi() }, ) { content, detail, filter, header, settings -> NetworkUiState( - contentState = content.copy( - pinPanel = settings.pinnedDetails - ), + contentState = content, detailState = detail, filterState = filter, headerState = header, @@ -276,6 +260,7 @@ class NetworkViewModel( NetworkAction.CloseWebsocketMocks -> contentState.update { it.copy(websocketMocksDisplayed = false) } is NetworkAction.OpenBodyExternally.Request -> openBodyDelegate.openBodyExternally(action.item) is NetworkAction.OpenBodyExternally.Response -> openBodyDelegate.openBodyExternally(action.item) + is NetworkAction.Pinned -> onPinned(action) } } @@ -297,7 +282,7 @@ class NetworkViewModel( private fun toggleAutoScroll(action: NetworkAction.ToggleAutoScroll) { viewModelScope.launch(dispatcherProvider.viewModel) { - updateNetworkSettingsUseCase( + saveNetworkSettingsUseCase( settings.value.copy( autoScroll = action.value ) @@ -307,7 +292,7 @@ class NetworkViewModel( private fun toggleDisplayOldSessions(action: NetworkAction.UpdateDisplayOldSessions) { viewModelScope.launch(dispatcherProvider.viewModel) { - updateNetworkSettingsUseCase( + saveNetworkSettingsUseCase( settings.value.copy( displayOldSessions = action.value ) @@ -317,7 +302,7 @@ class NetworkViewModel( private fun toggleInvertList(action: NetworkAction.InvertList) { viewModelScope.launch(dispatcherProvider.viewModel) { - updateNetworkSettingsUseCase( + saveNetworkSettingsUseCase( settings.value.copy( invertList = action.value ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/SettingsMapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/SettingsUiMapper.kt similarity index 57% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/SettingsMapper.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/SettingsUiMapper.kt index 1fe0dee08..cb3007fa9 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/SettingsMapper.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/mapper/SettingsUiMapper.kt @@ -1,10 +1,11 @@ package io.github.openflocon.flocondesktop.features.network.list.mapper -import io.github.openflocon.domain.network.models.NetworkSettingsDomainModel +import io.github.openflocon.domain.models.settings.NetworkSettings import io.github.openflocon.flocondesktop.features.network.list.model.NetworkSettingsUiModel -fun NetworkSettingsDomainModel.toUi() = NetworkSettingsUiModel( +fun NetworkSettings.toUi() = NetworkSettingsUiModel( + pinPanel = pinnedDetails, displayOldSessions = displayOldSessions, autoScroll = autoScroll, - invertList = invertList, + invertList = invertList ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkAction.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkAction.kt index 53ae0a6d9..fa2280b32 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkAction.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkAction.kt @@ -48,7 +48,7 @@ sealed interface NetworkAction { data class Pinned(val value: Boolean) : NetworkAction - data object ToggleAutoScroll : NetworkAction + data class ToggleAutoScroll(val value: Boolean): NetworkAction data object ClearOldSession : NetworkAction diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkSettingsUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkSettingsUiModel.kt index 8f21d505d..47cf5a409 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkSettingsUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkSettingsUiModel.kt @@ -6,11 +6,13 @@ import androidx.compose.runtime.Immutable data class NetworkSettingsUiModel( val displayOldSessions: Boolean, val autoScroll: Boolean, - val invertList: Boolean + val invertList: Boolean, + val pinPanel: Boolean ) fun previewNetworkSettingsUiModel() = NetworkSettingsUiModel( displayOldSessions = true, autoScroll = false, invertList = false, + pinPanel = false ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt index d63cf1a1f..414772180 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt @@ -15,13 +15,10 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.List -import androidx.compose.material.icons.outlined.ChatBubble import androidx.compose.material.icons.outlined.CleaningServices import androidx.compose.material.icons.outlined.Delete -import androidx.compose.material.icons.outlined.History import androidx.compose.material.icons.outlined.ImportExport import androidx.compose.material.icons.outlined.PlayCircle -import androidx.compose.material.icons.outlined.Podcasts import androidx.compose.material.icons.outlined.SignalWifiStatusbarConnectedNoInternet4 import androidx.compose.material.icons.outlined.WifiTethering import androidx.compose.material.icons.sharp.PushPin @@ -241,19 +238,19 @@ fun NetworkScreen( onClick = { onAction(NetworkAction.ExportCsv) } ) FloconDropdownMenuItem( - checked = uiState.contentState.autoScroll, + checked = uiState.settings.autoScroll, text = "Auto scroll", leadingIcon = Icons.Outlined.PlayCircle, - onCheckedChange = { onAction(NetworkAction.ToggleAutoScroll) } + onCheckedChange = { checked -> onAction(NetworkAction.ToggleAutoScroll(checked)) } ) FloconDropdownMenuItem( - checked = uiState.contentState.invertList, + checked = uiState.settings.invertList, text = "Invert list", leadingIcon = Icons.AutoMirrored.Outlined.List, onCheckedChange = { checked -> onAction(NetworkAction.InvertList(checked)) } ) FloconDropdownMenuItem( - checked = uiState.contentState.pinPanel, + checked = uiState.settings.pinPanel, text = "Pin panel", leadingIcon = Icons.Sharp.PushPin, onCheckedChange = { checked -> onAction(NetworkAction.Pinned(checked)); it() } @@ -292,7 +289,7 @@ fun NetworkScreen( ) { LazyColumn( state = lazyListState, - reverseLayout = uiState.contentState.invertList, + reverseLayout = uiState.settings.invertList, modifier = Modifier .fillMaxHeight() .weight(1f) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppView.kt index 8368e37fd..68b2d73fc 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppView.kt @@ -12,8 +12,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Code -import androidx.compose.material.icons.filled.SmartToy import androidx.compose.material.icons.filled.Terminal import androidx.compose.material.icons.outlined.Close import androidx.compose.material3.Text @@ -32,6 +30,7 @@ import androidx.compose.ui.unit.sp import flocondesktop.composeapp.generated.resources.Res import flocondesktop.composeapp.generated.resources.smartphone import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconIcon import org.jetbrains.compose.resources.painterResource @@ -117,7 +116,7 @@ private fun AppImage( modifier = modifier, ) } else { - when(platform) { + when (platform) { DeviceItemUiModel.Platform.Desktop -> { Image( imageVector = Icons.Default.Terminal, @@ -126,6 +125,7 @@ private fun AppImage( modifier = modifier, ) } + DeviceItemUiModel.Platform.ios, DeviceItemUiModel.Platform.Android, DeviceItemUiModel.Platform.Unknown -> { diff --git a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/DI.kt b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/DI.kt index 92fe3ddbb..287d8b4d6 100644 --- a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/DI.kt +++ b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/DI.kt @@ -7,7 +7,6 @@ import io.github.openflocon.domain.network.repository.NetworkBadQualityRepositor import io.github.openflocon.domain.network.repository.NetworkFilterRepository import io.github.openflocon.domain.network.repository.NetworkMocksRepository import io.github.openflocon.domain.network.repository.NetworkRepository -import io.github.openflocon.domain.network.repository.NetworkSettingsRepository import org.koin.core.module.dsl.bind import org.koin.core.module.dsl.singleOf import org.koin.dsl.bind @@ -20,6 +19,5 @@ internal val networkModule = module { bind() bind() bind() - bind() } } diff --git a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/datasource/NetworkSettingsLocalDataSource.kt b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/datasource/NetworkSettingsLocalDataSource.kt deleted file mode 100644 index a32c0a493..000000000 --- a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/datasource/NetworkSettingsLocalDataSource.kt +++ /dev/null @@ -1,18 +0,0 @@ -package io.github.openflocon.data.core.network.datasource - -import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel -import io.github.openflocon.domain.network.models.NetworkSettingsDomainModel -import kotlinx.coroutines.flow.Flow - -interface NetworkSettingsLocalDataSource { - suspend fun getNetworkSettings( - deviceAndApp: DeviceIdAndPackageNameDomainModel, - ): NetworkSettingsDomainModel? - - fun observeNetworkSettings(deviceAndApp: DeviceIdAndPackageNameDomainModel): Flow - - suspend fun updateNetworkSettings( - deviceAndApp: DeviceIdAndPackageNameDomainModel, - newValue: NetworkSettingsDomainModel, - ) -} diff --git a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/repository/NetworkRepositoryImpl.kt b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/repository/NetworkRepositoryImpl.kt index 45e9e7f2d..07d74465b 100644 --- a/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/repository/NetworkRepositoryImpl.kt +++ b/FloconDesktop/data/core/src/commonMain/kotlin/io/github/openflocon/data/core/network/repository/NetworkRepositoryImpl.kt @@ -6,7 +6,6 @@ import io.github.openflocon.data.core.network.datasource.NetworkLocalWebsocketDa import io.github.openflocon.data.core.network.datasource.NetworkMocksLocalDataSource import io.github.openflocon.data.core.network.datasource.NetworkQualityLocalDataSource import io.github.openflocon.data.core.network.datasource.NetworkRemoteDataSource -import io.github.openflocon.data.core.network.datasource.NetworkSettingsLocalDataSource import io.github.openflocon.domain.Protocol import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel @@ -18,7 +17,6 @@ import io.github.openflocon.domain.network.models.FloconNetworkCallDomainModel import io.github.openflocon.domain.network.models.FloconNetworkResponseOnlyDomainModel import io.github.openflocon.domain.network.models.MockNetworkDomainModel import io.github.openflocon.domain.network.models.NetworkFilterDomainModel -import io.github.openflocon.domain.network.models.NetworkSettingsDomainModel import io.github.openflocon.domain.network.models.NetworkSortDomainModel import io.github.openflocon.domain.network.models.NetworkWebsocketId import io.github.openflocon.domain.network.models.isImage @@ -26,7 +24,6 @@ import io.github.openflocon.domain.network.repository.NetworkBadQualityRepositor import io.github.openflocon.domain.network.repository.NetworkImageRepository import io.github.openflocon.domain.network.repository.NetworkMocksRepository import io.github.openflocon.domain.network.repository.NetworkRepository -import io.github.openflocon.domain.network.repository.NetworkSettingsRepository import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.withContext @@ -37,13 +34,11 @@ class NetworkRepositoryImpl( private val networkLocalWebsocketDataSource: NetworkLocalWebsocketDataSource, private val networkMocksLocalDataSource: NetworkMocksLocalDataSource, private val networkQualityLocalDataSource: NetworkQualityLocalDataSource, - private val networkSettingsLocalDataSource: NetworkSettingsLocalDataSource, private val networkImageRepository: NetworkImageRepository, private val networkRemoteDataSource: NetworkRemoteDataSource, ) : NetworkRepository, NetworkMocksRepository, MessagesReceiverRepository, - NetworkSettingsRepository, NetworkBadQualityRepository { override val pluginName = listOf(Protocol.FromDevice.Network.Plugin) @@ -57,7 +52,7 @@ class NetworkRepositoryImpl( deviceIdAndPackageName = deviceIdAndPackageName, mocks = getAllEnabledMocks(deviceIdAndPackageName = deviceIdAndPackageName), ) - if(isNewDevice) { + if (isNewDevice) { networkQualityLocalDataSource.prepopulate( deviceIdAndPackageName = deviceIdAndPackageName, ) @@ -122,6 +117,7 @@ class NetworkRepositoryImpl( ids = networkRemoteDataSource.getWebsocketClientsIds(message), ) } + Protocol.FromDevice.Network.Method.LogWebSocketEvent -> { networkRemoteDataSource.getWebSocketData(message) ?.let { wenSocketEvent -> @@ -218,7 +214,7 @@ class NetworkRepositoryImpl( ): FloconNetworkCallDomainModel? { val isRequestGraphQl = request.request.specificInfos is FloconNetworkCallDomainModel.Request.SpecificInfos.GraphQl return try { - val response = if(isRequestGraphQl) { + val response = if (isRequestGraphQl) { when (val r = receivedResponse.response) { is FloconNetworkCallDomainModel.Response.Success -> { // specific case : map to graphQl if needed @@ -231,6 +227,7 @@ class NetworkRepositoryImpl( ) ) } + else -> r } } @@ -418,32 +415,6 @@ class NetworkRepositoryImpl( } } - override suspend fun getNetworkSettings(deviceAndApp: DeviceIdAndPackageNameDomainModel): NetworkSettingsDomainModel? { - return withContext(dispatcherProvider.data) { - networkSettingsLocalDataSource.getNetworkSettings( - deviceAndApp = deviceAndApp, - ) - } - } - - override fun observeNetworkSettings(deviceAndApp: DeviceIdAndPackageNameDomainModel): Flow { - return networkSettingsLocalDataSource.observeNetworkSettings( - deviceAndApp = deviceAndApp, - ).flowOn(dispatcherProvider.data) - } - - override suspend fun updateNetworkSettings( - deviceAndApp: DeviceIdAndPackageNameDomainModel, - newValue: NetworkSettingsDomainModel - ) { - withContext(dispatcherProvider.data) { - networkSettingsLocalDataSource.updateNetworkSettings( - deviceAndApp = deviceAndApp, - newValue = newValue, - ) - } - } - override suspend fun observeWebsocketClientsIds(deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel): Flow> { return networkLocalWebsocketDataSource.observeWebsocketClients( deviceIdAndPackageName = deviceIdAndPackageName, diff --git a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/DI.kt b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/DI.kt index 33491fd53..fd3cd5d5b 100644 --- a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/DI.kt +++ b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/DI.kt @@ -5,13 +5,11 @@ import io.github.openflocon.data.core.network.datasource.NetworkLocalDataSource import io.github.openflocon.data.core.network.datasource.NetworkLocalWebsocketDataSource import io.github.openflocon.data.core.network.datasource.NetworkMocksLocalDataSource import io.github.openflocon.data.core.network.datasource.NetworkQualityLocalDataSource -import io.github.openflocon.data.core.network.datasource.NetworkSettingsLocalDataSource import io.github.openflocon.data.local.network.datasource.BadQualityConfigLocalDataSourceImpl import io.github.openflocon.data.local.network.datasource.NetworkFilterLocalDataSourceRoom import io.github.openflocon.data.local.network.datasource.NetworkLocalDataSourceRoom import io.github.openflocon.data.local.network.datasource.NetworkLocalWebsocketDataSourceRam import io.github.openflocon.data.local.network.datasource.NetworkMocksLocalDataSourceImpl -import io.github.openflocon.data.local.network.datasource.NetworkSettingsLocalDataSourceRoom import org.koin.core.module.dsl.singleOf import org.koin.dsl.bind import org.koin.dsl.module @@ -21,6 +19,5 @@ internal val networkModule = module { singleOf(::NetworkFilterLocalDataSourceRoom) bind NetworkFilterLocalDataSource::class singleOf(::NetworkMocksLocalDataSourceImpl) bind NetworkMocksLocalDataSource::class singleOf(::BadQualityConfigLocalDataSourceImpl) bind NetworkQualityLocalDataSource::class - singleOf(::NetworkSettingsLocalDataSourceRoom) bind NetworkSettingsLocalDataSource::class singleOf(::NetworkLocalWebsocketDataSourceRam) bind NetworkLocalWebsocketDataSource::class } diff --git a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/datasource/NetworkSettingsLocalDataSourceRoom.kt b/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/datasource/NetworkSettingsLocalDataSourceRoom.kt deleted file mode 100644 index a02b1e620..000000000 --- a/FloconDesktop/data/local/src/commonMain/kotlin/io/github/openflocon/data/local/network/datasource/NetworkSettingsLocalDataSourceRoom.kt +++ /dev/null @@ -1,103 +0,0 @@ -package io.github.openflocon.data.local.network.datasource - -import io.github.openflocon.data.core.network.datasource.NetworkSettingsLocalDataSource -import io.github.openflocon.data.local.network.dao.NetworkSettingsDao -import io.github.openflocon.data.local.network.models.NetworkSettingsEntity -import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel -import io.github.openflocon.domain.network.models.NetworkSettingsDomainModel -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json - -class NetworkSettingsLocalDataSourceRoom( - private val networkSettingsDao: NetworkSettingsDao, - private val json: Json, -) : NetworkSettingsLocalDataSource { - - override suspend fun getNetworkSettings( - deviceAndApp: DeviceIdAndPackageNameDomainModel, - ): NetworkSettingsDomainModel? { - return networkSettingsDao.get( - deviceId = deviceAndApp.deviceId, - packageName = deviceAndApp.packageName - ).let { - it?.toDomain( - json = json, - ) - } - } - - override fun observeNetworkSettings(deviceAndApp: DeviceIdAndPackageNameDomainModel): Flow { - return networkSettingsDao.observe( - deviceId = deviceAndApp.deviceId, - packageName = deviceAndApp.packageName - ).map { - it?.toDomain( - json = json, - ) - } - } - - override suspend fun updateNetworkSettings( - deviceAndApp: DeviceIdAndPackageNameDomainModel, - newValue: NetworkSettingsDomainModel - ) { - networkSettingsDao.insertOrUpdate( - newValue.toEntity( - json = json, - deviceAndApp = deviceAndApp, - ) - ) - } -} - -private fun NetworkSettingsDomainModel.toEntity( - deviceAndApp: DeviceIdAndPackageNameDomainModel, - json: Json, -): NetworkSettingsEntity { - val saved = try { - json.encodeToString(this.toSaved()) - } catch (t: Throwable) { - t.printStackTrace() - "" - } - return NetworkSettingsEntity( - deviceId = deviceAndApp.deviceId, - packageName = deviceAndApp.packageName, - valueAsJson = saved, - ) -} - -@Serializable -internal data class NetworkSettingsSavedModel( - val displayOldSessions: Boolean, - val autoScroll: Boolean, - val invertList: Boolean, -) - -private fun NetworkSettingsDomainModel.toSaved() = NetworkSettingsSavedModel( - displayOldSessions = displayOldSessions, - autoScroll = autoScroll, - invertList = invertList, -) - -private fun NetworkSettingsEntity.toDomain( - json: Json, -): NetworkSettingsDomainModel { - val saved = try { - json.decodeFromString(this.valueAsJson) - } catch (t: Throwable) { - t.printStackTrace() - NetworkSettingsSavedModel( - displayOldSessions = false, - autoScroll = false, - invertList = false, - ) - } - return NetworkSettingsDomainModel( - displayOldSessions = saved.displayOldSessions, - autoScroll = saved.autoScroll, - invertList = saved.invertList, - ) -} diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/models/settings/NetworkSettings.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/models/settings/NetworkSettings.kt index 27cef52f3..156164cae 100644 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/models/settings/NetworkSettings.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/models/settings/NetworkSettings.kt @@ -1,5 +1,8 @@ package io.github.openflocon.domain.models.settings data class NetworkSettings( - val pinnedDetails: Boolean + val pinnedDetails: Boolean, + val displayOldSessions: Boolean, + val autoScroll: Boolean, + val invertList: Boolean ) diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/DI.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/DI.kt index b78268705..6e4d3aba3 100644 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/DI.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/DI.kt @@ -5,11 +5,11 @@ import io.github.openflocon.domain.network.usecase.ExportNetworkCallsToCsvUseCas import io.github.openflocon.domain.network.usecase.GenerateCurlCommandUseCase import io.github.openflocon.domain.network.usecase.GetNetworkFilterUseCase import io.github.openflocon.domain.network.usecase.GetNetworkRequestsUseCase +import io.github.openflocon.domain.network.usecase.ObserveNetworkFilterUseCase import io.github.openflocon.domain.network.usecase.ObserveNetworkRequestsByIdUseCase import io.github.openflocon.domain.network.usecase.ObserveNetworkRequestsUseCase -import io.github.openflocon.domain.network.usecase.ObserveNetworkFilterUseCase -import io.github.openflocon.domain.network.usecase.RemoveNetworkRequestUseCase import io.github.openflocon.domain.network.usecase.RemoveHttpRequestsBeforeUseCase +import io.github.openflocon.domain.network.usecase.RemoveNetworkRequestUseCase import io.github.openflocon.domain.network.usecase.RemoveOldSessionsNetworkRequestUseCase import io.github.openflocon.domain.network.usecase.ResetCurrentDeviceHttpRequestsUseCase import io.github.openflocon.domain.network.usecase.UpdateNetworkFilterUseCase @@ -17,8 +17,8 @@ import io.github.openflocon.domain.network.usecase.badquality.DeleteBadQualityUs import io.github.openflocon.domain.network.usecase.badquality.ObserveAllNetworkBadQualitiesUseCase import io.github.openflocon.domain.network.usecase.badquality.ObserveNetworkBadQualityUseCase import io.github.openflocon.domain.network.usecase.badquality.SaveNetworkBadQualityUseCase -import io.github.openflocon.domain.network.usecase.badquality.SetupNetworkBadQualityUseCase import io.github.openflocon.domain.network.usecase.badquality.SetNetworkBadQualityEnabledConfigUseCase +import io.github.openflocon.domain.network.usecase.badquality.SetupNetworkBadQualityUseCase import io.github.openflocon.domain.network.usecase.mocks.AddNetworkMocksUseCase import io.github.openflocon.domain.network.usecase.mocks.DeleteNetworkMocksUseCase import io.github.openflocon.domain.network.usecase.mocks.GenerateNetworkMockFromNetworkCallUseCase @@ -29,9 +29,6 @@ import io.github.openflocon.domain.network.usecase.mocks.SendNetworkWebsocketMoc import io.github.openflocon.domain.network.usecase.mocks.SetupNetworkMocksUseCase import io.github.openflocon.domain.network.usecase.mocks.UpdateNetworkMockIsEnabledUseCase import io.github.openflocon.domain.network.usecase.mocks.UpdateNetworkMocksDeviceUseCase -import io.github.openflocon.domain.network.usecase.settings.GetNetworkSettingsUseCase -import io.github.openflocon.domain.network.usecase.settings.ObserveNetworkSettingsUseCase -import io.github.openflocon.domain.network.usecase.settings.UpdateNetworkSettingsUseCase import org.koin.core.module.dsl.factoryOf import org.koin.dsl.module @@ -68,8 +65,4 @@ internal val networkModule = module { factoryOf(::SetupNetworkBadQualityUseCase) factoryOf(::SetNetworkBadQualityEnabledConfigUseCase) factoryOf(::ObserveAllNetworkBadQualitiesUseCase) - // settings - factoryOf(::GetNetworkSettingsUseCase) - factoryOf(::UpdateNetworkSettingsUseCase) - factoryOf(::ObserveNetworkSettingsUseCase) } diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/models/NetworkSettingsDomainModel.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/models/NetworkSettingsDomainModel.kt deleted file mode 100644 index 826a4790c..000000000 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/models/NetworkSettingsDomainModel.kt +++ /dev/null @@ -1,7 +0,0 @@ -package io.github.openflocon.domain.network.models - -data class NetworkSettingsDomainModel( - val displayOldSessions: Boolean, - val autoScroll: Boolean, - val invertList: Boolean, -) diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/repository/NetworkSettingsRepository.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/repository/NetworkSettingsRepository.kt deleted file mode 100644 index 9c76f6aa0..000000000 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/repository/NetworkSettingsRepository.kt +++ /dev/null @@ -1,18 +0,0 @@ -package io.github.openflocon.domain.network.repository - -import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel -import io.github.openflocon.domain.network.models.NetworkSettingsDomainModel -import kotlinx.coroutines.flow.Flow - -interface NetworkSettingsRepository { - suspend fun getNetworkSettings( - deviceAndApp: DeviceIdAndPackageNameDomainModel, - ): NetworkSettingsDomainModel? - - fun observeNetworkSettings(deviceAndApp: DeviceIdAndPackageNameDomainModel): Flow - - suspend fun updateNetworkSettings( - deviceAndApp: DeviceIdAndPackageNameDomainModel, - newValue: NetworkSettingsDomainModel, - ) -} diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/settings/GetNetworkSettingsUseCase.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/settings/GetNetworkSettingsUseCase.kt deleted file mode 100644 index 5eb922ea6..000000000 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/settings/GetNetworkSettingsUseCase.kt +++ /dev/null @@ -1,21 +0,0 @@ -package io.github.openflocon.domain.network.usecase.settings - -import io.github.openflocon.domain.device.usecase.GetCurrentDeviceIdAndPackageNameUseCase -import io.github.openflocon.domain.network.models.MockNetworkDomainModel -import io.github.openflocon.domain.network.models.NetworkSettingsDomainModel -import io.github.openflocon.domain.network.repository.NetworkMocksRepository -import io.github.openflocon.domain.network.repository.NetworkSettingsRepository -import io.github.openflocon.domain.network.usecase.mocks.SetupNetworkMocksUseCase - -class GetNetworkSettingsUseCase( - private val getCurrentDeviceIdAndPackageNameUseCase: GetCurrentDeviceIdAndPackageNameUseCase, - private val networkSettingsRepository: NetworkSettingsRepository, -) { - suspend operator fun invoke() : NetworkSettingsDomainModel? { - return getCurrentDeviceIdAndPackageNameUseCase()?.let { deviceIdAndPackageName -> - networkSettingsRepository.getNetworkSettings( - deviceAndApp = deviceIdAndPackageName, - ) - } - } -} diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/settings/ObserveNetworkSettingsUseCase.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/settings/ObserveNetworkSettingsUseCase.kt deleted file mode 100644 index 20bfa6977..000000000 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/settings/ObserveNetworkSettingsUseCase.kt +++ /dev/null @@ -1,24 +0,0 @@ -package io.github.openflocon.domain.network.usecase.settings - -import io.github.openflocon.domain.device.usecase.ObserveCurrentDeviceIdAndPackageNameUseCase -import io.github.openflocon.domain.device.usecase.ObserveCurrentDeviceIdUseCase -import io.github.openflocon.domain.models.TextFilterStateDomainModel -import io.github.openflocon.domain.network.models.NetworkSettingsDomainModel -import io.github.openflocon.domain.network.models.NetworkTextFilterColumns -import io.github.openflocon.domain.network.repository.NetworkFilterRepository -import io.github.openflocon.domain.network.repository.NetworkSettingsRepository -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.flowOf - -class ObserveNetworkSettingsUseCase( - private val observeCurrentDeviceIdAndPackageNameUseCase: ObserveCurrentDeviceIdAndPackageNameUseCase, - private val networkSettingsRepository: NetworkSettingsRepository, -) { - operator fun invoke(): Flow = - observeCurrentDeviceIdAndPackageNameUseCase().flatMapLatest { current -> - if (current == null) flowOf(null) - else networkSettingsRepository.observeNetworkSettings(deviceAndApp = current) - }.distinctUntilChanged() -} diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/settings/UpdateNetworkSettingsUseCase.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/settings/UpdateNetworkSettingsUseCase.kt deleted file mode 100644 index 619eb2e28..000000000 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/network/usecase/settings/UpdateNetworkSettingsUseCase.kt +++ /dev/null @@ -1,24 +0,0 @@ -package io.github.openflocon.domain.network.usecase.settings - -import io.github.openflocon.domain.device.usecase.GetCurrentDeviceIdAndPackageNameUseCase -import io.github.openflocon.domain.network.models.MockNetworkDomainModel -import io.github.openflocon.domain.network.models.NetworkSettingsDomainModel -import io.github.openflocon.domain.network.repository.NetworkMocksRepository -import io.github.openflocon.domain.network.repository.NetworkSettingsRepository -import io.github.openflocon.domain.network.usecase.mocks.SetupNetworkMocksUseCase - -class UpdateNetworkSettingsUseCase( - private val getCurrentDeviceIdAndPackageNameUseCase: GetCurrentDeviceIdAndPackageNameUseCase, - private val networkSettingsRepository: NetworkSettingsRepository, -) { - suspend operator fun invoke( - settings: NetworkSettingsDomainModel, - ) { - getCurrentDeviceIdAndPackageNameUseCase()?.let { deviceIdAndPackageName -> - networkSettingsRepository.updateNetworkSettings( - deviceAndApp = deviceIdAndPackageName, - newValue = settings, - ) - } - } -} From b170a61749e3144f541b4ecf9aafd4ddcbfc2b8e Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Mon, 27 Oct 2025 21:07:38 +0100 Subject: [PATCH 14/28] feature: Rework again --- .../openflocon/flocondesktop/AppWindow.kt | 61 ++++--- .../openflocon/flocondesktop/app/AppAction.kt | 8 +- .../flocondesktop/app/AppUiState.kt | 23 +++ .../flocondesktop/app/AppViewModel.kt | 68 ++++++++ .../flocondesktop/app/ContentUiState.kt | 13 ++ .../features/analytics/Navigation.kt | 17 +- .../features/network/Navigation.kt | 17 +- .../flocondesktop/menu/MenuScene.kt | 159 ++++++++++++++++++ .../menu/ui/model/DevicesStateUiModel.kt | 15 ++ .../navigation/FloconNavigationState.kt | 16 +- .../openflocon/navigation/FloconRoute.kt | 2 + .../openflocon/navigation/scene/PanelScene.kt | 20 ++- 12 files changed, 387 insertions(+), 32 deletions(-) create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppUiState.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ContentUiState.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuScene.kt diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt index 15120e772..06f7cc629 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt @@ -5,10 +5,10 @@ package io.github.openflocon.flocondesktop import androidx.compose.foundation.ComposeFoundationFlags import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.produceState import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation3.scene.DialogSceneStrategy @@ -20,17 +20,21 @@ import io.github.openflocon.domain.adb.repository.AdbRepository import io.github.openflocon.domain.domainModule import io.github.openflocon.domain.settings.usecase.ObserveFontSizeMultiplierUseCase import io.github.openflocon.flocondesktop.adb.AdbRepositoryImpl +import io.github.openflocon.flocondesktop.app.AppAction +import io.github.openflocon.flocondesktop.app.AppUiState import io.github.openflocon.flocondesktop.app.AppViewModel import io.github.openflocon.flocondesktop.app.di.appModule import io.github.openflocon.flocondesktop.common.di.commonModule -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayerView import io.github.openflocon.flocondesktop.core.di.coreModule import io.github.openflocon.flocondesktop.features.analytics.analyticsRoutes import io.github.openflocon.flocondesktop.features.featuresModule +import io.github.openflocon.flocondesktop.features.network.NetworkRoutes import io.github.openflocon.flocondesktop.features.network.networkRoutes -import io.github.openflocon.flocondesktop.menu.MainRoutes +import io.github.openflocon.flocondesktop.menu.MenuSceneStrategy import io.github.openflocon.flocondesktop.menu.di.mainModule -import io.github.openflocon.flocondesktop.menu.menuRoutes +import io.github.openflocon.flocondesktop.menu.ui.buildLeftPanelState +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.LeftPanelView import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.navigation.FloconNavigation import io.github.openflocon.navigation.MainFloconNavigationState @@ -64,7 +68,7 @@ fun App() { // scope { // scoped { MainFloconNavigationState(MainRoutes.Main) } // } - single { MainFloconNavigationState(MainRoutes.Main) } + single { MainFloconNavigationState(NetworkRoutes.Main) } singleOf(::AdbRepositoryImpl) bind AdbRepository::class }, ) @@ -80,9 +84,12 @@ fun App() { fontSizeMultiplier = fontSizeMultiplier ) { val viewModel: AppViewModel = koinViewModel() + val uiState by viewModel.uiState.collectAsStateWithLifecycle() Content( + uiState = uiState, navigationState = viewModel.navigationState, + onAction = viewModel::onAction ) } // } @@ -91,26 +98,36 @@ fun App() { @Composable private fun Content( - navigationState: MainFloconNavigationState + uiState: AppUiState, + navigationState: MainFloconNavigationState, + onAction: (AppAction) -> Unit ) { - Box( + // TODO Redo + val menuState by produceState( + buildLeftPanelState(SubScreen.Network), + uiState.contentState.current + ) { + value = buildLeftPanelState(uiState.contentState.current) + } + + FloconNavigation( + navigationState = navigationState, + sceneStrategy = PanelSceneStrategy() + .then(WindowSceneStrategy()) + .then(DialogSceneStrategy()) + .then(MenuSceneStrategy { + LeftPanelView( + state = menuState, + expanded = it, + onClickItem = { menu -> onAction(AppAction.SelectMenu(menu.screen)) } + ) + }) + .then(SinglePaneSceneStrategy()), modifier = Modifier .fillMaxSize() + .background(FloconTheme.colorPalette.surface) ) { - FloconNavigation( - navigationState = navigationState, - sceneStrategy = PanelSceneStrategy() - .then(WindowSceneStrategy()) - .then(DialogSceneStrategy()) - .then(SinglePaneSceneStrategy()), - modifier = Modifier - .matchParentSize() - .background(FloconTheme.colorPalette.surface) - ) { - menuRoutes() - networkRoutes() - analyticsRoutes() - } - FeedbackDisplayerView() + networkRoutes() + analyticsRoutes() } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt index a9fded2bd..8da46978b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt @@ -1,3 +1,9 @@ package io.github.openflocon.flocondesktop.app -internal sealed interface AppAction +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen + +internal sealed interface AppAction { + + data class SelectMenu(val menu: SubScreen) : AppAction + +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppUiState.kt new file mode 100644 index 000000000..24c034aca --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppUiState.kt @@ -0,0 +1,23 @@ +package io.github.openflocon.flocondesktop.app + +import androidx.compose.runtime.Immutable +import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.previewAppsStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.previewDevicesStateUiModel + +@Immutable +data class AppUiState( + val contentState: ContentUiState, + val deviceState: DevicesStateUiModel, + val appState: AppsStateUiModel, + val recordState: RecordVideoStateUiModel +) + +fun previewAppUiState() = AppUiState( + contentState = previewContentUiState(), + deviceState = previewDevicesStateUiModel(), + appState = previewAppsStateUiModel(), + recordState = RecordVideoStateUiModel.Recording +) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt index 4afec9e08..374584d07 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt @@ -3,11 +3,23 @@ package io.github.openflocon.flocondesktop.app import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import io.github.openflocon.domain.common.DispatcherProvider +import io.github.openflocon.domain.device.usecase.RestartAppUseCase +import io.github.openflocon.domain.device.usecase.TakeScreenshotUseCase +import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.domain.settings.usecase.InitAdbPathUseCase import io.github.openflocon.domain.settings.usecase.StartAdbForwardUseCase +import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed +import io.github.openflocon.flocondesktop.features.analytics.AnalyticsRoutes +import io.github.openflocon.flocondesktop.features.network.NetworkRoutes +import io.github.openflocon.flocondesktop.menu.ui.delegates.DevicesDelegate +import io.github.openflocon.flocondesktop.menu.ui.delegates.RecordVideoDelegate +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen import io.github.openflocon.flocondesktop.messages.ui.MessagesServerDelegate import io.github.openflocon.navigation.MainFloconNavigationState import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.update import kotlinx.coroutines.isActive import kotlinx.coroutines.launch @@ -18,8 +30,41 @@ internal class AppViewModel( val navigationState: MainFloconNavigationState, private val initialSetupStateHolder: InitialSetupStateHolder, dispatcherProvider: DispatcherProvider, + private val devicesDelegate: DevicesDelegate, + private val takeScreenshotUseCase: TakeScreenshotUseCase, + private val restartAppUseCase: RestartAppUseCase, + private val recordVideoDelegate: RecordVideoDelegate, + private val feedbackDisplayer: FeedbackDisplayer ) : ViewModel(messagesServerDelegate) { + private val contentState = MutableStateFlow( + ContentUiState( + current = SubScreen.Network + ) + ) + + val uiState = combine( + contentState, + devicesDelegate.devicesState, + devicesDelegate.appsState, + recordVideoDelegate.state + ) { content, devices, apps, record -> + AppUiState( + contentState = content, + deviceState = devices, + appState = apps, + recordState = record + ) + } + .stateInWhileSubscribed( + AppUiState( + contentState = contentState.value, + deviceState = devicesDelegate.devicesState.value, + appState = devicesDelegate.appsState.value, + recordState = recordVideoDelegate.state.value + ) + ) + init { viewModelScope.launch(dispatcherProvider.viewModel) { initAdbPathUseCase().alsoFailure { @@ -38,5 +83,28 @@ internal class AppViewModel( } } + fun onAction(action: AppAction) { + when (action) { + is AppAction.SelectMenu -> onSelectMenu(action) + } + } + + private fun onSelectMenu(action: AppAction.SelectMenu) { + contentState.update { it.copy(current = action.menu) } + navigationState.menu( + when (action.menu) { + SubScreen.Analytics -> AnalyticsRoutes.Main + SubScreen.Dashboard -> TODO() + SubScreen.Database -> TODO() + SubScreen.Deeplinks -> TODO() + SubScreen.Files -> TODO() + SubScreen.Images -> TODO() + SubScreen.Network -> NetworkRoutes.Main + SubScreen.Settings -> TODO() + SubScreen.SharedPreferences -> TODO() + SubScreen.Tables -> TODO() + } + ) + } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ContentUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ContentUiState.kt new file mode 100644 index 000000000..e3a1ccfa8 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ContentUiState.kt @@ -0,0 +1,13 @@ +package io.github.openflocon.flocondesktop.app + +import androidx.compose.runtime.Immutable +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen + +@Immutable +data class ContentUiState( + val current: SubScreen +) + +fun previewContentUiState() = ContentUiState( + current = SubScreen.Network +) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt index 3d5d34f18..04401257d 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt @@ -1,8 +1,23 @@ package io.github.openflocon.flocondesktop.features.analytics import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.features.analytics.view.AnalyticsScreen +import io.github.openflocon.flocondesktop.menu.MenuSceneStrategy +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen import io.github.openflocon.navigation.FloconRoute +import kotlinx.serialization.Serializable + +sealed interface AnalyticsRoutes : FloconRoute { + + @Serializable + data object Main : AnalyticsRoutes + +} fun EntryProviderScope.analyticsRoutes() { - // TODO + entry( + metadata = MenuSceneStrategy.menu(SubScreen.Analytics) + ) { + AnalyticsScreen() + } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt index 0b29483bf..4eef07640 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt @@ -3,19 +3,32 @@ package io.github.openflocon.flocondesktop.features.network import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.domain.settings.repository.SettingsRepository import io.github.openflocon.flocondesktop.features.network.detail.view.NetworkDetailScreen +import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen +import io.github.openflocon.flocondesktop.menu.MenuScene +import io.github.openflocon.flocondesktop.menu.MenuSceneStrategy +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen import io.github.openflocon.navigation.FloconRoute +import io.github.openflocon.navigation.PanelRoute import io.github.openflocon.navigation.scene.PanelSceneStrategy import kotlinx.serialization.Serializable import org.koin.mp.KoinPlatform -internal sealed interface NetworkRoutes : FloconRoute { +internal sealed interface NetworkRoutes { @Serializable - data class Panel(val requestId: String) : FloconRoute + data object Main : PanelRoute + + @Serializable + data class Panel(val requestId: String) : PanelRoute } fun EntryProviderScope.networkRoutes() { + entry( + metadata = MenuSceneStrategy.menu(SubScreen.Network) + ) { + NetworkScreen() + } entry( metadata = PanelSceneStrategy.panel( pinnable = true, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuScene.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuScene.kt new file mode 100644 index 000000000..0c1ddac30 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuScene.kt @@ -0,0 +1,159 @@ +package io.github.openflocon.flocondesktop.menu + +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.ChevronRight +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.dp +import androidx.navigation3.runtime.NavEntry +import androidx.navigation3.scene.Scene +import androidx.navigation3.scene.SceneStrategy +import androidx.navigation3.scene.SceneStrategyScope +import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.PanelMaxWidth +import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.PanelMinWidth +import io.github.openflocon.flocondesktop.menu.ui.view.topbar.MainScreenTopBar +import io.github.openflocon.library.designsystem.FloconTheme +import io.github.openflocon.library.designsystem.components.FloconIcon +import io.github.openflocon.library.designsystem.components.FloconScaffold +import io.github.openflocon.navigation.FloconRoute + +@Immutable +data class MenuScene( + override val entries: List>, + override val previousEntries: List>, + val entry: NavEntry, + val screen: SubScreen, + val menuContent: @Composable (expanded: Boolean) -> Unit +) : Scene { + override val key: Any + get() = Unit + + override val content: @Composable (() -> Unit) = { + var expanded by remember { mutableStateOf(false) } + val width by animateDpAsState(targetValue = if (expanded) PanelMaxWidth else PanelMinWidth) + var windowSize by remember { mutableStateOf(IntSize.Zero) } + val position by animateDpAsState( + targetValue = if (expanded) PanelMaxWidth else PanelMinWidth, + ) + val rotate by animateFloatAsState(targetValue = if (expanded) 180f else 0f) + + Box { + FloconScaffold( + topBar = { + MainScreenTopBar( + devicesState = DevicesStateUiModel.Empty, + appsState = AppsStateUiModel.Empty, + recordState = RecordVideoStateUiModel.Recording, + deleteApp = {}, + deleteDevice = {}, + onDeviceSelected = {}, + onAppSelected = {}, + onRecordClicked = {}, + onRestartClicked = {}, + onTakeScreenshotClicked = {} + ) + }, + modifier = Modifier + .fillMaxSize() + .onGloballyPositioned { + windowSize = it.size // TODO Add windowsize lib + } + ) { padding -> + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier + .fillMaxSize() + .padding(padding) + .padding(8.dp) + ) { + Box( + modifier = Modifier + .width(width) + .fillMaxHeight(), + ) { + menuContent(expanded) + } + entry.Content() + } + } + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .width(20.dp) + .height(60.dp) + .graphicsLayer { + translationX = position.toPx() - size.width / 2 - 2.dp.toPx() + translationY = (windowSize.height / 4f).times(3f) + (size.height / 2f) + } + .clip(RoundedCornerShape(topStart = 4.dp, bottomStart = 4.dp)) + .background(FloconTheme.colorPalette.secondary) + .clickable(onClick = { expanded = !expanded }), + ) { + FloconIcon( + imageVector = Icons.Outlined.ChevronRight, + tint = Color.LightGray, + modifier = Modifier.rotate(rotate), + ) + } + } + } +} + +class MenuSceneStrategy( + private val menuContent: @Composable (expanded: Boolean) -> Unit +) : SceneStrategy { + + override fun SceneStrategyScope.calculateScene(entries: List>): Scene? { + val entry = entries.lastOrNull() ?: return null + val menu = entry.metadata[MENU_KEY] ?: return null + + if (menu is SubScreen) { + return MenuScene( + entries = listOf(entry), + previousEntries = entries.dropLast(1), + entry = entry, + screen = menu, + menuContent = menuContent + ) + } + + return null + } + + companion object { + private const val MENU_KEY = "menu_key" + + fun menu(menu: SubScreen) = mapOf(MENU_KEY to menu) + + } + +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DevicesStateUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DevicesStateUiModel.kt index 0187530bb..190e82d74 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DevicesStateUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DevicesStateUiModel.kt @@ -86,3 +86,18 @@ fun previewDevicesStateUiModel(): DevicesStateUiModel = DevicesStateUiModel.With canRestart = true, ), ) + +fun previewAppsStateUiModel(): AppsStateUiModel = AppsStateUiModel.WithApps( + apps = listOf( + DeviceAppUiModel( + name = "appName1", + packageName = "packageName", + iconEncoded = null + ) + ), + appSelected = DeviceAppUiModel( + name = "appName1", + packageName = "packageName", + iconEncoded = null + ) +) diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt index 63308611a..78f02a49a 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt @@ -17,11 +17,25 @@ class MainFloconNavigationState(initialScreen: FloconRoute = LoadingRoute) : Flo override val stack: SnapshotStateList = _stack override fun navigate(route: FloconRoute) { - _stack.add(route) + if (route is PanelRoute) { + val index = _stack.indexOfFirst { it is PanelRoute } + + if (index != -1) { + _stack[index] = route + } else { + _stack.add(route) + } + } else { + _stack.add(route) + } } override fun back(count: Int) { repeat(count) { _stack.removeLast() } } + fun menu(route: FloconRoute) { + _stack[0] = route + } + } diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconRoute.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconRoute.kt index 51b4f4369..49e4c8590 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconRoute.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconRoute.kt @@ -3,3 +3,5 @@ package io.github.openflocon.navigation import androidx.navigation3.runtime.NavKey interface FloconRoute : NavKey + +interface PanelRoute : FloconRoute diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt index 0eb7a5667..00fe8b133 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt @@ -4,9 +4,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Close -import androidx.compose.material.icons.outlined.Pin -import androidx.compose.material.icons.sharp.Pin -import androidx.compose.material.icons.sharp.PinInvoke import androidx.compose.material.icons.sharp.PushPin import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable @@ -88,6 +85,8 @@ data class PanelScene( class PanelSceneStrategy : SceneStrategy { + var currentScene: PanelScene? = null + override fun SceneStrategyScope.calculateScene( entries: List> ): Scene? { @@ -95,15 +94,26 @@ class PanelSceneStrategy : SceneStrategy { val properties = lastEntry.metadata[PANEL_KEY] ?: return null if (properties is PaneProperties) { - return PanelScene( + return currentScene?.copy( + key = lastEntry.contentKey, + previousEntries = entries.dropLast(1), + overlaidEntries = entries.dropLast(1), + entry = lastEntry, + properties = properties, + onPin = lastEntry.metadata[ON_PIN] as? OnPin + ) ?: PanelScene( key = lastEntry.contentKey, previousEntries = entries.dropLast(1), overlaidEntries = entries.dropLast(1), entry = lastEntry, properties = properties, onPin = lastEntry.metadata[ON_PIN] as? OnPin, - onBack = { onBack() } + onBack = { + currentScene = null + onBack() + } ) + .also { currentScene = it } } return null From 1c9598e609735f7b510085f25ee5cc3397da68cf Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 29 Oct 2025 13:51:59 +0100 Subject: [PATCH 15/28] feature: Rework --- .../openflocon/flocondesktop/AppWindow.kt | 67 +------ .../openflocon/flocondesktop/app/AppAction.kt | 2 +- .../openflocon/flocondesktop/app/AppScreen.kt | 71 +++++++ .../flocondesktop/app/AppUiState.kt | 10 +- .../flocondesktop/app/AppViewModel.kt | 6 +- .../flocondesktop/app/ContentUiState.kt | 2 +- .../openflocon/flocondesktop/app/MenuScene.kt | 159 +++++++++++++++ .../flocondesktop/app/di/AppUiModule.kt | 14 +- .../{menu => app}/ui/MenuUiState.kt | 14 +- .../{menu => app}/ui/MenuViewModel.kt | 31 ++- .../ui/delegates/DevicesDelegate.kt | 8 +- .../{menu => app}/ui/delegates/Mapper.kt | 6 +- .../ui/delegates/RecordVideoDelegate.kt | 4 +- .../app/{models => ui/model}/AppUiState.kt | 2 +- .../ui/model/DeviceAppUiModel.kt | 2 +- .../ui/model/DeviceItemUiModel.kt | 2 +- .../ui/model/DevicesStateUiModel.kt | 2 +- .../ui/model/RecordVideoStateUiModel.kt | 2 +- .../{menu => app}/ui/model/SubScreen.kt | 2 +- .../ui/model/leftpanel/LeftPanelItem.kt | 5 +- .../ui/model/leftpanel/LeftPannelSection.kt | 2 +- .../ui/model/leftpanel/MenuUiState.kt | 14 +- .../{menu => app}/ui/settings/AboutScreen.kt | 2 +- .../{menu => app}/ui/settings/Navigation.kt | 2 +- .../ui/settings/SettingsAction.kt | 2 +- .../ui/settings/SettingsScreen.kt | 2 +- .../ui/settings/SettingsUiState.kt | 2 +- .../ui/settings/SettingsViewModel.kt | 2 +- .../ui/view/SubScreenSelectorItem.kt | 4 +- .../ui/view/leftpannel/LeftPannelDivider.kt | 2 +- .../ui/view/leftpannel/LeftPannelView.kt | 14 +- .../ui/view/leftpannel/PannelLabel.kt | 2 +- .../ui/view/leftpannel/PannelView.kt | 4 +- .../ui/view/topbar/MainScreenTopBar.kt | 14 +- .../ui/view/topbar/TopBarDeviceAndAppView.kt | 14 +- .../ui/view/topbar/TopBarSelector.kt | 2 +- .../ui/view/topbar/actions/TopBarActions.kt | 6 +- .../ui/view/topbar/actions/TopBarButton.kt | 2 +- .../ui/view/topbar/app/TopBarAppDropdown.kt | 11 +- .../ui/view/topbar/app/TopBarAppView.kt | 6 +- .../topbar/device/TopBarDeviceDropdown.kt | 10 +- .../ui/view/topbar/device/TopBarDeviceView.kt | 10 +- .../features/analytics/Navigation.kt | 2 +- .../features/network/Navigation.kt | 3 +- .../flocondesktop/menu/MenuRoutes.kt | 41 ---- .../flocondesktop/menu/MenuScene.kt | 14 +- .../flocondesktop/menu/di/MainModule.kt | 10 - .../menu/ui/MenuNavigationState.kt | 19 -- .../flocondesktop/menu/ui/MenuScreen.kt | 185 ------------------ .../flocondesktop/menu/ui/di/MainUiModule.kt | 24 --- .../github/openflocon/flocondesktop/Main.kt | 2 +- 51 files changed, 361 insertions(+), 479 deletions(-) create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/MenuUiState.kt (50%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/MenuViewModel.kt (83%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/delegates/DevicesDelegate.kt (95%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/delegates/Mapper.kt (89%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/delegates/RecordVideoDelegate.kt (94%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/{models => ui/model}/AppUiState.kt (75%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/model/DeviceAppUiModel.kt (84%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/model/DeviceItemUiModel.kt (91%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/model/DevicesStateUiModel.kt (97%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/model/RecordVideoStateUiModel.kt (53%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/model/SubScreen.kt (91%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/model/leftpanel/LeftPanelItem.kt (59%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/model/leftpanel/LeftPannelSection.kt (57%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/model/leftpanel/MenuUiState.kt (79%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/settings/AboutScreen.kt (97%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/settings/Navigation.kt (84%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/settings/SettingsAction.kt (65%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/settings/SettingsScreen.kt (99%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/settings/SettingsUiState.kt (76%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/settings/SettingsViewModel.kt (98%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/SubScreenSelectorItem.kt (93%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/leftpannel/LeftPannelDivider.kt (87%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/leftpannel/LeftPannelView.kt (87%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/leftpannel/PannelLabel.kt (95%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/leftpannel/PannelView.kt (96%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/topbar/MainScreenTopBar.kt (85%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/topbar/TopBarDeviceAndAppView.kt (72%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/topbar/TopBarSelector.kt (96%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/topbar/actions/TopBarActions.kt (90%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/topbar/actions/TopBarButton.kt (92%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/topbar/app/TopBarAppDropdown.kt (90%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/topbar/app/TopBarAppView.kt (95%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/topbar/device/TopBarDeviceDropdown.kt (89%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/{menu => app}/ui/view/topbar/device/TopBarDeviceView.kt (96%) delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/di/MainModule.kt delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuNavigationState.kt delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/di/MainUiModule.kt diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt index 06f7cc629..6a54d6023 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/AppWindow.kt @@ -4,15 +4,9 @@ package io.github.openflocon.flocondesktop import androidx.compose.foundation.ComposeFoundationFlags import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.produceState -import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation3.scene.DialogSceneStrategy -import androidx.navigation3.scene.SinglePaneSceneStrategy import com.flocon.data.remote.dataRemoteModule import io.github.openflocon.data.core.dataCoreModule import io.github.openflocon.data.local.dataLocalModule @@ -20,29 +14,16 @@ import io.github.openflocon.domain.adb.repository.AdbRepository import io.github.openflocon.domain.domainModule import io.github.openflocon.domain.settings.usecase.ObserveFontSizeMultiplierUseCase import io.github.openflocon.flocondesktop.adb.AdbRepositoryImpl -import io.github.openflocon.flocondesktop.app.AppAction -import io.github.openflocon.flocondesktop.app.AppUiState -import io.github.openflocon.flocondesktop.app.AppViewModel +import io.github.openflocon.flocondesktop.app.AppScreen import io.github.openflocon.flocondesktop.app.di.appModule import io.github.openflocon.flocondesktop.common.di.commonModule import io.github.openflocon.flocondesktop.core.di.coreModule -import io.github.openflocon.flocondesktop.features.analytics.analyticsRoutes import io.github.openflocon.flocondesktop.features.featuresModule import io.github.openflocon.flocondesktop.features.network.NetworkRoutes -import io.github.openflocon.flocondesktop.features.network.networkRoutes -import io.github.openflocon.flocondesktop.menu.MenuSceneStrategy -import io.github.openflocon.flocondesktop.menu.di.mainModule -import io.github.openflocon.flocondesktop.menu.ui.buildLeftPanelState -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen -import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.LeftPanelView import io.github.openflocon.library.designsystem.FloconTheme -import io.github.openflocon.navigation.FloconNavigation import io.github.openflocon.navigation.MainFloconNavigationState -import io.github.openflocon.navigation.scene.PanelSceneStrategy -import io.github.openflocon.navigation.scene.WindowSceneStrategy import org.koin.compose.KoinApplication import org.koin.compose.koinInject -import org.koin.compose.viewmodel.koinViewModel import org.koin.core.module.dsl.singleOf import org.koin.dsl.bind import org.koin.dsl.module @@ -57,7 +38,6 @@ fun App() { commonModule, appModule, coreModule, - mainModule, featuresModule, domainModule, dataCoreModule, @@ -83,51 +63,8 @@ fun App() { FloconTheme( fontSizeMultiplier = fontSizeMultiplier ) { - val viewModel: AppViewModel = koinViewModel() - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - - Content( - uiState = uiState, - navigationState = viewModel.navigationState, - onAction = viewModel::onAction - ) + AppScreen() } // } } } - -@Composable -private fun Content( - uiState: AppUiState, - navigationState: MainFloconNavigationState, - onAction: (AppAction) -> Unit -) { - // TODO Redo - val menuState by produceState( - buildLeftPanelState(SubScreen.Network), - uiState.contentState.current - ) { - value = buildLeftPanelState(uiState.contentState.current) - } - - FloconNavigation( - navigationState = navigationState, - sceneStrategy = PanelSceneStrategy() - .then(WindowSceneStrategy()) - .then(DialogSceneStrategy()) - .then(MenuSceneStrategy { - LeftPanelView( - state = menuState, - expanded = it, - onClickItem = { menu -> onAction(AppAction.SelectMenu(menu.screen)) } - ) - }) - .then(SinglePaneSceneStrategy()), - modifier = Modifier - .fillMaxSize() - .background(FloconTheme.colorPalette.surface) - ) { - networkRoutes() - analyticsRoutes() - } -} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt index 8da46978b..bbcab3582 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt @@ -1,6 +1,6 @@ package io.github.openflocon.flocondesktop.app -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen internal sealed interface AppAction { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt new file mode 100644 index 000000000..b5913403d --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt @@ -0,0 +1,71 @@ +package io.github.openflocon.flocondesktop.app + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.produceState +import androidx.compose.ui.Modifier +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation3.scene.DialogSceneStrategy +import androidx.navigation3.scene.SinglePaneSceneStrategy +import io.github.openflocon.flocondesktop.app.ui.buildLeftPanelState +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.LeftPanelView +import io.github.openflocon.flocondesktop.features.analytics.analyticsRoutes +import io.github.openflocon.flocondesktop.features.network.networkRoutes +import io.github.openflocon.flocondesktop.menu.MenuSceneStrategy +import io.github.openflocon.library.designsystem.FloconTheme +import io.github.openflocon.navigation.FloconNavigation +import io.github.openflocon.navigation.MainFloconNavigationState +import io.github.openflocon.navigation.scene.PanelSceneStrategy +import io.github.openflocon.navigation.scene.WindowSceneStrategy +import org.koin.compose.viewmodel.koinViewModel + +@Composable +fun AppScreen() { + val viewModel = koinViewModel() + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + Content( + uiState = uiState, + navigationState = viewModel.navigationState, + onAction = viewModel::onAction + ) +} + +@Composable +private fun Content( + uiState: AppUiState, + navigationState: MainFloconNavigationState, + onAction: (AppAction) -> Unit +) { + // TODO Redo + val menuState by produceState( + buildLeftPanelState(SubScreen.Network), + uiState.contentState.current + ) { + value = buildLeftPanelState(uiState.contentState.current) + } + + FloconNavigation( + navigationState = navigationState, + sceneStrategy = PanelSceneStrategy() + .then(WindowSceneStrategy()) + .then(DialogSceneStrategy()) + .then(MenuSceneStrategy { + LeftPanelView( + state = menuState, + expanded = it, + onClickItem = { menu -> onAction(AppAction.SelectMenu(menu.screen)) } + ) + }) + .then(SinglePaneSceneStrategy()), + modifier = Modifier + .fillMaxSize() + .background(FloconTheme.colorPalette.surface) + ) { + networkRoutes() + analyticsRoutes() + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppUiState.kt index 24c034aca..fd8ede054 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppUiState.kt @@ -1,11 +1,11 @@ package io.github.openflocon.flocondesktop.app import androidx.compose.runtime.Immutable -import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.previewAppsStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.previewDevicesStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.previewAppsStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.previewDevicesStateUiModel @Immutable data class AppUiState( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt index 374584d07..af4b6c3d5 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt @@ -8,12 +8,12 @@ import io.github.openflocon.domain.device.usecase.TakeScreenshotUseCase import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.domain.settings.usecase.InitAdbPathUseCase import io.github.openflocon.domain.settings.usecase.StartAdbForwardUseCase +import io.github.openflocon.flocondesktop.app.ui.delegates.DevicesDelegate +import io.github.openflocon.flocondesktop.app.ui.delegates.RecordVideoDelegate +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed import io.github.openflocon.flocondesktop.features.analytics.AnalyticsRoutes import io.github.openflocon.flocondesktop.features.network.NetworkRoutes -import io.github.openflocon.flocondesktop.menu.ui.delegates.DevicesDelegate -import io.github.openflocon.flocondesktop.menu.ui.delegates.RecordVideoDelegate -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen import io.github.openflocon.flocondesktop.messages.ui.MessagesServerDelegate import io.github.openflocon.navigation.MainFloconNavigationState import kotlinx.coroutines.delay diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ContentUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ContentUiState.kt index e3a1ccfa8..f6d17b757 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ContentUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ContentUiState.kt @@ -1,7 +1,7 @@ package io.github.openflocon.flocondesktop.app import androidx.compose.runtime.Immutable -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen @Immutable data class ContentUiState( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt new file mode 100644 index 000000000..16dda6e9c --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt @@ -0,0 +1,159 @@ +package io.github.openflocon.flocondesktop.app + +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.ChevronRight +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.dp +import androidx.navigation3.runtime.NavEntry +import androidx.navigation3.scene.Scene +import androidx.navigation3.scene.SceneStrategy +import androidx.navigation3.scene.SceneStrategyScope +import io.github.openflocon.flocondesktop.app.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.PanelMaxWidth +import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.PanelMinWidth +import io.github.openflocon.flocondesktop.app.ui.view.topbar.MainScreenTopBar +import io.github.openflocon.library.designsystem.FloconTheme +import io.github.openflocon.library.designsystem.components.FloconIcon +import io.github.openflocon.library.designsystem.components.FloconScaffold +import io.github.openflocon.navigation.FloconRoute + +@Immutable +data class MenuScene( + override val entries: List>, + override val previousEntries: List>, + val entry: NavEntry, + val screen: SubScreen, + val menuContent: @Composable (expanded: Boolean) -> Unit +) : Scene { + override val key: Any + get() = Unit + + override val content: @Composable (() -> Unit) = { + var expanded by remember { mutableStateOf(false) } + val width by animateDpAsState(targetValue = if (expanded) PanelMaxWidth else PanelMinWidth) + var windowSize by remember { mutableStateOf(IntSize.Zero) } + val position by animateDpAsState( + targetValue = if (expanded) PanelMaxWidth else PanelMinWidth, + ) + val rotate by animateFloatAsState(targetValue = if (expanded) 180f else 0f) + + Box { + FloconScaffold( + topBar = { + MainScreenTopBar( + devicesState = DevicesStateUiModel.Empty, + appsState = AppsStateUiModel.Empty, + recordState = RecordVideoStateUiModel.Recording, + deleteApp = {}, + deleteDevice = {}, + onDeviceSelected = {}, + onAppSelected = {}, + onRecordClicked = {}, + onRestartClicked = {}, + onTakeScreenshotClicked = {} + ) + }, + modifier = Modifier + .fillMaxSize() + .onGloballyPositioned { + windowSize = it.size // TODO Add windowsize lib + } + ) { padding -> + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier + .fillMaxSize() + .padding(padding) + .padding(8.dp) + ) { + Box( + modifier = Modifier + .width(width) + .fillMaxHeight(), + ) { + menuContent(expanded) + } + entry.Content() + } + } + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .width(20.dp) + .height(60.dp) + .graphicsLayer { + translationX = position.toPx() - size.width / 2 - 2.dp.toPx() + translationY = (windowSize.height / 4f).times(3f) + (size.height / 2f) + } + .clip(RoundedCornerShape(topStart = 4.dp, bottomStart = 4.dp)) + .background(FloconTheme.colorPalette.secondary) + .clickable(onClick = { expanded = !expanded }), + ) { + FloconIcon( + imageVector = Icons.Outlined.ChevronRight, + tint = Color.LightGray, + modifier = Modifier.rotate(rotate), + ) + } + } + } +} + +class MenuSceneStrategy( + private val menuContent: @Composable (expanded: Boolean) -> Unit +) : SceneStrategy { + + override fun SceneStrategyScope.calculateScene(entries: List>): Scene? { + val entry = entries.lastOrNull() ?: return null + val menu = entry.metadata[MENU_KEY] ?: return null + + if (menu is SubScreen) { + return MenuScene( + entries = listOf(entry), + previousEntries = entries.dropLast(1), + entry = entry, + screen = menu, + menuContent = menuContent + ) + } + + return null + } + + companion object { + private const val MENU_KEY = "menu_key" + + fun menu(menu: SubScreen) = mapOf(MENU_KEY to menu) + + } + +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/di/AppUiModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/di/AppUiModule.kt index d07305e38..78498b84c 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/di/AppUiModule.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/di/AppUiModule.kt @@ -1,12 +1,16 @@ package io.github.openflocon.flocondesktop.app.di import io.github.openflocon.flocondesktop.app.AppViewModel +import io.github.openflocon.flocondesktop.app.ui.delegates.DevicesDelegate +import io.github.openflocon.flocondesktop.app.ui.delegates.RecordVideoDelegate import io.github.openflocon.flocondesktop.app.version.VersionCheckerViewModel +import org.koin.core.module.dsl.factoryOf import org.koin.core.module.dsl.viewModelOf import org.koin.dsl.module -val appUiModule = - module { - viewModelOf(::AppViewModel) - viewModelOf(::VersionCheckerViewModel) - } +val appUiModule = module { + viewModelOf(::AppViewModel) + factoryOf(::DevicesDelegate) + factoryOf(::RecordVideoDelegate) + viewModelOf(::VersionCheckerViewModel) +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuUiState.kt similarity index 50% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuUiState.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuUiState.kt index 69e1d6c0c..f29ca47ec 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuUiState.kt @@ -1,12 +1,12 @@ -package io.github.openflocon.flocondesktop.menu.ui +package io.github.openflocon.flocondesktop.app.ui import androidx.compose.runtime.Immutable -import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen -import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelState -import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.previewLeftPannelState +import io.github.openflocon.flocondesktop.app.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPanelState +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.previewLeftPannelState @Immutable data class MenuUiState( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuViewModel.kt similarity index 83% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuViewModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuViewModel.kt index dbc536f90..872af184b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuViewModel.kt @@ -1,26 +1,24 @@ -package io.github.openflocon.flocondesktop.menu.ui +package io.github.openflocon.flocondesktop.app.ui import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import io.github.openflocon.domain.common.DispatcherProvider -import io.github.openflocon.domain.common.combines -import io.github.openflocon.domain.device.models.DeviceCapabilitiesDomainModel import io.github.openflocon.domain.device.usecase.ObserveCurrentDeviceCapabilitiesUseCase import io.github.openflocon.domain.device.usecase.RestartAppUseCase import io.github.openflocon.domain.device.usecase.TakeScreenshotUseCase import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.app.InitialSetupStateHolder +import io.github.openflocon.flocondesktop.app.ui.delegates.DevicesDelegate +import io.github.openflocon.flocondesktop.app.ui.delegates.RecordVideoDelegate +import io.github.openflocon.flocondesktop.app.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPanelItem +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPanelState +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPannelSection +import io.github.openflocon.flocondesktop.app.ui.view.displayName +import io.github.openflocon.flocondesktop.app.ui.view.icon import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed -import io.github.openflocon.flocondesktop.menu.ui.delegates.DevicesDelegate -import io.github.openflocon.flocondesktop.menu.ui.delegates.RecordVideoDelegate -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen -import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelItem -import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelState -import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPannelSection -import io.github.openflocon.flocondesktop.menu.ui.view.displayName -import io.github.openflocon.flocondesktop.menu.ui.view.icon import io.github.openflocon.navigation.MainFloconNavigationState import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine @@ -71,7 +69,7 @@ class MenuViewModel( viewModelScope.launch(dispatcherProvider.viewModel) { initialSetupStateHolder.needsAdbSetup.collect { if (it) { - menuNavigationState.navigate(SubScreen.Settings) +// menuNavigationState.navigate(SubScreen.Settings) leftPanelState.update { state -> state.copy(current = SubScreen.Settings) } } } @@ -104,7 +102,7 @@ class MenuViewModel( fun onClickLeftPanelItem(leftPanelItem: LeftPanelItem) { leftPanelState.update { state -> state.copy(current = leftPanelItem.screen) } - menuNavigationState.navigate(leftPanelItem.screen) +// menuNavigationState.navigate(leftPanelItem.screen) } fun onRecordClicked() { @@ -177,6 +175,7 @@ private fun item( return LeftPanelItem( screen = subScreen, icon = subScreen.icon(), - text = subScreen.displayName() + text = subScreen.displayName(), + isEnabled = true ) } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/DevicesDelegate.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/delegates/DevicesDelegate.kt similarity index 95% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/DevicesDelegate.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/delegates/DevicesDelegate.kt index cde372f68..6f45f703e 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/DevicesDelegate.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/delegates/DevicesDelegate.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.delegates +package io.github.openflocon.flocondesktop.app.ui.delegates import io.github.openflocon.domain.device.usecase.DeleteDeviceApplicationUseCase import io.github.openflocon.domain.device.usecase.DeleteDeviceUseCase @@ -11,10 +11,10 @@ import io.github.openflocon.domain.device.usecase.ObserveCurrentDeviceIdUseCase import io.github.openflocon.domain.device.usecase.ObserveDevicesUseCase import io.github.openflocon.domain.device.usecase.SelectDeviceAppUseCase import io.github.openflocon.domain.device.usecase.SelectDeviceUseCase +import io.github.openflocon.flocondesktop.app.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableDelegate import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableScoped -import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine @@ -86,7 +86,7 @@ class DevicesDelegate( // do this only if we have 1 unique active device observeActiveDevicesUseCase().distinctUntilChanged().onEach { activeDevices -> val currentDeviceId = getCurrentDeviceIdAndPackageNameUseCase()?.deviceId - if(activeDevices.size == 1 && currentDeviceId !in activeDevices.map { it.deviceId }) { + if (activeDevices.size == 1 && currentDeviceId !in activeDevices.map { it.deviceId }) { val firstActiveDevice = activeDevices.first() select(firstActiveDevice.deviceId) } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/Mapper.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/delegates/Mapper.kt similarity index 89% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/Mapper.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/delegates/Mapper.kt index 48de72144..141406900 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/Mapper.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/delegates/Mapper.kt @@ -1,11 +1,11 @@ -package io.github.openflocon.flocondesktop.menu.ui.delegates +package io.github.openflocon.flocondesktop.app.ui.delegates import io.github.openflocon.domain.device.models.DeviceAppDomainModel import io.github.openflocon.domain.device.models.DeviceCapabilitiesDomainModel import io.github.openflocon.domain.device.models.DeviceDomainModel import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DeviceItemUiModel internal fun mapListToUi( devices: List, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/RecordVideoDelegate.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/delegates/RecordVideoDelegate.kt similarity index 94% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/RecordVideoDelegate.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/delegates/RecordVideoDelegate.kt index 052fe1d38..107d19b9b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/delegates/RecordVideoDelegate.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/delegates/RecordVideoDelegate.kt @@ -1,13 +1,13 @@ -package io.github.openflocon.flocondesktop.menu.ui.delegates +package io.github.openflocon.flocondesktop.app.ui.delegates import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.device.models.RecordingDomainModel import io.github.openflocon.domain.device.usecase.StartRecordingVideoUseCase import io.github.openflocon.domain.device.usecase.StopRecordingVideoUseCase import io.github.openflocon.domain.feedback.FeedbackDisplayer +import io.github.openflocon.flocondesktop.app.ui.model.RecordVideoStateUiModel import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableDelegate import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableScoped -import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed import kotlinx.coroutines.flow.StateFlow diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/AppUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/AppUiState.kt similarity index 75% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/AppUiState.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/AppUiState.kt index 880c1e759..260f851e4 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/models/AppUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/AppUiState.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.app.models +package io.github.openflocon.flocondesktop.app.ui.model import androidx.compose.runtime.Immutable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DeviceAppUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/DeviceAppUiModel.kt similarity index 84% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DeviceAppUiModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/DeviceAppUiModel.kt index fe2a83a3b..c1ed82c44 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DeviceAppUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/DeviceAppUiModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.model +package io.github.openflocon.flocondesktop.app.ui.model import androidx.compose.runtime.Immutable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DeviceItemUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/DeviceItemUiModel.kt similarity index 91% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DeviceItemUiModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/DeviceItemUiModel.kt index f054a4feb..f76be5d0e 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DeviceItemUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/DeviceItemUiModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.model +package io.github.openflocon.flocondesktop.app.ui.model import androidx.compose.runtime.Immutable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DevicesStateUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/DevicesStateUiModel.kt similarity index 97% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DevicesStateUiModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/DevicesStateUiModel.kt index 190e82d74..a86e7c08c 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/DevicesStateUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/DevicesStateUiModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.model +package io.github.openflocon.flocondesktop.app.ui.model import androidx.compose.runtime.Immutable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/RecordVideoStateUiModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/RecordVideoStateUiModel.kt similarity index 53% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/RecordVideoStateUiModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/RecordVideoStateUiModel.kt index a08293303..716ffbef9 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/RecordVideoStateUiModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/RecordVideoStateUiModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.model +package io.github.openflocon.flocondesktop.app.ui.model enum class RecordVideoStateUiModel { Idle, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/SubScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/SubScreen.kt similarity index 91% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/SubScreen.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/SubScreen.kt index 81f97ea97..2fa0d345f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/SubScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/SubScreen.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.model +package io.github.openflocon.flocondesktop.app.ui.model sealed interface SubScreen { data object Dashboard : SubScreen diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/LeftPanelItem.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/LeftPanelItem.kt similarity index 59% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/LeftPanelItem.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/LeftPanelItem.kt index 6b61924dc..f27edbe73 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/LeftPanelItem.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/LeftPanelItem.kt @@ -1,14 +1,13 @@ -package io.github.openflocon.flocondesktop.menu.ui.model.leftpanel +package io.github.openflocon.flocondesktop.app.ui.model.leftpanel import androidx.compose.runtime.Immutable import androidx.compose.ui.graphics.vector.ImageVector -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen @Immutable data class LeftPanelItem( val screen: SubScreen, val icon: ImageVector, val text: String, - val isSelected: Boolean, val isEnabled: Boolean, ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/LeftPannelSection.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/LeftPannelSection.kt similarity index 57% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/LeftPannelSection.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/LeftPannelSection.kt index ece731ff1..a65c7c373 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/LeftPannelSection.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/LeftPannelSection.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.model.leftpanel +package io.github.openflocon.flocondesktop.app.ui.model.leftpanel data class LeftPannelSection( val title: String, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/MenuUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/MenuUiState.kt similarity index 79% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/MenuUiState.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/MenuUiState.kt index 0b5163bb3..dc2fd2b79 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/model/leftpanel/MenuUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/MenuUiState.kt @@ -1,10 +1,9 @@ -package io.github.openflocon.flocondesktop.menu.ui.model.leftpanel +package io.github.openflocon.flocondesktop.app.ui.model.leftpanel import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.Analytics import androidx.compose.material.icons.outlined.Settings import androidx.compose.runtime.Immutable -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen @Immutable data class LeftPanelState( @@ -20,7 +19,6 @@ fun previewLeftPannelState(current: SubScreen) = LeftPanelState( screen = SubScreen.Settings, icon = Icons.Outlined.Settings, text = "Settings", - isSelected = selectedId == "Settings", isEnabled = true, ), ), @@ -32,21 +30,18 @@ fun previewLeftPannelState(current: SubScreen) = LeftPanelState( screen = SubScreen.Network, icon = Icons.Outlined.Settings, text = "Http", - isSelected = selectedId == "Http", isEnabled = true, ), LeftPanelItem( screen = SubScreen.Images, icon = Icons.Outlined.Settings, text = "Images", - isSelected = selectedId == "Images", isEnabled = true, ), LeftPanelItem( screen = SubScreen.Network, icon = Icons.Outlined.Settings, text = "Grpc", - isSelected = selectedId == "Grpc", isEnabled = true, ), ), @@ -58,21 +53,18 @@ fun previewLeftPannelState(current: SubScreen) = LeftPanelState( screen = SubScreen.Network, icon = Icons.Outlined.Settings, text = "Database", - isSelected = selectedId == "Database", isEnabled = true, ), LeftPanelItem( screen = SubScreen.SharedPreferences, icon = Icons.Outlined.Settings, text = "SharedPreferences", - isSelected = selectedId == "SharedPreferences", isEnabled = true, ), LeftPanelItem( screen = SubScreen.Files, icon = Icons.Outlined.Settings, text = "Files", - isSelected = selectedId == "Files", isEnabled = true, ), ), @@ -84,14 +76,12 @@ fun previewLeftPannelState(current: SubScreen) = LeftPanelState( screen = SubScreen.Dashboard, icon = Icons.Outlined.Settings, text = "Dashboard", - isSelected = selectedId == "Dashboard", isEnabled = true, ), LeftPanelItem( screen = SubScreen.Tables, icon = Icons.Outlined.Settings, text = "Tables", - isSelected = selectedId == "Tables", isEnabled = true, ), ), diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/AboutScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/AboutScreen.kt similarity index 97% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/AboutScreen.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/AboutScreen.kt index 0dc692724..53206a1ca 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/AboutScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/AboutScreen.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.settings +package io.github.openflocon.flocondesktop.app.ui.settings import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/Navigation.kt similarity index 84% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/Navigation.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/Navigation.kt index 495028ae4..cdf6e67e0 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/Navigation.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.settings +package io.github.openflocon.flocondesktop.app.ui.settings import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.navigation.FloconRoute diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsAction.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/SettingsAction.kt similarity index 65% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsAction.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/SettingsAction.kt index 8be8fdce9..a51d05f16 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsAction.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/SettingsAction.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.settings +package io.github.openflocon.flocondesktop.app.ui.settings sealed interface SettingsAction { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/SettingsScreen.kt similarity index 99% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsScreen.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/SettingsScreen.kt index 18552b1fe..e18a4dc52 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/SettingsScreen.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.settings +package io.github.openflocon.flocondesktop.app.ui.settings import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/SettingsUiState.kt similarity index 76% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsUiState.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/SettingsUiState.kt index cfd182879..cad85f0b0 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/SettingsUiState.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.settings +package io.github.openflocon.flocondesktop.app.ui.settings import androidx.compose.runtime.Immutable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/SettingsViewModel.kt similarity index 98% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsViewModel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/SettingsViewModel.kt index 9decbe722..576a7c5dd 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/settings/SettingsViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/SettingsViewModel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.settings +package io.github.openflocon.flocondesktop.app.ui.settings import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/SubScreenSelectorItem.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/SubScreenSelectorItem.kt similarity index 93% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/SubScreenSelectorItem.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/SubScreenSelectorItem.kt index 961d7cb98..34ae55f1b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/SubScreenSelectorItem.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/SubScreenSelectorItem.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.view +package io.github.openflocon.flocondesktop.app.ui.view import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Link @@ -12,7 +12,7 @@ import androidx.compose.material.icons.outlined.StackedBarChart import androidx.compose.material.icons.outlined.Storage import androidx.compose.material.icons.outlined.TableView import androidx.compose.ui.graphics.vector.ImageVector -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen // Extension function to get the display name for each SubScreen fun SubScreen.displayName(): String = when (this) { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelDivider.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/LeftPannelDivider.kt similarity index 87% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelDivider.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/LeftPannelDivider.kt index b5c6fdb1c..94aa59acc 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelDivider.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/LeftPannelDivider.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.view.leftpannel +package io.github.openflocon.flocondesktop.app.ui.view.leftpannel import androidx.compose.foundation.layout.padding import androidx.compose.material3.HorizontalDivider diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/LeftPannelView.kt similarity index 87% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/LeftPannelView.kt index 4cbce45f6..8ec74bfcf 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/LeftPannelView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/LeftPannelView.kt @@ -1,6 +1,6 @@ @file:Suppress("UnusedReceiverParameter") -package io.github.openflocon.flocondesktop.menu.ui.view.leftpannel +package io.github.openflocon.flocondesktop.app.ui.view.leftpannel import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -20,11 +20,11 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEachIndexed -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen -import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelItem -import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelState -import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPannelSection -import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.previewLeftPannelState +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPanelItem +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPanelState +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPannelSection +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.previewLeftPannelState import io.github.openflocon.library.designsystem.FloconTheme val PanelMaxWidth = 275.dp @@ -97,7 +97,7 @@ private fun ColumnScope.MenuItems( icon = item.icon, text = item.text, expanded = expanded, - isSelected = item.isSelected, + isSelected = current == item, isEnabled = item.isEnabled, onClick = { onClickItem(item) }, ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelLabel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/PannelLabel.kt similarity index 95% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelLabel.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/PannelLabel.kt index 8b6849197..0575fbb49 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelLabel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/PannelLabel.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.view.leftpannel +package io.github.openflocon.flocondesktop.app.ui.view.leftpannel import androidx.compose.animation.Crossfade import androidx.compose.foundation.layout.Box diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/PannelView.kt similarity index 96% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/PannelView.kt index ccea6895a..d6da7f90d 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/leftpannel/PannelView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/PannelView.kt @@ -1,10 +1,11 @@ @file:OptIn(ExperimentalSharedTransitionApi::class) -package io.github.openflocon.flocondesktop.menu.ui.view.leftpannel +package io.github.openflocon.flocondesktop.app.ui.view.leftpannel import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.ExperimentalSharedTransitionApi import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -26,6 +27,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp import io.github.openflocon.library.designsystem.FloconTheme diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/MainScreenTopBar.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/MainScreenTopBar.kt similarity index 85% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/MainScreenTopBar.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/MainScreenTopBar.kt index dfab7c49e..9e367c9a1 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/MainScreenTopBar.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/MainScreenTopBar.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.view.topbar +package io.github.openflocon.flocondesktop.app.ui.view.topbar import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -19,12 +19,12 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import flocondesktop.composeapp.generated.resources.Res import flocondesktop.composeapp.generated.resources.app_icon_small -import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.view.topbar.actions.TopBarActions +import io.github.openflocon.flocondesktop.app.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.app.ui.view.topbar.actions.TopBarActions import io.github.openflocon.library.designsystem.FloconTheme import org.jetbrains.compose.resources.painterResource diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/TopBarDeviceAndAppView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/TopBarDeviceAndAppView.kt similarity index 72% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/TopBarDeviceAndAppView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/TopBarDeviceAndAppView.kt index 6f99e4f66..5bcaa0bf0 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/TopBarDeviceAndAppView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/TopBarDeviceAndAppView.kt @@ -1,7 +1,7 @@ @file:OptIn(ExperimentalMaterial3Api::class) @file:Suppress("UnusedReceiverParameter") -package io.github.openflocon.flocondesktop.menu.ui.view.topbar +package io.github.openflocon.flocondesktop.app.ui.view.topbar import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Arrangement @@ -11,12 +11,12 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.view.topbar.app.TopBarAppDropdown -import io.github.openflocon.flocondesktop.menu.ui.view.topbar.device.TopBarDeviceDropdown +import io.github.openflocon.flocondesktop.app.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.app.ui.view.topbar.app.TopBarAppDropdown +import io.github.openflocon.flocondesktop.app.ui.view.topbar.device.TopBarDeviceDropdown @Composable internal fun TopBarDeviceAndAppView( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/TopBarSelector.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/TopBarSelector.kt similarity index 96% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/TopBarSelector.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/TopBarSelector.kt index 5c5b6d211..17d8ddbde 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/TopBarSelector.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/TopBarSelector.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.view.topbar +package io.github.openflocon.flocondesktop.app.ui.view.topbar import androidx.compose.foundation.Image diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/actions/TopBarActions.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/actions/TopBarActions.kt similarity index 90% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/actions/TopBarActions.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/actions/TopBarActions.kt index d9f65d9e1..e91151a6f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/actions/TopBarActions.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/actions/TopBarActions.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.view.topbar.actions +package io.github.openflocon.flocondesktop.app.ui.view.topbar.actions import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row @@ -11,8 +11,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.RecordVideoStateUiModel @Composable internal fun TopBarActions( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/actions/TopBarButton.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/actions/TopBarButton.kt similarity index 92% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/actions/TopBarButton.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/actions/TopBarButton.kt index 396208b65..30f1f4080 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/actions/TopBarButton.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/actions/TopBarButton.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.view.topbar.actions +package io.github.openflocon.flocondesktop.app.ui.view.topbar.actions import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppDropdown.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/app/TopBarAppDropdown.kt similarity index 90% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppDropdown.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/app/TopBarAppDropdown.kt index d8078e503..ecbe4f7e1 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppDropdown.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/app/TopBarAppDropdown.kt @@ -1,6 +1,6 @@ @file:OptIn(ExperimentalMaterial3Api::class) -package io.github.openflocon.flocondesktop.menu.ui.view.topbar.app +package io.github.openflocon.flocondesktop.app.ui.view.topbar.app import androidx.compose.foundation.clickable @@ -14,14 +14,13 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.util.fastForEach -import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.view.topbar.TopBarSelector +import io.github.openflocon.flocondesktop.app.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.app.ui.view.topbar.TopBarSelector import io.github.openflocon.library.designsystem.components.FloconExposedDropdownMenu import io.github.openflocon.library.designsystem.components.FloconExposedDropdownMenuBox - @Composable internal fun TopBarAppDropdown( devicesState: DevicesStateUiModel, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/app/TopBarAppView.kt similarity index 95% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/app/TopBarAppView.kt index 68b2d73fc..ace09ee17 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/app/TopBarAppView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/app/TopBarAppView.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.view.topbar.app +package io.github.openflocon.flocondesktop.app.ui.view.topbar.app import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -29,8 +29,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import flocondesktop.composeapp.generated.resources.Res import flocondesktop.composeapp.generated.resources.smartphone -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DeviceItemUiModel import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconIcon import org.jetbrains.compose.resources.painterResource diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/device/TopBarDeviceDropdown.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/device/TopBarDeviceDropdown.kt similarity index 89% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/device/TopBarDeviceDropdown.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/device/TopBarDeviceDropdown.kt index ea4c393f3..11368a13b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/device/TopBarDeviceDropdown.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/device/TopBarDeviceDropdown.kt @@ -1,6 +1,6 @@ @file:OptIn(ExperimentalMaterial3Api::class) -package io.github.openflocon.flocondesktop.menu.ui.view.topbar.device +package io.github.openflocon.flocondesktop.app.ui.view.topbar.device import androidx.compose.foundation.layout.padding @@ -16,9 +16,9 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.view.topbar.TopBarSelector +import io.github.openflocon.flocondesktop.app.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.app.ui.view.topbar.TopBarSelector import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconCircularProgressIndicator @@ -41,7 +41,7 @@ internal fun TopBarDeviceDropdown( when (state) { DevicesStateUiModel.Empty -> Empty() DevicesStateUiModel.Loading -> Loading() - is DevicesStateUiModel.WithDevices -> TopBarSelector( + is DevicesStateUiModel.WithDevices -> TopBarSelector( onClick = { expanded = true }, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/device/TopBarDeviceView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/device/TopBarDeviceView.kt similarity index 96% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/device/TopBarDeviceView.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/device/TopBarDeviceView.kt index 82b64f8de..5e8266713 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/view/topbar/device/TopBarDeviceView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/topbar/device/TopBarDeviceView.kt @@ -1,4 +1,4 @@ -package io.github.openflocon.flocondesktop.menu.ui.view.topbar.device +package io.github.openflocon.flocondesktop.app.ui.view.topbar.device import androidx.compose.desktop.ui.tooling.preview.Preview @@ -22,7 +22,6 @@ import androidx.compose.material.icons.filled.PhoneIphone import androidx.compose.material.icons.filled.Smartphone import androidx.compose.material.icons.outlined.Close import androidx.compose.material.icons.outlined.MobileOff -import androidx.compose.material.icons.outlined.PhoneIphone import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -34,7 +33,7 @@ import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DeviceItemUiModel import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconIcon import io.github.openflocon.library.designsystem.components.FloconSurface @@ -68,22 +67,25 @@ internal fun TopBarDeviceView( ) { Image( modifier = Modifier.width(20.dp), - imageVector = when(device.platform) { + imageVector = when (device.platform) { DeviceItemUiModel.Platform.Android -> if (device.isActive.not()) { Icons.Filled.MobileOff } else { Icons.Filled.Smartphone } + DeviceItemUiModel.Platform.Desktop -> if (device.isActive.not()) { Icons.Filled.DesktopAccessDisabled } else { Icons.Filled.DesktopWindows } + DeviceItemUiModel.Platform.ios -> if (device.isActive.not()) { Icons.Outlined.MobileOff } else { Icons.Filled.PhoneIphone } + DeviceItemUiModel.Platform.Unknown -> if (device.isActive.not()) { Icons.Filled.MobileOff } else { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt index 04401257d..bdafea3c4 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt @@ -1,9 +1,9 @@ package io.github.openflocon.flocondesktop.features.analytics import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.features.analytics.view.AnalyticsScreen import io.github.openflocon.flocondesktop.menu.MenuSceneStrategy -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen import io.github.openflocon.navigation.FloconRoute import kotlinx.serialization.Serializable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt index 4eef07640..476a9e330 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt @@ -2,11 +2,10 @@ package io.github.openflocon.flocondesktop.features.network import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.domain.settings.repository.SettingsRepository +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.features.network.detail.view.NetworkDetailScreen import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen -import io.github.openflocon.flocondesktop.menu.MenuScene import io.github.openflocon.flocondesktop.menu.MenuSceneStrategy -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen import io.github.openflocon.navigation.FloconRoute import io.github.openflocon.navigation.PanelRoute import io.github.openflocon.navigation.scene.PanelSceneStrategy diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt deleted file mode 100644 index beab06a87..000000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuRoutes.kt +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.openflocon.flocondesktop.menu - -import androidx.navigation3.runtime.EntryProviderScope -import io.github.openflocon.flocondesktop.menu.ui.MenuScreen -import io.github.openflocon.navigation.FloconRoute -import io.github.openflocon.navigation.scene.WindowSceneStrategy -import kotlinx.serialization.Serializable -import org.koin.core.Koin -import org.koin.core.component.KoinScopeComponent -import org.koin.core.component.createScope -import org.koin.core.scope.Scope - -internal sealed interface MainRoutes : FloconRoute { - - @Serializable - data object Main : MainRoutes - - // For later - @Serializable - data class Sub( - val id: String - ) : MainRoutes, KoinScopeComponent { - override val scope: Scope - get() = createScope(scopeId = id) - - companion object { - val Main = Sub(id = "main") - } - } - -} - -internal fun Koin.createFloconScope(sub: MainRoutes.Sub) = createScope(sub) - -fun EntryProviderScope.menuRoutes() { - entry { MenuScreen() } - // TODO Scope VM on this - entry(metadata = WindowSceneStrategy.window()) { - MenuScreen() // TODO Remove toolbar - } -} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuScene.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuScene.kt index 0c1ddac30..c1a389ce6 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuScene.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuScene.kt @@ -34,13 +34,13 @@ import androidx.navigation3.runtime.NavEntry import androidx.navigation3.scene.Scene import androidx.navigation3.scene.SceneStrategy import androidx.navigation3.scene.SceneStrategyScope -import io.github.openflocon.flocondesktop.menu.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.RecordVideoStateUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen -import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.PanelMaxWidth -import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.PanelMinWidth -import io.github.openflocon.flocondesktop.menu.ui.view.topbar.MainScreenTopBar +import io.github.openflocon.flocondesktop.app.ui.model.AppsStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.PanelMaxWidth +import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.PanelMinWidth +import io.github.openflocon.flocondesktop.app.ui.view.topbar.MainScreenTopBar import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconIcon import io.github.openflocon.library.designsystem.components.FloconScaffold diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/di/MainModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/di/MainModule.kt deleted file mode 100644 index 06a9ee36b..000000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/di/MainModule.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.openflocon.flocondesktop.menu.di - -import io.github.openflocon.flocondesktop.menu.ui.di.mainUiModule -import org.koin.dsl.module - -val mainModule = module { - includes( - mainUiModule - ) -} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuNavigationState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuNavigationState.kt deleted file mode 100644 index aa4e43c35..000000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuNavigationState.kt +++ /dev/null @@ -1,19 +0,0 @@ -package io.github.openflocon.flocondesktop.menu.ui - -import androidx.compose.runtime.mutableStateListOf -import androidx.compose.runtime.snapshots.SnapshotStateList -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen -import io.github.openflocon.navigation.FloconNavigationState - -class MenuNavigationState(initialScreen: SubScreen) : FloconNavigationState { - private val _stack = mutableStateListOf(initialScreen) - override val stack: SnapshotStateList = _stack - - override fun navigate(route: SubScreen) { - _stack[0] = route - } - - override fun back(count: Int) { - repeat(count) { _stack.removeLast() } - } -} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt deleted file mode 100644 index 24e43454b..000000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/MenuScreen.kt +++ /dev/null @@ -1,185 +0,0 @@ -@file:OptIn(ExperimentalMaterial3Api::class) - -package io.github.openflocon.flocondesktop.menu.ui - -import androidx.compose.animation.core.animateDpAsState -import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.ChevronRight -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.rotate -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.layout.onGloballyPositioned -import androidx.compose.ui.unit.IntSize -import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation3.runtime.EntryProviderScope -import io.github.openflocon.flocondesktop.features.analytics.view.AnalyticsScreen -import io.github.openflocon.flocondesktop.features.dashboard.view.DashboardScreen -import io.github.openflocon.flocondesktop.features.database.view.DatabaseScreen -import io.github.openflocon.flocondesktop.features.deeplinks.view.DeeplinkScreen -import io.github.openflocon.flocondesktop.features.files.view.FilesScreen -import io.github.openflocon.flocondesktop.features.images.view.ImagesScreen -import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen -import io.github.openflocon.flocondesktop.features.sharedpreferences.view.SharedPreferencesScreen -import io.github.openflocon.flocondesktop.features.table.view.TableScreen -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.DeviceItemUiModel -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen -import io.github.openflocon.flocondesktop.menu.ui.model.leftpanel.LeftPanelItem -import io.github.openflocon.flocondesktop.menu.ui.settings.SettingsScreen -import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.LeftPanelView -import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.PanelMaxWidth -import io.github.openflocon.flocondesktop.menu.ui.view.leftpannel.PanelMinWidth -import io.github.openflocon.flocondesktop.menu.ui.view.topbar.MainScreenTopBar -import io.github.openflocon.library.designsystem.FloconTheme -import io.github.openflocon.library.designsystem.components.FloconIcon -import io.github.openflocon.navigation.FloconNavigation -import org.koin.compose.viewmodel.koinViewModel - -@Composable -fun MenuScreen( - modifier: Modifier = Modifier -) { - val viewModel: MenuViewModel = koinViewModel() - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - - MenuScreen( - uiState = uiState, - navigationState = viewModel.menuNavigationState, - modifier = modifier, - onDeviceSelected = viewModel::onDeviceSelected, - deleteDevice = viewModel::deleteDevice, - deleteApp = viewModel::deleteApp, - onAppSelected = viewModel::onAppSelected, - onClickLeftPanelItem = viewModel::onClickLeftPanelItem, - onTakeScreenshotClicked = viewModel::onTakeScreenshotClicked, - onRecordClicked = viewModel::onRecordClicked, - onRestartClicked = viewModel::onRestartClicked, - ) -} - -@Composable -private fun MenuScreen( - uiState: MenuUiState, - navigationState: MenuNavigationState, - onClickLeftPanelItem: (LeftPanelItem) -> Unit, - onDeviceSelected: (DeviceItemUiModel) -> Unit, - deleteDevice: (DeviceItemUiModel) -> Unit, - onAppSelected: (DeviceAppUiModel) -> Unit, - deleteApp: (DeviceAppUiModel) -> Unit, - onTakeScreenshotClicked: () -> Unit, - onRecordClicked: () -> Unit, - onRestartClicked: () -> Unit, - modifier: Modifier = Modifier, -) { - var expanded by remember { mutableStateOf(true) } - val width by animateDpAsState(targetValue = if (expanded) PanelMaxWidth else PanelMinWidth) - var windowSize by remember { mutableStateOf(IntSize.Zero) } - val position by animateDpAsState( - targetValue = if (expanded) PanelMaxWidth else PanelMinWidth, - ) - val rotate by animateFloatAsState(targetValue = if (expanded) 180f else 0f) - - Box( - modifier = Modifier - .fillMaxSize() - .onGloballyPositioned { - windowSize = it.size // TODO Add windowsize lib - } - ) { - Column( - modifier = modifier - .matchParentSize() - ) { - MainScreenTopBar( - appsState = uiState.appsStateUiModel, - devicesState = uiState.devicesStateUiModel, - recordState = uiState.recordVideoState, - deleteApp = deleteApp, - deleteDevice = deleteDevice, - onAppSelected = onAppSelected, - onRecordClicked = onRecordClicked, - onRestartClicked = onRestartClicked, - onDeviceSelected = onDeviceSelected, - onTakeScreenshotClicked = onTakeScreenshotClicked - ) - Row( - modifier = Modifier - .fillMaxSize() - .padding(8.dp) - ) { - LeftPanelView( - modifier = Modifier - .width(width) - .fillMaxHeight(), - expanded = expanded, - onClickItem = onClickLeftPanelItem, - state = uiState.leftPanelState, - ) - Spacer(Modifier.width(8.dp)) - FloconNavigation( - navigationState = navigationState, - modifier = Modifier - .weight(1f) - .fillMaxHeight(), - ) { - menus() - } - } - } - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .width(20.dp) - .height(60.dp) - .graphicsLayer { - translationX = position.toPx() - size.width / 2 - 2.dp.toPx() - translationY = (windowSize.height / 2) - (size.height / 2) - } - .clip(RoundedCornerShape(topStart = 4.dp, bottomStart = 4.dp)) - .background(FloconTheme.colorPalette.secondary) - .clickable(onClick = { expanded = !expanded }), - ) { - FloconIcon( - imageVector = Icons.Outlined.ChevronRight, - tint = Color.LightGray, - modifier = Modifier.rotate(rotate), - ) - } - } -} - -private fun EntryProviderScope.menus() { - entry { NetworkScreen() } - entry { DashboardScreen() } - entry { AnalyticsScreen() } - entry { TableScreen() } - entry { ImagesScreen() } - entry { FilesScreen() } - entry { SharedPreferencesScreen() } - entry { DatabaseScreen() } - entry { DeeplinkScreen() } - entry { SettingsScreen() } -} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/di/MainUiModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/di/MainUiModule.kt deleted file mode 100644 index 93e4d9a6e..000000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/ui/di/MainUiModule.kt +++ /dev/null @@ -1,24 +0,0 @@ -package io.github.openflocon.flocondesktop.menu.ui.di - -import io.github.openflocon.flocondesktop.features.network.detail.NetworkDetailViewModel -import io.github.openflocon.flocondesktop.menu.ui.MenuViewModel -import io.github.openflocon.flocondesktop.menu.ui.MenuNavigationState -import io.github.openflocon.flocondesktop.menu.ui.delegates.DevicesDelegate -import io.github.openflocon.flocondesktop.menu.ui.delegates.RecordVideoDelegate -import io.github.openflocon.flocondesktop.menu.ui.model.SubScreen -import io.github.openflocon.flocondesktop.menu.ui.settings.SettingsViewModel -import org.koin.core.module.dsl.factoryOf -import org.koin.core.module.dsl.viewModelOf -import org.koin.dsl.module - -val mainUiModule = module { -// scope { - single { MenuNavigationState(SubScreen.Network) } - viewModelOf(::MenuViewModel) - factoryOf(::DevicesDelegate) - factoryOf(::RecordVideoDelegate) - viewModelOf(::SettingsViewModel) - - viewModelOf(::NetworkDetailViewModel) -// } -} diff --git a/FloconDesktop/composeApp/src/desktopMain/kotlin/io/github/openflocon/flocondesktop/Main.kt b/FloconDesktop/composeApp/src/desktopMain/kotlin/io/github/openflocon/flocondesktop/Main.kt index 37155916e..5f0ae0d17 100644 --- a/FloconDesktop/composeApp/src/desktopMain/kotlin/io/github/openflocon/flocondesktop/Main.kt +++ b/FloconDesktop/composeApp/src/desktopMain/kotlin/io/github/openflocon/flocondesktop/Main.kt @@ -145,7 +145,7 @@ private fun FrameWindowScope.FloconMenu() { alwaysOnTop = true, onCloseRequest = { openLicenses = false }, ) { - io.github.openflocon.flocondesktop.menu.ui.settings.AboutScreen( + io.github.openflocon.flocondesktop.app.ui.settings.AboutScreen( modifier = Modifier .fillMaxSize() .background(FloconTheme.colorPalette.primary), From 1d1b42e22a6aaf0fa82c8bcdb8f290f442d2710e Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 29 Oct 2025 13:52:23 +0100 Subject: [PATCH 16/28] fix: Delete duplicate --- .../flocondesktop/menu/MenuScene.kt | 159 ------------------ 1 file changed, 159 deletions(-) delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuScene.kt diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuScene.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuScene.kt deleted file mode 100644 index c1a389ce6..000000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/menu/MenuScene.kt +++ /dev/null @@ -1,159 +0,0 @@ -package io.github.openflocon.flocondesktop.menu - -import androidx.compose.animation.core.animateDpAsState -import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.ChevronRight -import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.rotate -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.layout.onGloballyPositioned -import androidx.compose.ui.unit.IntSize -import androidx.compose.ui.unit.dp -import androidx.navigation3.runtime.NavEntry -import androidx.navigation3.scene.Scene -import androidx.navigation3.scene.SceneStrategy -import androidx.navigation3.scene.SceneStrategyScope -import io.github.openflocon.flocondesktop.app.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.app.ui.model.RecordVideoStateUiModel -import io.github.openflocon.flocondesktop.app.ui.model.SubScreen -import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.PanelMaxWidth -import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.PanelMinWidth -import io.github.openflocon.flocondesktop.app.ui.view.topbar.MainScreenTopBar -import io.github.openflocon.library.designsystem.FloconTheme -import io.github.openflocon.library.designsystem.components.FloconIcon -import io.github.openflocon.library.designsystem.components.FloconScaffold -import io.github.openflocon.navigation.FloconRoute - -@Immutable -data class MenuScene( - override val entries: List>, - override val previousEntries: List>, - val entry: NavEntry, - val screen: SubScreen, - val menuContent: @Composable (expanded: Boolean) -> Unit -) : Scene { - override val key: Any - get() = Unit - - override val content: @Composable (() -> Unit) = { - var expanded by remember { mutableStateOf(false) } - val width by animateDpAsState(targetValue = if (expanded) PanelMaxWidth else PanelMinWidth) - var windowSize by remember { mutableStateOf(IntSize.Zero) } - val position by animateDpAsState( - targetValue = if (expanded) PanelMaxWidth else PanelMinWidth, - ) - val rotate by animateFloatAsState(targetValue = if (expanded) 180f else 0f) - - Box { - FloconScaffold( - topBar = { - MainScreenTopBar( - devicesState = DevicesStateUiModel.Empty, - appsState = AppsStateUiModel.Empty, - recordState = RecordVideoStateUiModel.Recording, - deleteApp = {}, - deleteDevice = {}, - onDeviceSelected = {}, - onAppSelected = {}, - onRecordClicked = {}, - onRestartClicked = {}, - onTakeScreenshotClicked = {} - ) - }, - modifier = Modifier - .fillMaxSize() - .onGloballyPositioned { - windowSize = it.size // TODO Add windowsize lib - } - ) { padding -> - Row( - horizontalArrangement = Arrangement.spacedBy(8.dp), - modifier = Modifier - .fillMaxSize() - .padding(padding) - .padding(8.dp) - ) { - Box( - modifier = Modifier - .width(width) - .fillMaxHeight(), - ) { - menuContent(expanded) - } - entry.Content() - } - } - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .width(20.dp) - .height(60.dp) - .graphicsLayer { - translationX = position.toPx() - size.width / 2 - 2.dp.toPx() - translationY = (windowSize.height / 4f).times(3f) + (size.height / 2f) - } - .clip(RoundedCornerShape(topStart = 4.dp, bottomStart = 4.dp)) - .background(FloconTheme.colorPalette.secondary) - .clickable(onClick = { expanded = !expanded }), - ) { - FloconIcon( - imageVector = Icons.Outlined.ChevronRight, - tint = Color.LightGray, - modifier = Modifier.rotate(rotate), - ) - } - } - } -} - -class MenuSceneStrategy( - private val menuContent: @Composable (expanded: Boolean) -> Unit -) : SceneStrategy { - - override fun SceneStrategyScope.calculateScene(entries: List>): Scene? { - val entry = entries.lastOrNull() ?: return null - val menu = entry.metadata[MENU_KEY] ?: return null - - if (menu is SubScreen) { - return MenuScene( - entries = listOf(entry), - previousEntries = entries.dropLast(1), - entry = entry, - screen = menu, - menuContent = menuContent - ) - } - - return null - } - - companion object { - private const val MENU_KEY = "menu_key" - - fun menu(menu: SubScreen) = mapOf(MENU_KEY to menu) - - } - -} From c242853470a5cfbbde7790ea221b51c60be8525d Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 29 Oct 2025 14:08:34 +0100 Subject: [PATCH 17/28] feature: Add routes --- .../openflocon/flocondesktop/app/AppScreen.kt | 19 +++++++++++++-- .../app/ui/settings/Navigation.kt | 10 +++++--- .../features/analytics/Navigation.kt | 2 +- .../dashboard/{DashboardModule.kt => DI.kt} | 0 .../features/dashboard/Navigation.kt | 23 +++++++++++++++++++ .../features/database/Navigation.kt | 19 +++++++++++++++ .../features/deeplinks/Navigation.kt | 19 +++++++++++++++ .../features/files/Navigation.kt | 19 +++++++++++++++ .../features/images/Navigation.kt | 23 +++++++++++++++++++ .../features/network/Navigation.kt | 2 +- .../features/sharedpreferences/Navigation.kt | 23 +++++++++++++++++++ .../features/table/Navigation.kt | 23 +++++++++++++++++++ 12 files changed, 175 insertions(+), 7 deletions(-) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/{DashboardModule.kt => DI.kt} (100%) create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/Navigation.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/Navigation.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/Navigation.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/files/Navigation.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/images/Navigation.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/sharedpreferences/Navigation.kt create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/table/Navigation.kt diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt index b5913403d..5f125f427 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt @@ -11,10 +11,17 @@ import androidx.navigation3.scene.DialogSceneStrategy import androidx.navigation3.scene.SinglePaneSceneStrategy import io.github.openflocon.flocondesktop.app.ui.buildLeftPanelState import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.settings.settingsRoutes import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.LeftPanelView import io.github.openflocon.flocondesktop.features.analytics.analyticsRoutes +import io.github.openflocon.flocondesktop.features.dashboard.dashboardRoutes +import io.github.openflocon.flocondesktop.features.database.databaseRoutes +import io.github.openflocon.flocondesktop.features.deeplinks.deeplinkRoutes +import io.github.openflocon.flocondesktop.features.files.filesRoutes +import io.github.openflocon.flocondesktop.features.images.imageRoutes import io.github.openflocon.flocondesktop.features.network.networkRoutes -import io.github.openflocon.flocondesktop.menu.MenuSceneStrategy +import io.github.openflocon.flocondesktop.features.sharedpreferences.sharedPreferencesRoutes +import io.github.openflocon.flocondesktop.features.table.tableRoutes import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.navigation.FloconNavigation import io.github.openflocon.navigation.MainFloconNavigationState @@ -65,7 +72,15 @@ private fun Content( .fillMaxSize() .background(FloconTheme.colorPalette.surface) ) { - networkRoutes() analyticsRoutes() + dashboardRoutes() + databaseRoutes() + deeplinkRoutes() + filesRoutes() + imageRoutes() + networkRoutes() + sharedPreferencesRoutes() + tableRoutes() + settingsRoutes() } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/Navigation.kt index cdf6e67e0..d9d8f2eff 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/Navigation.kt @@ -4,11 +4,15 @@ import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.navigation.FloconRoute import kotlinx.serialization.Serializable -@Serializable -data object SettingsRoute : FloconRoute +sealed interface SettingsRoutes : FloconRoute { + + @Serializable + data object Main : SettingsRoutes + +} fun EntryProviderScope.settingsRoutes() { - entry { + entry { SettingsScreen() } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt index bdafea3c4..144ffd8b6 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt @@ -1,9 +1,9 @@ package io.github.openflocon.flocondesktop.features.analytics import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.app.MenuSceneStrategy import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.features.analytics.view.AnalyticsScreen -import io.github.openflocon.flocondesktop.menu.MenuSceneStrategy import io.github.openflocon.navigation.FloconRoute import kotlinx.serialization.Serializable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/DashboardModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/DI.kt similarity index 100% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/DashboardModule.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/DI.kt diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/Navigation.kt new file mode 100644 index 000000000..8c0fc50e6 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/Navigation.kt @@ -0,0 +1,23 @@ +package io.github.openflocon.flocondesktop.features.dashboard + +import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.app.MenuSceneStrategy +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.features.dashboard.view.DashboardScreen +import io.github.openflocon.navigation.FloconRoute +import kotlinx.serialization.Serializable + +sealed interface DashboardRoutes : FloconRoute { + + @Serializable + data object Main : DashboardRoutes + +} + +fun EntryProviderScope.dashboardRoutes() { + entry( + metadata = MenuSceneStrategy.menu(SubScreen.Dashboard) + ) { + DashboardScreen() + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/Navigation.kt new file mode 100644 index 000000000..6a4bd705a --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/Navigation.kt @@ -0,0 +1,19 @@ +package io.github.openflocon.flocondesktop.features.database + +import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.features.database.view.DatabaseScreen +import io.github.openflocon.navigation.FloconRoute +import kotlinx.serialization.Serializable + +sealed interface DatabaseRoutes : FloconRoute { + + @Serializable + data object Main : DatabaseRoutes + +} + +fun EntryProviderScope.databaseRoutes() { + entry { + DatabaseScreen() + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/Navigation.kt new file mode 100644 index 000000000..3a891009f --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/Navigation.kt @@ -0,0 +1,19 @@ +package io.github.openflocon.flocondesktop.features.deeplinks + +import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.features.deeplinks.view.DeeplinkScreen +import io.github.openflocon.navigation.FloconRoute +import kotlinx.serialization.Serializable + +sealed interface DeeplinkRoutes : FloconRoute { + + @Serializable + data object Main : DeeplinkRoutes + +} + +fun EntryProviderScope.deeplinkRoutes() { + entry { + DeeplinkScreen() + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/files/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/files/Navigation.kt new file mode 100644 index 000000000..cc68f96db --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/files/Navigation.kt @@ -0,0 +1,19 @@ +package io.github.openflocon.flocondesktop.features.files + +import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.features.files.view.FilesScreen +import io.github.openflocon.navigation.FloconRoute +import kotlinx.serialization.Serializable + +sealed interface FilesRoutes : FloconRoute { + + @Serializable + data object Main : FilesRoutes + +} + +fun EntryProviderScope.filesRoutes() { + entry { + FilesScreen() + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/images/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/images/Navigation.kt new file mode 100644 index 000000000..5f56e4200 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/images/Navigation.kt @@ -0,0 +1,23 @@ +package io.github.openflocon.flocondesktop.features.images + +import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.app.MenuSceneStrategy +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.features.images.view.ImagesScreen +import io.github.openflocon.navigation.FloconRoute +import kotlinx.serialization.Serializable + +sealed interface ImageRoutes : FloconRoute { + + @Serializable + data object Main : ImageRoutes + +} + +fun EntryProviderScope.imageRoutes() { + entry( + metadata = MenuSceneStrategy.menu(SubScreen.Images) + ) { + ImagesScreen() + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt index 476a9e330..12f51257d 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt @@ -2,10 +2,10 @@ package io.github.openflocon.flocondesktop.features.network import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.domain.settings.repository.SettingsRepository +import io.github.openflocon.flocondesktop.app.MenuSceneStrategy import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.features.network.detail.view.NetworkDetailScreen import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen -import io.github.openflocon.flocondesktop.menu.MenuSceneStrategy import io.github.openflocon.navigation.FloconRoute import io.github.openflocon.navigation.PanelRoute import io.github.openflocon.navigation.scene.PanelSceneStrategy diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/sharedpreferences/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/sharedpreferences/Navigation.kt new file mode 100644 index 000000000..9dfea286f --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/sharedpreferences/Navigation.kt @@ -0,0 +1,23 @@ +package io.github.openflocon.flocondesktop.features.sharedpreferences + +import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.app.MenuSceneStrategy +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.features.sharedpreferences.view.SharedPreferencesScreen +import io.github.openflocon.navigation.FloconRoute +import kotlinx.serialization.Serializable + +sealed interface SharedPreferencesRoutes : FloconRoute { + + @Serializable + data object Main : SharedPreferencesRoutes + +} + +fun EntryProviderScope.sharedPreferencesRoutes() { + entry( + metadata = MenuSceneStrategy.menu(SubScreen.SharedPreferences) + ) { + SharedPreferencesScreen() + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/table/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/table/Navigation.kt new file mode 100644 index 000000000..2d147fe1e --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/table/Navigation.kt @@ -0,0 +1,23 @@ +package io.github.openflocon.flocondesktop.features.table + +import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.app.MenuSceneStrategy +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.features.table.view.TableScreen +import io.github.openflocon.navigation.FloconRoute +import kotlinx.serialization.Serializable + +sealed interface TableRoutes : FloconRoute { + + @Serializable + data object Main : TableRoutes + +} + +fun EntryProviderScope.tableRoutes() { + entry( + metadata = MenuSceneStrategy.menu(SubScreen.Tables) + ) { + TableScreen() + } +} From a725a565354a039565180ad013f310df74729912 Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 29 Oct 2025 14:12:08 +0100 Subject: [PATCH 18/28] feature: Routing --- .../flocondesktop/app/AppViewModel.kt | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt index af4b6c3d5..c664bdc34 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt @@ -11,9 +11,17 @@ import io.github.openflocon.domain.settings.usecase.StartAdbForwardUseCase import io.github.openflocon.flocondesktop.app.ui.delegates.DevicesDelegate import io.github.openflocon.flocondesktop.app.ui.delegates.RecordVideoDelegate import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.settings.SettingsRoutes import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed import io.github.openflocon.flocondesktop.features.analytics.AnalyticsRoutes +import io.github.openflocon.flocondesktop.features.dashboard.DashboardRoutes +import io.github.openflocon.flocondesktop.features.database.DatabaseRoutes +import io.github.openflocon.flocondesktop.features.deeplinks.DeeplinkRoutes +import io.github.openflocon.flocondesktop.features.files.FilesRoutes +import io.github.openflocon.flocondesktop.features.images.ImageRoutes import io.github.openflocon.flocondesktop.features.network.NetworkRoutes +import io.github.openflocon.flocondesktop.features.sharedpreferences.SharedPreferencesRoutes +import io.github.openflocon.flocondesktop.features.table.TableRoutes import io.github.openflocon.flocondesktop.messages.ui.MessagesServerDelegate import io.github.openflocon.navigation.MainFloconNavigationState import kotlinx.coroutines.delay @@ -94,15 +102,15 @@ internal class AppViewModel( navigationState.menu( when (action.menu) { SubScreen.Analytics -> AnalyticsRoutes.Main - SubScreen.Dashboard -> TODO() - SubScreen.Database -> TODO() - SubScreen.Deeplinks -> TODO() - SubScreen.Files -> TODO() - SubScreen.Images -> TODO() + SubScreen.Dashboard -> DashboardRoutes.Main + SubScreen.Database -> DatabaseRoutes.Main + SubScreen.Deeplinks -> DeeplinkRoutes.Main + SubScreen.Files -> FilesRoutes.Main + SubScreen.Images -> ImageRoutes.Main SubScreen.Network -> NetworkRoutes.Main - SubScreen.Settings -> TODO() - SubScreen.SharedPreferences -> TODO() - SubScreen.Tables -> TODO() + SubScreen.Settings -> SettingsRoutes.Main + SubScreen.SharedPreferences -> SharedPreferencesRoutes.Main + SubScreen.Tables -> TableRoutes.Main } ) } From 245fd204d46a0fbc61262df5eca3bdb71a3dcfba Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 29 Oct 2025 14:17:11 +0100 Subject: [PATCH 19/28] fix: Navigation --- .../io/github/openflocon/flocondesktop/app/MenuScene.kt | 8 ++------ .../github/openflocon/flocondesktop/app/ui/settings/DI.kt | 8 ++++++++ .../flocondesktop/app/ui/settings/Navigation.kt | 5 ++++- .../openflocon/flocondesktop/features/FeaturesModule.kt | 2 ++ .../flocondesktop/features/analytics/Navigation.kt | 3 +-- .../flocondesktop/features/dashboard/Navigation.kt | 3 +-- .../flocondesktop/features/database/Navigation.kt | 5 ++++- .../flocondesktop/features/deeplinks/Navigation.kt | 5 ++++- .../openflocon/flocondesktop/features/files/Navigation.kt | 5 ++++- .../flocondesktop/features/images/Navigation.kt | 3 +-- .../flocondesktop/features/network/Navigation.kt | 3 +-- .../features/sharedpreferences/Navigation.kt | 3 +-- .../openflocon/flocondesktop/features/table/Navigation.kt | 3 +-- 13 files changed, 34 insertions(+), 22 deletions(-) create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/DI.kt diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt index 16dda6e9c..af4f48d11 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt @@ -37,7 +37,6 @@ import androidx.navigation3.scene.SceneStrategyScope import io.github.openflocon.flocondesktop.app.ui.model.AppsStateUiModel import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel import io.github.openflocon.flocondesktop.app.ui.model.RecordVideoStateUiModel -import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.PanelMaxWidth import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.PanelMinWidth import io.github.openflocon.flocondesktop.app.ui.view.topbar.MainScreenTopBar @@ -51,7 +50,6 @@ data class MenuScene( override val entries: List>, override val previousEntries: List>, val entry: NavEntry, - val screen: SubScreen, val menuContent: @Composable (expanded: Boolean) -> Unit ) : Scene { override val key: Any @@ -134,14 +132,12 @@ class MenuSceneStrategy( override fun SceneStrategyScope.calculateScene(entries: List>): Scene? { val entry = entries.lastOrNull() ?: return null - val menu = entry.metadata[MENU_KEY] ?: return null - if (menu is SubScreen) { + if (entry.metadata.containsKey(MENU_KEY)) { return MenuScene( entries = listOf(entry), previousEntries = entries.dropLast(1), entry = entry, - screen = menu, menuContent = menuContent ) } @@ -152,7 +148,7 @@ class MenuSceneStrategy( companion object { private const val MENU_KEY = "menu_key" - fun menu(menu: SubScreen) = mapOf(MENU_KEY to menu) + fun menu() = mapOf(MENU_KEY to MENU_KEY) } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/DI.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/DI.kt new file mode 100644 index 000000000..60d408410 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/DI.kt @@ -0,0 +1,8 @@ +package io.github.openflocon.flocondesktop.app.ui.settings + +import org.koin.core.module.dsl.viewModelOf +import org.koin.dsl.module + +internal val settingsModule = module { + viewModelOf(::SettingsViewModel) +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/Navigation.kt index d9d8f2eff..0c70d65c1 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/settings/Navigation.kt @@ -1,6 +1,7 @@ package io.github.openflocon.flocondesktop.app.ui.settings import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.app.MenuSceneStrategy import io.github.openflocon.navigation.FloconRoute import kotlinx.serialization.Serializable @@ -12,7 +13,9 @@ sealed interface SettingsRoutes : FloconRoute { } fun EntryProviderScope.settingsRoutes() { - entry { + entry( + metadata = MenuSceneStrategy.menu() + ) { SettingsScreen() } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/FeaturesModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/FeaturesModule.kt index 525d7bb91..68a8a8d6a 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/FeaturesModule.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/FeaturesModule.kt @@ -1,5 +1,6 @@ package io.github.openflocon.flocondesktop.features +import io.github.openflocon.flocondesktop.app.ui.settings.settingsModule import io.github.openflocon.flocondesktop.features.analytics.analyticsModule import io.github.openflocon.flocondesktop.features.dashboard.dashboardModule import io.github.openflocon.flocondesktop.features.database.databaseModule @@ -24,5 +25,6 @@ val featuresModule = module { dashboardModule, tableModule, deeplinkModule, + settingsModule ) } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt index 144ffd8b6..20680470b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt @@ -2,7 +2,6 @@ package io.github.openflocon.flocondesktop.features.analytics import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.flocondesktop.app.MenuSceneStrategy -import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.features.analytics.view.AnalyticsScreen import io.github.openflocon.navigation.FloconRoute import kotlinx.serialization.Serializable @@ -16,7 +15,7 @@ sealed interface AnalyticsRoutes : FloconRoute { fun EntryProviderScope.analyticsRoutes() { entry( - metadata = MenuSceneStrategy.menu(SubScreen.Analytics) + metadata = MenuSceneStrategy.menu() ) { AnalyticsScreen() } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/Navigation.kt index 8c0fc50e6..f911e81af 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/Navigation.kt @@ -2,7 +2,6 @@ package io.github.openflocon.flocondesktop.features.dashboard import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.flocondesktop.app.MenuSceneStrategy -import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.features.dashboard.view.DashboardScreen import io.github.openflocon.navigation.FloconRoute import kotlinx.serialization.Serializable @@ -16,7 +15,7 @@ sealed interface DashboardRoutes : FloconRoute { fun EntryProviderScope.dashboardRoutes() { entry( - metadata = MenuSceneStrategy.menu(SubScreen.Dashboard) + metadata = MenuSceneStrategy.menu() ) { DashboardScreen() } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/Navigation.kt index 6a4bd705a..40da4ceb7 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/Navigation.kt @@ -1,6 +1,7 @@ package io.github.openflocon.flocondesktop.features.database import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.app.MenuSceneStrategy import io.github.openflocon.flocondesktop.features.database.view.DatabaseScreen import io.github.openflocon.navigation.FloconRoute import kotlinx.serialization.Serializable @@ -13,7 +14,9 @@ sealed interface DatabaseRoutes : FloconRoute { } fun EntryProviderScope.databaseRoutes() { - entry { + entry( + metadata = MenuSceneStrategy.menu() + ) { DatabaseScreen() } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/Navigation.kt index 3a891009f..2ecef9cdf 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/Navigation.kt @@ -1,6 +1,7 @@ package io.github.openflocon.flocondesktop.features.deeplinks import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.app.MenuSceneStrategy import io.github.openflocon.flocondesktop.features.deeplinks.view.DeeplinkScreen import io.github.openflocon.navigation.FloconRoute import kotlinx.serialization.Serializable @@ -13,7 +14,9 @@ sealed interface DeeplinkRoutes : FloconRoute { } fun EntryProviderScope.deeplinkRoutes() { - entry { + entry( + metadata = MenuSceneStrategy.menu() + ) { DeeplinkScreen() } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/files/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/files/Navigation.kt index cc68f96db..fa9b628aa 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/files/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/files/Navigation.kt @@ -1,6 +1,7 @@ package io.github.openflocon.flocondesktop.features.files import androidx.navigation3.runtime.EntryProviderScope +import io.github.openflocon.flocondesktop.app.MenuSceneStrategy import io.github.openflocon.flocondesktop.features.files.view.FilesScreen import io.github.openflocon.navigation.FloconRoute import kotlinx.serialization.Serializable @@ -13,7 +14,9 @@ sealed interface FilesRoutes : FloconRoute { } fun EntryProviderScope.filesRoutes() { - entry { + entry( + metadata = MenuSceneStrategy.menu() + ) { FilesScreen() } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/images/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/images/Navigation.kt index 5f56e4200..f5d1a7268 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/images/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/images/Navigation.kt @@ -2,7 +2,6 @@ package io.github.openflocon.flocondesktop.features.images import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.flocondesktop.app.MenuSceneStrategy -import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.features.images.view.ImagesScreen import io.github.openflocon.navigation.FloconRoute import kotlinx.serialization.Serializable @@ -16,7 +15,7 @@ sealed interface ImageRoutes : FloconRoute { fun EntryProviderScope.imageRoutes() { entry( - metadata = MenuSceneStrategy.menu(SubScreen.Images) + metadata = MenuSceneStrategy.menu() ) { ImagesScreen() } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt index 12f51257d..4c3d8520b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt @@ -3,7 +3,6 @@ package io.github.openflocon.flocondesktop.features.network import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.domain.settings.repository.SettingsRepository import io.github.openflocon.flocondesktop.app.MenuSceneStrategy -import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.features.network.detail.view.NetworkDetailScreen import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen import io.github.openflocon.navigation.FloconRoute @@ -24,7 +23,7 @@ internal sealed interface NetworkRoutes { fun EntryProviderScope.networkRoutes() { entry( - metadata = MenuSceneStrategy.menu(SubScreen.Network) + metadata = MenuSceneStrategy.menu() ) { NetworkScreen() } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/sharedpreferences/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/sharedpreferences/Navigation.kt index 9dfea286f..928bc5110 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/sharedpreferences/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/sharedpreferences/Navigation.kt @@ -2,7 +2,6 @@ package io.github.openflocon.flocondesktop.features.sharedpreferences import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.flocondesktop.app.MenuSceneStrategy -import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.features.sharedpreferences.view.SharedPreferencesScreen import io.github.openflocon.navigation.FloconRoute import kotlinx.serialization.Serializable @@ -16,7 +15,7 @@ sealed interface SharedPreferencesRoutes : FloconRoute { fun EntryProviderScope.sharedPreferencesRoutes() { entry( - metadata = MenuSceneStrategy.menu(SubScreen.SharedPreferences) + metadata = MenuSceneStrategy.menu() ) { SharedPreferencesScreen() } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/table/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/table/Navigation.kt index 2d147fe1e..a4298f737 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/table/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/table/Navigation.kt @@ -2,7 +2,6 @@ package io.github.openflocon.flocondesktop.features.table import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.flocondesktop.app.MenuSceneStrategy -import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.features.table.view.TableScreen import io.github.openflocon.navigation.FloconRoute import kotlinx.serialization.Serializable @@ -16,7 +15,7 @@ sealed interface TableRoutes : FloconRoute { fun EntryProviderScope.tableRoutes() { entry( - metadata = MenuSceneStrategy.menu(SubScreen.Tables) + metadata = MenuSceneStrategy.menu() ) { TableScreen() } From 3f62ccb33a7f0a57156b2ee55b26b0373b8db393 Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 29 Oct 2025 19:38:10 +0100 Subject: [PATCH 20/28] fix: Panel --- .../openflocon/flocondesktop/app/AppScreen.kt | 2 +- .../network/{NetworkUiModule.kt => DI.kt} | 5 ++- .../features/network/Navigation.kt | 23 +++++++++-- .../features/network/list/NetworkViewModel.kt | 39 ++++++++----------- .../mock/list/view/NetworkMocksScreen.kt | 26 ++++++------- .../components/panel/FloconPanel.kt | 5 ++- .../navigation/FloconNavigationState.kt | 9 +++++ .../openflocon/navigation/FloconRoute.kt | 2 +- .../openflocon/navigation/scene/PanelScene.kt | 31 ++++++--------- 9 files changed, 80 insertions(+), 62 deletions(-) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/{NetworkUiModule.kt => DI.kt} (91%) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt index 5f125f427..bf3c102d9 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt @@ -78,7 +78,7 @@ private fun Content( deeplinkRoutes() filesRoutes() imageRoutes() - networkRoutes() + networkRoutes(navigationState) sharedPreferencesRoutes() tableRoutes() settingsRoutes() diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkUiModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/DI.kt similarity index 91% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkUiModule.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/DI.kt index 1b587e3f9..aa599d8ea 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkUiModule.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/DI.kt @@ -2,6 +2,7 @@ package io.github.openflocon.flocondesktop.features.network import io.github.openflocon.flocondesktop.features.network.badquality.BadQualityNetworkViewModel import io.github.openflocon.flocondesktop.features.network.detail.NetworkDetailDelegate +import io.github.openflocon.flocondesktop.features.network.detail.NetworkDetailViewModel import io.github.openflocon.flocondesktop.features.network.list.NetworkViewModel import io.github.openflocon.flocondesktop.features.network.list.delegate.HeaderDelegate import io.github.openflocon.flocondesktop.features.network.list.delegate.OpenBodyDelegate @@ -16,9 +17,12 @@ import org.koin.dsl.module internal val networkModule = module { viewModelOf(::NetworkViewModel) + viewModelOf(::NetworkDetailViewModel) + factoryOf(::MessagesServerDelegate) factoryOf(::HeaderDelegate) factoryOf(::OpenBodyDelegate) + factoryOf(::NetworkDetailDelegate) viewModelOf(::NetworkMocksViewModel) factoryOf(::ExportMocksProcessor) @@ -27,5 +31,4 @@ internal val networkModule = module { viewModelOf(::BadQualityNetworkViewModel) viewModelOf(::NetworkWebsocketMockViewModel) - factoryOf(::NetworkDetailDelegate) } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt index 4c3d8520b..0b983e6bc 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt @@ -1,27 +1,33 @@ package io.github.openflocon.flocondesktop.features.network import androidx.navigation3.runtime.EntryProviderScope +import androidx.navigation3.scene.DialogSceneStrategy import io.github.openflocon.domain.settings.repository.SettingsRepository import io.github.openflocon.flocondesktop.app.MenuSceneStrategy import io.github.openflocon.flocondesktop.features.network.detail.view.NetworkDetailScreen import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen +import io.github.openflocon.flocondesktop.features.network.mock.list.view.NetworkMocksWindow import io.github.openflocon.navigation.FloconRoute +import io.github.openflocon.navigation.MainFloconNavigationState import io.github.openflocon.navigation.PanelRoute import io.github.openflocon.navigation.scene.PanelSceneStrategy import kotlinx.serialization.Serializable import org.koin.mp.KoinPlatform -internal sealed interface NetworkRoutes { +internal sealed interface NetworkRoutes : FloconRoute { @Serializable - data object Main : PanelRoute + data object Main : NetworkRoutes @Serializable - data class Panel(val requestId: String) : PanelRoute + data object Mocks : NetworkRoutes + + @Serializable + data class Panel(val requestId: String) : NetworkRoutes, PanelRoute } -fun EntryProviderScope.networkRoutes() { +fun EntryProviderScope.networkRoutes(navigationState: MainFloconNavigationState) { entry( metadata = MenuSceneStrategy.menu() ) { @@ -40,4 +46,13 @@ fun EntryProviderScope.networkRoutes() { ) { NetworkDetailScreen(requestId = it.requestId) } + entry( + metadata = DialogSceneStrategy.dialog() + ) { + NetworkMocksWindow( + instanceId = "instance", + fromNetworkCallId = null, + onCloseRequest = { navigationState.remove(it) } + ) + } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt index fd180050f..ec38e3db9 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt @@ -36,7 +36,6 @@ import io.github.openflocon.flocondesktop.core.data.settings.usecase.ObserveNetw import io.github.openflocon.flocondesktop.core.data.settings.usecase.SaveNetworkSettingsUseCase import io.github.openflocon.flocondesktop.features.network.NetworkRoutes import io.github.openflocon.flocondesktop.features.network.body.model.ContentUiState -import io.github.openflocon.flocondesktop.features.network.body.model.MockDisplayed import io.github.openflocon.flocondesktop.features.network.detail.NetworkDetailDelegate import io.github.openflocon.flocondesktop.features.network.list.delegate.HeaderDelegate import io.github.openflocon.flocondesktop.features.network.list.delegate.OpenBodyDelegate @@ -253,8 +252,8 @@ class NetworkViewModel( is NetworkAction.InvertList -> toggleInvertList(action) is NetworkAction.ToggleAutoScroll -> toggleAutoScroll(action) NetworkAction.ClearOldSession -> onClearSession() - is NetworkAction.Down -> contentState.update { it.copy(selectedRequestId = action.itemIdToSelect) } - is NetworkAction.Up -> contentState.update { it.copy(selectedRequestId = action.itemIdToSelect) } + is NetworkAction.Down -> selectRequest(action.itemIdToSelect) + is NetworkAction.Up -> selectRequest(action.itemIdToSelect) is NetworkAction.UpdateDisplayOldSessions -> toggleDisplayOldSessions(action) NetworkAction.OpenWebsocketMocks -> openWebsocketMocks() NetworkAction.CloseWebsocketMocks -> contentState.update { it.copy(websocketMocksDisplayed = false) } @@ -316,40 +315,36 @@ class NetworkViewModel( } } - private var selectRequestJob: Job? = null private fun onSelectRequest(action: NetworkAction.SelectRequest) { - contentState.update { it.copy(selectedRequestId = action.id) } + selectRequest(action.id) + } + + private var selectRequestJob: Job? = null + private fun selectRequest(id: String) { + contentState.update { it.copy(selectedRequestId = id) } selectRequestJob?.cancel() selectRequestJob = viewModelScope.launch { observeNetworkSettingsUseCase().collect { if (it.pinnedDetails) { - detailDelegate.setRequestId(action.id) + detailDelegate.setRequestId(id) } else { - navigationState.navigate(NetworkRoutes.Panel(action.id)) + navigationState.navigate(NetworkRoutes.Panel(id)) } } } + } + + private fun openMocks(callId: String?) { + navigationState.navigate(NetworkRoutes.Mocks) // contentState.update { state -> // state.copy( -// selectedRequestId = if (state.selectedRequestId == action.id) { -// null -// } else { -// action.id -// }, +// mocksDisplayed = MockDisplayed( +// fromNetworkCallId = callId, +// ), // ) // } } - private fun openMocks(callId: String?) { - contentState.update { state -> - state.copy( - mocksDisplayed = MockDisplayed( - fromNetworkCallId = callId, - ), - ) - } - } - private fun openWebsocketMocks() { contentState.update { state -> state.copy( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt index 28971d459..95dd38971 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt @@ -44,25 +44,25 @@ fun NetworkMocksWindow( val mocks by viewModel.items.collectAsStateWithLifecycle() val editionWindow by viewModel.editionWindow.collectAsStateWithLifecycle() key(instanceId) { - FloconDialog( - onDismissRequest = onCloseRequest, - ) { +// FloconDialog( +// onDismissRequest = onCloseRequest, +// ) { NetworkMocksContent( mocks = mocks, modifier = Modifier.fillMaxWidth(), onAction = viewModel::onAction, ) - } +// } - editionWindow?.let { - NetworkEditionWindow( - instanceId = it.windowInstanceId, - state = it.selectedMockUiModel, - onCloseRequest = viewModel::cancelMockCreation, - onCancel = viewModel::cancelMockCreation, - onSave = viewModel::addMock, - ) - } +// editionWindow?.let { +// NetworkEditionWindow( +// instanceId = it.windowInstanceId, +// state = it.selectedMockUiModel, +// onCloseRequest = viewModel::cancelMockCreation, +// onCancel = viewModel::cancelMockCreation, +// onSave = viewModel::addMock, +// ) +// } } } diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt index 061aa1993..13f2ce61e 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt @@ -57,7 +57,10 @@ class FloconPanelState internal constructor(initialValue: Boolean) { @Composable fun rememberFloconPanelState(initialValue: Boolean = false): FloconPanelState { - return remember { FloconPanelState(initialValue) } + return remember { + println("rememberFloconPanelState") + FloconPanelState(initialValue) + } } diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt index 78f02a49a..c4422d261 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt @@ -8,7 +8,12 @@ interface FloconNavigationState { fun navigate(route: T) + // TODO Remove, since it's multiple window handling + // Maybe not if we instansiate one per window fun back(count: Int = 1) + + fun remove(route: FloconRoute) + } class MainFloconNavigationState(initialScreen: FloconRoute = LoadingRoute) : FloconNavigationState { @@ -34,6 +39,10 @@ class MainFloconNavigationState(initialScreen: FloconRoute = LoadingRoute) : Flo repeat(count) { _stack.removeLast() } } + override fun remove(route: FloconRoute) { + _stack.remove(route) + } + fun menu(route: FloconRoute) { _stack[0] = route } diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconRoute.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconRoute.kt index 49e4c8590..650530222 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconRoute.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconRoute.kt @@ -4,4 +4,4 @@ import androidx.navigation3.runtime.NavKey interface FloconRoute : NavKey -interface PanelRoute : FloconRoute +interface PanelRoute : NavKey diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt index 00fe8b133..7090691d9 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt @@ -26,13 +26,14 @@ import org.koin.core.component.KoinComponent @Immutable data class PanelScene( override val overlaidEntries: List>, - override val key: Any, override val previousEntries: List>, private val entry: NavEntry, private val properties: PaneProperties, private val onPin: OnPin?, private val onBack: () -> Unit, ) : OverlayScene, KoinComponent { + override val key: Any + get() = PanelScene::class.qualifiedName!! override val entries: List> = listOf(entry) @@ -49,7 +50,12 @@ data class PanelScene( onDismissRequest = onBack, actions = { FloconIconTonalButton( - onClick = onBack, + onClick = { + scope.launch { + state.hide() + onBack() + } + }, modifier = Modifier .animatePanelAction() ) { @@ -85,8 +91,6 @@ data class PanelScene( class PanelSceneStrategy : SceneStrategy { - var currentScene: PanelScene? = null - override fun SceneStrategyScope.calculateScene( entries: List> ): Scene? { @@ -94,33 +98,22 @@ class PanelSceneStrategy : SceneStrategy { val properties = lastEntry.metadata[PANEL_KEY] ?: return null if (properties is PaneProperties) { - return currentScene?.copy( - key = lastEntry.contentKey, - previousEntries = entries.dropLast(1), - overlaidEntries = entries.dropLast(1), - entry = lastEntry, - properties = properties, - onPin = lastEntry.metadata[ON_PIN] as? OnPin - ) ?: PanelScene( - key = lastEntry.contentKey, + return PanelScene( previousEntries = entries.dropLast(1), overlaidEntries = entries.dropLast(1), entry = lastEntry, properties = properties, onPin = lastEntry.metadata[ON_PIN] as? OnPin, - onBack = { - currentScene = null - onBack() - } + onBack = onBack ) - .also { currentScene = it } } return null } companion object { - private const val PANEL_KEY = "panel_key" + private val PANEL_KEY = PanelSceneStrategy::class.qualifiedName!! + private const val ON_PIN = "on_pin" fun panel( From 2fb2122eaacab25c46ff52f4c4dfb88fffb17465 Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 29 Oct 2025 19:39:34 +0100 Subject: [PATCH 21/28] fix: inner Panel --- .../library/designsystem/components/FloconAnimateVisibility.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt index ca8b604a9..26a42fc96 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt @@ -28,6 +28,7 @@ fun FloconAnimateVisibility( AnimatedContent( targetState = state, transitionSpec = transitionSpec, + contentKey = { it != null }, modifier = modifier ) { if (it != null) { From c364e84b43b407c70b7fc25d27d7ff8b9dc0f524 Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 29 Oct 2025 19:56:32 +0100 Subject: [PATCH 22/28] fix: Topbar --- .../openflocon/flocondesktop/app/AppAction.kt | 16 +++++ .../openflocon/flocondesktop/app/AppScreen.kt | 32 +++++++--- .../flocondesktop/app/AppViewModel.kt | 60 ++++++++++++++++++- .../openflocon/flocondesktop/app/MenuScene.kt | 28 +++------ 4 files changed, 106 insertions(+), 30 deletions(-) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt index bbcab3582..e6611e90d 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppAction.kt @@ -1,9 +1,25 @@ package io.github.openflocon.flocondesktop.app +import io.github.openflocon.flocondesktop.app.ui.model.DeviceAppUiModel +import io.github.openflocon.flocondesktop.app.ui.model.DeviceItemUiModel import io.github.openflocon.flocondesktop.app.ui.model.SubScreen internal sealed interface AppAction { data class SelectMenu(val menu: SubScreen) : AppAction + data class DeleteApp(val app: DeviceAppUiModel) : AppAction + + data class DeleteDevice(val device: DeviceItemUiModel) : AppAction + + data class SelectApp(val app: DeviceAppUiModel) : AppAction + + data class SelectDevice(val device: DeviceItemUiModel) : AppAction + + data object Record : AppAction + + data object Restart : AppAction + + data object Screenshoot : AppAction + } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt index bf3c102d9..7f2849030 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt @@ -13,6 +13,7 @@ import io.github.openflocon.flocondesktop.app.ui.buildLeftPanelState import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.app.ui.settings.settingsRoutes import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.LeftPanelView +import io.github.openflocon.flocondesktop.app.ui.view.topbar.MainScreenTopBar import io.github.openflocon.flocondesktop.features.analytics.analyticsRoutes import io.github.openflocon.flocondesktop.features.dashboard.dashboardRoutes import io.github.openflocon.flocondesktop.features.database.databaseRoutes @@ -60,13 +61,30 @@ private fun Content( sceneStrategy = PanelSceneStrategy() .then(WindowSceneStrategy()) .then(DialogSceneStrategy()) - .then(MenuSceneStrategy { - LeftPanelView( - state = menuState, - expanded = it, - onClickItem = { menu -> onAction(AppAction.SelectMenu(menu.screen)) } - ) - }) + .then( + MenuSceneStrategy( + menuContent = { + LeftPanelView( + state = menuState, + expanded = it, + onClickItem = { menu -> onAction(AppAction.SelectMenu(menu.screen)) } + ) + }, + topBarContent = { + MainScreenTopBar( + devicesState = uiState.deviceState, + appsState = uiState.appState, + recordState = uiState.recordState, + deleteApp = { onAction(AppAction.DeleteApp(it)) }, + deleteDevice = { onAction(AppAction.DeleteDevice(it)) }, + onDeviceSelected = { onAction(AppAction.SelectDevice(it)) }, + onAppSelected = { onAction(AppAction.SelectApp(it)) }, + onRecordClicked = { onAction(AppAction.Record) }, + onRestartClicked = { onAction(AppAction.Restart) }, + onTakeScreenshotClicked = { onAction(AppAction.Screenshoot) } + ) + } + )) .then(SinglePaneSceneStrategy()), modifier = Modifier .fillMaxSize() diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt index c664bdc34..506361b4e 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt @@ -37,12 +37,12 @@ internal class AppViewModel( startAdbForwardUseCase: StartAdbForwardUseCase, val navigationState: MainFloconNavigationState, private val initialSetupStateHolder: InitialSetupStateHolder, - dispatcherProvider: DispatcherProvider, + private val dispatcherProvider: DispatcherProvider, private val devicesDelegate: DevicesDelegate, private val takeScreenshotUseCase: TakeScreenshotUseCase, private val restartAppUseCase: RestartAppUseCase, private val recordVideoDelegate: RecordVideoDelegate, - private val feedbackDisplayer: FeedbackDisplayer + private val feedbackDisplayer: FeedbackDisplayer, ) : ViewModel(messagesServerDelegate) { private val contentState = MutableStateFlow( @@ -94,6 +94,13 @@ internal class AppViewModel( fun onAction(action: AppAction) { when (action) { is AppAction.SelectMenu -> onSelectMenu(action) + is AppAction.DeleteApp -> deleteApp(action) + is AppAction.DeleteDevice -> deleteDevice(action) + AppAction.Record -> onRecord() + AppAction.Restart -> onRestart() + AppAction.Screenshoot -> onTakeScreenshot() + is AppAction.SelectApp -> onAppSelected(action) + is AppAction.SelectDevice -> onDeviceSelected(action) } } @@ -115,4 +122,53 @@ internal class AppViewModel( ) } + private fun onDeviceSelected(action: AppAction.SelectDevice) { + viewModelScope.launch(dispatcherProvider.viewModel) { + devicesDelegate.select(action.device.id) + } + } + + private fun deleteDevice(action: AppAction.DeleteDevice) { + viewModelScope.launch(dispatcherProvider.viewModel) { + devicesDelegate.delete(action.device.id) + } + } + + private fun deleteApp(action: AppAction.DeleteApp) { + viewModelScope.launch(dispatcherProvider.viewModel) { + devicesDelegate.deleteApp(action.app.packageName) + } + } + + private fun onAppSelected(action: AppAction.SelectApp) { + viewModelScope.launch(dispatcherProvider.viewModel) { + devicesDelegate.selectApp(action.app.packageName) + } + } + + private fun onRecord() { + viewModelScope.launch(dispatcherProvider.viewModel) { + recordVideoDelegate.toggleRecording() + } + } + + private fun onRestart() { + viewModelScope.launch(dispatcherProvider.viewModel) { + restartAppUseCase() + } + } + + private fun onTakeScreenshot() { + viewModelScope.launch(dispatcherProvider.viewModel) { + takeScreenshotUseCase().fold( + doOnFailure = { + feedbackDisplayer.displayMessage(it.message ?: "Unknown error") + }, + doOnSuccess = { + feedbackDisplayer.displayMessage("Success, file saved at $it") + }, + ) + } + } + } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt index af4f48d11..572c501b7 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt @@ -34,12 +34,8 @@ import androidx.navigation3.runtime.NavEntry import androidx.navigation3.scene.Scene import androidx.navigation3.scene.SceneStrategy import androidx.navigation3.scene.SceneStrategyScope -import io.github.openflocon.flocondesktop.app.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.app.ui.model.RecordVideoStateUiModel import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.PanelMaxWidth import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.PanelMinWidth -import io.github.openflocon.flocondesktop.app.ui.view.topbar.MainScreenTopBar import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconIcon import io.github.openflocon.library.designsystem.components.FloconScaffold @@ -50,7 +46,8 @@ data class MenuScene( override val entries: List>, override val previousEntries: List>, val entry: NavEntry, - val menuContent: @Composable (expanded: Boolean) -> Unit + val menuContent: @Composable (expanded: Boolean) -> Unit, + val topBarContent: @Composable (() -> Unit)? ) : Scene { override val key: Any get() = Unit @@ -66,20 +63,7 @@ data class MenuScene( Box { FloconScaffold( - topBar = { - MainScreenTopBar( - devicesState = DevicesStateUiModel.Empty, - appsState = AppsStateUiModel.Empty, - recordState = RecordVideoStateUiModel.Recording, - deleteApp = {}, - deleteDevice = {}, - onDeviceSelected = {}, - onAppSelected = {}, - onRecordClicked = {}, - onRestartClicked = {}, - onTakeScreenshotClicked = {} - ) - }, + topBar = { topBarContent?.invoke() }, modifier = Modifier .fillMaxSize() .onGloballyPositioned { @@ -127,7 +111,8 @@ data class MenuScene( } class MenuSceneStrategy( - private val menuContent: @Composable (expanded: Boolean) -> Unit + private val menuContent: @Composable (expanded: Boolean) -> Unit, + private val topBarContent: @Composable (() -> Unit)? = null ) : SceneStrategy { override fun SceneStrategyScope.calculateScene(entries: List>): Scene? { @@ -138,7 +123,8 @@ class MenuSceneStrategy( entries = listOf(entry), previousEntries = entries.dropLast(1), entry = entry, - menuContent = menuContent + menuContent = menuContent, + topBarContent = topBarContent ) } From 5f9df0556dc46e6e8bf32d6bc63cf722f8be82ad Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 29 Oct 2025 19:57:33 +0100 Subject: [PATCH 23/28] feature: Remove files --- .../flocondesktop/app/ui/MenuUiState.kt | 24 --- .../flocondesktop/app/ui/MenuViewModel.kt | 181 ------------------ 2 files changed, 205 deletions(-) delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuUiState.kt delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuViewModel.kt diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuUiState.kt deleted file mode 100644 index f29ca47ec..000000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuUiState.kt +++ /dev/null @@ -1,24 +0,0 @@ -package io.github.openflocon.flocondesktop.app.ui - -import androidx.compose.runtime.Immutable -import io.github.openflocon.flocondesktop.app.ui.model.AppsStateUiModel -import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel -import io.github.openflocon.flocondesktop.app.ui.model.RecordVideoStateUiModel -import io.github.openflocon.flocondesktop.app.ui.model.SubScreen -import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPanelState -import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.previewLeftPannelState - -@Immutable -data class MenuUiState( - val leftPanelState: LeftPanelState, - val recordVideoState: RecordVideoStateUiModel, - val appsStateUiModel: AppsStateUiModel, - val devicesStateUiModel: DevicesStateUiModel -) - -fun previewMenuUiState() = MenuUiState( - leftPanelState = previewLeftPannelState(SubScreen.Network), - recordVideoState = RecordVideoStateUiModel.Idle, - appsStateUiModel = AppsStateUiModel.Empty, - devicesStateUiModel = DevicesStateUiModel.Empty -) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuViewModel.kt deleted file mode 100644 index 872af184b..000000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/MenuViewModel.kt +++ /dev/null @@ -1,181 +0,0 @@ -package io.github.openflocon.flocondesktop.app.ui - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import io.github.openflocon.domain.common.DispatcherProvider -import io.github.openflocon.domain.device.usecase.ObserveCurrentDeviceCapabilitiesUseCase -import io.github.openflocon.domain.device.usecase.RestartAppUseCase -import io.github.openflocon.domain.device.usecase.TakeScreenshotUseCase -import io.github.openflocon.domain.feedback.FeedbackDisplayer -import io.github.openflocon.flocondesktop.app.InitialSetupStateHolder -import io.github.openflocon.flocondesktop.app.ui.delegates.DevicesDelegate -import io.github.openflocon.flocondesktop.app.ui.delegates.RecordVideoDelegate -import io.github.openflocon.flocondesktop.app.ui.model.DeviceAppUiModel -import io.github.openflocon.flocondesktop.app.ui.model.DeviceItemUiModel -import io.github.openflocon.flocondesktop.app.ui.model.SubScreen -import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPanelItem -import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPanelState -import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPannelSection -import io.github.openflocon.flocondesktop.app.ui.view.displayName -import io.github.openflocon.flocondesktop.app.ui.view.icon -import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed -import io.github.openflocon.navigation.MainFloconNavigationState -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch -import org.koin.core.component.KoinComponent - -class MenuViewModel( - private val devicesDelegate: DevicesDelegate, - private val dispatcherProvider: DispatcherProvider, - private val initialSetupStateHolder: InitialSetupStateHolder, - private val takeScreenshotUseCase: TakeScreenshotUseCase, - private val restartAppUseCase: RestartAppUseCase, - private val recordVideoDelegate: RecordVideoDelegate, - private val feedbackDisplayer: FeedbackDisplayer, - private val observeCurrentDeviceCapabilitiesUseCase: ObserveCurrentDeviceCapabilitiesUseCase, - private val mainNavigationState: MainFloconNavigationState -) : ViewModel( - devicesDelegate, - recordVideoDelegate, -), KoinComponent { - - private val leftPanelState = MutableStateFlow(buildLeftPanelState(current = SubScreen.Network)) - - val uiState = combine( - leftPanelState, - recordVideoDelegate.state, - devicesDelegate.devicesState, - devicesDelegate.appsState - ) { content, record, device, apps -> - MenuUiState( - leftPanelState = content, - recordVideoState = record, - appsStateUiModel = apps, - devicesStateUiModel = device - ) - } - .stateInWhileSubscribed( - MenuUiState( - leftPanelState = leftPanelState.value, - recordVideoState = recordVideoDelegate.state.value, - devicesStateUiModel = devicesDelegate.devicesState.value, - appsStateUiModel = devicesDelegate.appsState.value - ) - ) - - init { - viewModelScope.launch(dispatcherProvider.viewModel) { - initialSetupStateHolder.needsAdbSetup.collect { - if (it) { -// menuNavigationState.navigate(SubScreen.Settings) - leftPanelState.update { state -> state.copy(current = SubScreen.Settings) } - } - } - } - } - - fun onDeviceSelected(device: DeviceItemUiModel) { - viewModelScope.launch(dispatcherProvider.viewModel) { - devicesDelegate.select(device.id) - } - } - - fun deleteDevice(device: DeviceItemUiModel) { - viewModelScope.launch(dispatcherProvider.viewModel) { - devicesDelegate.delete(device.id) - } - } - - fun deleteApp(app: DeviceAppUiModel) { - viewModelScope.launch(dispatcherProvider.viewModel) { - devicesDelegate.deleteApp(app.packageName) - } - } - - fun onAppSelected(app: DeviceAppUiModel) { - viewModelScope.launch(dispatcherProvider.viewModel) { - devicesDelegate.selectApp(app.packageName) - } - } - - fun onClickLeftPanelItem(leftPanelItem: LeftPanelItem) { - leftPanelState.update { state -> state.copy(current = leftPanelItem.screen) } -// menuNavigationState.navigate(leftPanelItem.screen) - } - - fun onRecordClicked() { - viewModelScope.launch(dispatcherProvider.viewModel) { - recordVideoDelegate.toggleRecording() - } - } - - fun onRestartClicked() { - viewModelScope.launch(dispatcherProvider.viewModel) { - restartAppUseCase() - } - } - - fun onTakeScreenshotClicked() { - viewModelScope.launch(dispatcherProvider.viewModel) { - takeScreenshotUseCase().fold( - doOnFailure = { - feedbackDisplayer.displayMessage(it.message ?: "Unknown error") - }, - doOnSuccess = { - feedbackDisplayer.displayMessage("Success, file saved at $it") - }, - ) - } - } -} - -internal fun buildLeftPanelState(current: SubScreen) = LeftPanelState( - current = current, - bottomItems = listOf( - item(subScreen = SubScreen.Settings) - ), - sections = listOf( - LeftPannelSection( - title = "Network", - items = listOf( - item(subScreen = SubScreen.Network), - item(subScreen = SubScreen.Images), - ), - ), - LeftPannelSection( - title = "Storage", - items = listOf( - item(SubScreen.Database), - item(SubScreen.SharedPreferences), - item(SubScreen.Files), - ), - ), - LeftPannelSection( - title = "Data", - items = listOf( - item(SubScreen.Dashboard), - item(SubScreen.Analytics), - item(SubScreen.Tables), - ), - ), - LeftPannelSection( - title = "Actions", - items = listOf( - item(SubScreen.Deeplinks) - ), - ), - ), -) - -private fun item( - subScreen: SubScreen -): LeftPanelItem { - return LeftPanelItem( - screen = subScreen, - icon = subScreen.icon(), - text = subScreen.displayName(), - isEnabled = true - ) -} From 0cec6cf941bef233e4384f6622715efea5508565 Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 29 Oct 2025 20:01:00 +0100 Subject: [PATCH 24/28] fix: Discussion --- .../navigation/ExampleInstrumentedTest.kt | 24 ------------------- .../openflocon/navigation/ExampleUnitTest.kt | 16 ------------- .../src/androidMain/AndroidManifest.xml | 4 ---- 3 files changed, 44 deletions(-) delete mode 100644 FloconDesktop/navigation/src/androidDeviceTest/kotlin/io/github/openflocon/navigation/ExampleInstrumentedTest.kt delete mode 100644 FloconDesktop/navigation/src/androidHostTest/kotlin/io/github/openflocon/navigation/ExampleUnitTest.kt delete mode 100644 FloconDesktop/navigation/src/androidMain/AndroidManifest.xml diff --git a/FloconDesktop/navigation/src/androidDeviceTest/kotlin/io/github/openflocon/navigation/ExampleInstrumentedTest.kt b/FloconDesktop/navigation/src/androidDeviceTest/kotlin/io/github/openflocon/navigation/ExampleInstrumentedTest.kt deleted file mode 100644 index 7e645936f..000000000 --- a/FloconDesktop/navigation/src/androidDeviceTest/kotlin/io/github/openflocon/navigation/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package io.github.openflocon.navigation - -import android.support.test.InstrumentationRegistry -import android.support.test.runner.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("io.github.openflocon.navigation.test", appContext.packageName) - } -} diff --git a/FloconDesktop/navigation/src/androidHostTest/kotlin/io/github/openflocon/navigation/ExampleUnitTest.kt b/FloconDesktop/navigation/src/androidHostTest/kotlin/io/github/openflocon/navigation/ExampleUnitTest.kt deleted file mode 100644 index 87dbe2c42..000000000 --- a/FloconDesktop/navigation/src/androidHostTest/kotlin/io/github/openflocon/navigation/ExampleUnitTest.kt +++ /dev/null @@ -1,16 +0,0 @@ -package io.github.openflocon.navigation - -import kotlin.test.Test -import kotlin.test.assertEquals - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} \ No newline at end of file diff --git a/FloconDesktop/navigation/src/androidMain/AndroidManifest.xml b/FloconDesktop/navigation/src/androidMain/AndroidManifest.xml deleted file mode 100644 index a5918e68a..000000000 --- a/FloconDesktop/navigation/src/androidMain/AndroidManifest.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file From 52c98950ac6a36bf7bb20cb5b0962c8c4235b52b Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Wed, 29 Oct 2025 20:13:56 +0100 Subject: [PATCH 25/28] feature: Dialog & rename --- .../openflocon/flocondesktop/app/AppScreen.kt | 17 +-- .../flocondesktop/app/AppUiState.kt | 5 + .../flocondesktop/app/AppViewModel.kt | 9 +- .../{LeftPanelItem.kt => MenuItem.kt} | 2 +- .../{LeftPannelSection.kt => MenuSection.kt} | 4 +- .../app/ui/model/leftpanel/MenuUiState.kt | 83 ++++++++++++--- .../app/ui/view/leftpannel/LeftPannelView.kt | 22 ++-- .../features/network/Navigation.kt | 9 +- .../network/body/model/ContentUiState.kt | 9 -- .../features/network/list/NetworkViewModel.kt | 19 +--- .../network/list/model/NetworkAction.kt | 4 +- .../network/list/view/NetworkScreen.kt | 11 -- .../mock/list/view/NetworkMocksScreen.kt | 24 ++--- .../designsystem/components/FloconDialog.kt | 7 +- .../navigation/scene/DialogScene.kt | 100 ++++++++++++++++++ 15 files changed, 212 insertions(+), 113 deletions(-) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/{LeftPanelItem.kt => MenuItem.kt} (93%) rename FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/{LeftPannelSection.kt => MenuSection.kt} (58%) create mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/DialogScene.kt diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt index 7f2849030..6baaa32d9 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppScreen.kt @@ -4,13 +4,9 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.produceState import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation3.scene.DialogSceneStrategy import androidx.navigation3.scene.SinglePaneSceneStrategy -import io.github.openflocon.flocondesktop.app.ui.buildLeftPanelState -import io.github.openflocon.flocondesktop.app.ui.model.SubScreen import io.github.openflocon.flocondesktop.app.ui.settings.settingsRoutes import io.github.openflocon.flocondesktop.app.ui.view.leftpannel.LeftPanelView import io.github.openflocon.flocondesktop.app.ui.view.topbar.MainScreenTopBar @@ -26,6 +22,7 @@ import io.github.openflocon.flocondesktop.features.table.tableRoutes import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.navigation.FloconNavigation import io.github.openflocon.navigation.MainFloconNavigationState +import io.github.openflocon.navigation.scene.DialogSceneStrategy import io.github.openflocon.navigation.scene.PanelSceneStrategy import io.github.openflocon.navigation.scene.WindowSceneStrategy import org.koin.compose.viewmodel.koinViewModel @@ -48,14 +45,6 @@ private fun Content( navigationState: MainFloconNavigationState, onAction: (AppAction) -> Unit ) { - // TODO Redo - val menuState by produceState( - buildLeftPanelState(SubScreen.Network), - uiState.contentState.current - ) { - value = buildLeftPanelState(uiState.contentState.current) - } - FloconNavigation( navigationState = navigationState, sceneStrategy = PanelSceneStrategy() @@ -65,7 +54,7 @@ private fun Content( MenuSceneStrategy( menuContent = { LeftPanelView( - state = menuState, + state = uiState.menuState, expanded = it, onClickItem = { menu -> onAction(AppAction.SelectMenu(menu.screen)) } ) @@ -96,7 +85,7 @@ private fun Content( deeplinkRoutes() filesRoutes() imageRoutes() - networkRoutes(navigationState) + networkRoutes() sharedPreferencesRoutes() tableRoutes() settingsRoutes() diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppUiState.kt index fd8ede054..618a3c680 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppUiState.kt @@ -4,12 +4,16 @@ import androidx.compose.runtime.Immutable import io.github.openflocon.flocondesktop.app.ui.model.AppsStateUiModel import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel import io.github.openflocon.flocondesktop.app.ui.model.RecordVideoStateUiModel +import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.MenuState +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.previewMenuState import io.github.openflocon.flocondesktop.app.ui.model.previewAppsStateUiModel import io.github.openflocon.flocondesktop.app.ui.model.previewDevicesStateUiModel @Immutable data class AppUiState( val contentState: ContentUiState, + val menuState: MenuState, val deviceState: DevicesStateUiModel, val appState: AppsStateUiModel, val recordState: RecordVideoStateUiModel @@ -17,6 +21,7 @@ data class AppUiState( fun previewAppUiState() = AppUiState( contentState = previewContentUiState(), + menuState = previewMenuState(SubScreen.Network), deviceState = previewDevicesStateUiModel(), appState = previewAppsStateUiModel(), recordState = RecordVideoStateUiModel.Recording diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt index 506361b4e..ffe43724b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/AppViewModel.kt @@ -11,6 +11,7 @@ import io.github.openflocon.domain.settings.usecase.StartAdbForwardUseCase import io.github.openflocon.flocondesktop.app.ui.delegates.DevicesDelegate import io.github.openflocon.flocondesktop.app.ui.delegates.RecordVideoDelegate import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.buildMenu import io.github.openflocon.flocondesktop.app.ui.settings.SettingsRoutes import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed import io.github.openflocon.flocondesktop.features.analytics.AnalyticsRoutes @@ -50,15 +51,20 @@ internal class AppViewModel( current = SubScreen.Network ) ) + private val menuState = MutableStateFlow( + buildMenu(SubScreen.Network) + ) val uiState = combine( contentState, + menuState, devicesDelegate.devicesState, devicesDelegate.appsState, recordVideoDelegate.state - ) { content, devices, apps, record -> + ) { content, menu, devices, apps, record -> AppUiState( contentState = content, + menuState = menu, deviceState = devices, appState = apps, recordState = record @@ -67,6 +73,7 @@ internal class AppViewModel( .stateInWhileSubscribed( AppUiState( contentState = contentState.value, + menuState = menuState.value, deviceState = devicesDelegate.devicesState.value, appState = devicesDelegate.appsState.value, recordState = recordVideoDelegate.state.value diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/LeftPanelItem.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/MenuItem.kt similarity index 93% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/LeftPanelItem.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/MenuItem.kt index f27edbe73..ba57fd13a 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/LeftPanelItem.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/MenuItem.kt @@ -5,7 +5,7 @@ import androidx.compose.ui.graphics.vector.ImageVector import io.github.openflocon.flocondesktop.app.ui.model.SubScreen @Immutable -data class LeftPanelItem( +data class MenuItem( val screen: SubScreen, val icon: ImageVector, val text: String, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/LeftPannelSection.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/MenuSection.kt similarity index 58% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/LeftPannelSection.kt rename to FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/MenuSection.kt index a65c7c373..3ae0e0e28 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/LeftPannelSection.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/MenuSection.kt @@ -1,6 +1,6 @@ package io.github.openflocon.flocondesktop.app.ui.model.leftpanel -data class LeftPannelSection( +data class MenuSection( val title: String, - val items: List, + val items: List, ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/MenuUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/MenuUiState.kt index dc2fd2b79..f4c8d1dd2 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/MenuUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/model/leftpanel/MenuUiState.kt @@ -4,18 +4,20 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Settings import androidx.compose.runtime.Immutable import io.github.openflocon.flocondesktop.app.ui.model.SubScreen +import io.github.openflocon.flocondesktop.app.ui.view.displayName +import io.github.openflocon.flocondesktop.app.ui.view.icon @Immutable -data class LeftPanelState( +data class MenuState( val current: SubScreen, - val sections: List, - val bottomItems: List, + val sections: List, + val bottomItems: List, ) -fun previewLeftPannelState(current: SubScreen) = LeftPanelState( +fun previewMenuState(current: SubScreen) = MenuState( current = current, bottomItems = listOf( - LeftPanelItem( + MenuItem( screen = SubScreen.Settings, icon = Icons.Outlined.Settings, text = "Settings", @@ -23,22 +25,22 @@ fun previewLeftPannelState(current: SubScreen) = LeftPanelState( ), ), sections = listOf( - LeftPannelSection( + MenuSection( title = "Network", items = listOf( - LeftPanelItem( + MenuItem( screen = SubScreen.Network, icon = Icons.Outlined.Settings, text = "Http", isEnabled = true, ), - LeftPanelItem( + MenuItem( screen = SubScreen.Images, icon = Icons.Outlined.Settings, text = "Images", isEnabled = true, ), - LeftPanelItem( + MenuItem( screen = SubScreen.Network, icon = Icons.Outlined.Settings, text = "Grpc", @@ -46,22 +48,22 @@ fun previewLeftPannelState(current: SubScreen) = LeftPanelState( ), ), ), - LeftPannelSection( + MenuSection( title = "Storage", items = listOf( - LeftPanelItem( + MenuItem( screen = SubScreen.Network, icon = Icons.Outlined.Settings, text = "Database", isEnabled = true, ), - LeftPanelItem( + MenuItem( screen = SubScreen.SharedPreferences, icon = Icons.Outlined.Settings, text = "SharedPreferences", isEnabled = true, ), - LeftPanelItem( + MenuItem( screen = SubScreen.Files, icon = Icons.Outlined.Settings, text = "Files", @@ -69,16 +71,16 @@ fun previewLeftPannelState(current: SubScreen) = LeftPanelState( ), ), ), - LeftPannelSection( + MenuSection( title = "Data", items = listOf( - LeftPanelItem( + MenuItem( screen = SubScreen.Dashboard, icon = Icons.Outlined.Settings, text = "Dashboard", isEnabled = true, ), - LeftPanelItem( + MenuItem( screen = SubScreen.Tables, icon = Icons.Outlined.Settings, text = "Tables", @@ -88,3 +90,52 @@ fun previewLeftPannelState(current: SubScreen) = LeftPanelState( ), ), ) + +internal fun buildMenu(current: SubScreen) = MenuState( + current = current, + bottomItems = listOf( + item(subScreen = SubScreen.Settings) + ), + sections = listOf( + MenuSection( + title = "Network", + items = listOf( + item(subScreen = SubScreen.Network), + item(subScreen = SubScreen.Images), + ), + ), + MenuSection( + title = "Storage", + items = listOf( + item(SubScreen.Database), + item(SubScreen.SharedPreferences), + item(SubScreen.Files), + ), + ), + MenuSection( + title = "Data", + items = listOf( + item(SubScreen.Dashboard), + item(SubScreen.Analytics), + item(SubScreen.Tables), + ), + ), + MenuSection( + title = "Actions", + items = listOf( + item(SubScreen.Deeplinks) + ), + ), + ), +) + +private fun item( + subScreen: SubScreen +): MenuItem { + return MenuItem( + screen = subScreen, + icon = subScreen.icon(), + text = subScreen.displayName(), + isEnabled = true + ) +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/LeftPannelView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/LeftPannelView.kt index 8ec74bfcf..07e8246a7 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/LeftPannelView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/ui/view/leftpannel/LeftPannelView.kt @@ -21,10 +21,10 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEachIndexed import io.github.openflocon.flocondesktop.app.ui.model.SubScreen -import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPanelItem -import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPanelState -import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.LeftPannelSection -import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.previewLeftPannelState +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.MenuItem +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.MenuState +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.MenuSection +import io.github.openflocon.flocondesktop.app.ui.model.leftpanel.previewMenuState import io.github.openflocon.library.designsystem.FloconTheme val PanelMaxWidth = 275.dp @@ -33,9 +33,9 @@ val PanelContentMinSize = 40.dp @Composable fun LeftPanelView( - state: LeftPanelState, + state: MenuState, expanded: Boolean, - onClickItem: (LeftPanelItem) -> Unit, + onClickItem: (MenuItem) -> Unit, modifier: Modifier = Modifier, ) { Column( @@ -64,9 +64,9 @@ fun LeftPanelView( @Composable private fun ColumnScope.MenuSection( current: SubScreen, - items: List, + items: List, expanded: Boolean, - onClickItem: (LeftPanelItem) -> Unit, + onClickItem: (MenuItem) -> Unit, ) { items.fastForEachIndexed { index, section -> PannelLabel( @@ -85,9 +85,9 @@ private fun ColumnScope.MenuSection( @Composable private fun ColumnScope.MenuItems( current: SubScreen, - items: List, + items: List, expanded: Boolean, - onClickItem: (LeftPanelItem) -> Unit, + onClickItem: (MenuItem) -> Unit, ) { items.fastForEachIndexed { index, item -> PanelView( @@ -114,7 +114,7 @@ private fun LeftPanelViewPreview() { FloconTheme { Box(modifier = Modifier.background(Color.White)) LeftPanelView( - state = previewLeftPannelState( + state = previewMenuState( current = selectedItem.value, ), onClickItem = { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt index 0b983e6bc..14bd458a1 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/Navigation.kt @@ -8,7 +8,6 @@ import io.github.openflocon.flocondesktop.features.network.detail.view.NetworkDe import io.github.openflocon.flocondesktop.features.network.list.view.NetworkScreen import io.github.openflocon.flocondesktop.features.network.mock.list.view.NetworkMocksWindow import io.github.openflocon.navigation.FloconRoute -import io.github.openflocon.navigation.MainFloconNavigationState import io.github.openflocon.navigation.PanelRoute import io.github.openflocon.navigation.scene.PanelSceneStrategy import kotlinx.serialization.Serializable @@ -20,14 +19,14 @@ internal sealed interface NetworkRoutes : FloconRoute { data object Main : NetworkRoutes @Serializable - data object Mocks : NetworkRoutes + data class Mocks(val id: String?) : NetworkRoutes @Serializable data class Panel(val requestId: String) : NetworkRoutes, PanelRoute } -fun EntryProviderScope.networkRoutes(navigationState: MainFloconNavigationState) { +fun EntryProviderScope.networkRoutes() { entry( metadata = MenuSceneStrategy.menu() ) { @@ -50,9 +49,7 @@ fun EntryProviderScope.networkRoutes(navigationState: MainFloconNav metadata = DialogSceneStrategy.dialog() ) { NetworkMocksWindow( - instanceId = "instance", - fromNetworkCallId = null, - onCloseRequest = { navigationState.remove(it) } + fromNetworkCallId = it.id ) } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/body/model/ContentUiState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/body/model/ContentUiState.kt index c8a13543f..bfae7ef4b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/body/model/ContentUiState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/body/model/ContentUiState.kt @@ -2,27 +2,18 @@ package io.github.openflocon.flocondesktop.features.network.body.model import androidx.compose.runtime.Immutable import io.github.openflocon.flocondesktop.features.network.model.NetworkBodyDetailUi -import java.util.UUID @Immutable data class ContentUiState( val selectedRequestId: String?, val detailJsons: Set, - val mocksDisplayed: MockDisplayed?, val websocketMocksDisplayed: Boolean, val badNetworkQualityDisplayed: Boolean ) -@Immutable -data class MockDisplayed( - val fromNetworkCallId: String?, - val windowInstanceId: String = UUID.randomUUID().toString(), -) - fun previewContentUiState() = ContentUiState( selectedRequestId = null, detailJsons = emptySet(), - mocksDisplayed = null, badNetworkQualityDisplayed = false, websocketMocksDisplayed = false ) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt index ec38e3db9..faf76b972 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/NetworkViewModel.kt @@ -94,7 +94,6 @@ class NetworkViewModel( ContentUiState( selectedRequestId = null, detailJsons = emptySet(), - mocksDisplayed = null, badNetworkQualityDisplayed = false, websocketMocksDisplayed = false ) @@ -230,7 +229,6 @@ class NetworkViewModel( is NetworkAction.OpenBadNetworkQuality -> openBadNetworkQuality() is NetworkAction.CloseBadNetworkQuality -> closeBadNetworkQuality() - is NetworkAction.CloseMocks -> closeMocks() is NetworkAction.CopyCUrl -> onCopyCUrl(action) is NetworkAction.CopyUrl -> onCopyUrl(action) is NetworkAction.Remove -> onRemove(action) @@ -335,14 +333,7 @@ class NetworkViewModel( } private fun openMocks(callId: String?) { - navigationState.navigate(NetworkRoutes.Mocks) -// contentState.update { state -> -// state.copy( -// mocksDisplayed = MockDisplayed( -// fromNetworkCallId = callId, -// ), -// ) -// } + navigationState.navigate(NetworkRoutes.Mocks(callId)) } private fun openWebsocketMocks() { @@ -353,14 +344,6 @@ class NetworkViewModel( } } - private fun closeMocks() { - contentState.update { state -> - state.copy( - mocksDisplayed = null, - ) - } - } - private fun openBadNetworkQuality() { contentState.update { state -> state.copy( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkAction.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkAction.kt index fa2280b32..32e249666 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkAction.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/model/NetworkAction.kt @@ -21,7 +21,6 @@ sealed interface NetworkAction { data class CreateMock(val item: NetworkItemViewState) : NetworkAction data object OpenMocks : NetworkAction - data object CloseMocks : NetworkAction data object OpenWebsocketMocks : NetworkAction @@ -48,7 +47,7 @@ sealed interface NetworkAction { data class Pinned(val value: Boolean) : NetworkAction - data class ToggleAutoScroll(val value: Boolean): NetworkAction + data class ToggleAutoScroll(val value: Boolean) : NetworkAction data object ClearOldSession : NetworkAction @@ -65,6 +64,7 @@ sealed interface NetworkAction { data class Request(val item: NetworkDetailViewState) : OpenBodyExternally data class Response(val item: NetworkDetailViewState.Response.Success) : OpenBodyExternally } + sealed interface HeaderAction : NetworkAction { data class ClickOnSort( val type: NetworkColumnsTypeUiModel, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt index 414772180..4bd7ae70d 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt @@ -57,7 +57,6 @@ import io.github.openflocon.flocondesktop.features.network.list.model.previewNet import io.github.openflocon.flocondesktop.features.network.list.model.previewNetworkUiState import io.github.openflocon.flocondesktop.features.network.list.view.components.FilterBar import io.github.openflocon.flocondesktop.features.network.list.view.header.NetworkItemHeaderView -import io.github.openflocon.flocondesktop.features.network.mock.list.view.NetworkMocksWindow import io.github.openflocon.flocondesktop.features.network.model.NetworkBodyDetailUi import io.github.openflocon.flocondesktop.features.network.view.NetworkBodyWindow import io.github.openflocon.flocondesktop.features.network.websocket.NetworkWebsocketMockWindow @@ -370,16 +369,6 @@ fun NetworkScreen( } } - uiState.contentState.mocksDisplayed?.let { - NetworkMocksWindow( - instanceId = it.windowInstanceId, - fromNetworkCallId = it.fromNetworkCallId, - onCloseRequest = { - onAction(NetworkAction.CloseMocks) - }, - ) - } - if (uiState.contentState.badNetworkQualityDisplayed) { BadNetworkQualityWindow( onCloseRequest = { diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt index 95dd38971..ab99ddb5a 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt @@ -13,17 +13,14 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.key import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import io.github.openflocon.flocondesktop.features.network.mock.NetworkMocksViewModel -import io.github.openflocon.flocondesktop.features.network.mock.edition.view.NetworkEditionWindow import io.github.openflocon.flocondesktop.features.network.mock.list.model.MockNetworkLineUiModel import io.github.openflocon.flocondesktop.features.network.mock.list.model.previewMockNetworkLineUiModel import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconButton -import io.github.openflocon.library.designsystem.components.FloconDialog import io.github.openflocon.library.designsystem.components.FloconDialogHeader import io.github.openflocon.library.designsystem.components.FloconDropdownMenuItem import io.github.openflocon.library.designsystem.components.FloconOverflow @@ -33,9 +30,7 @@ import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable fun NetworkMocksWindow( - instanceId: String, - fromNetworkCallId: String?, - onCloseRequest: () -> Unit, + fromNetworkCallId: String? ) { val viewModel: NetworkMocksViewModel = koinViewModel() LaunchedEffect(viewModel, fromNetworkCallId) { @@ -43,16 +38,12 @@ fun NetworkMocksWindow( } val mocks by viewModel.items.collectAsStateWithLifecycle() val editionWindow by viewModel.editionWindow.collectAsStateWithLifecycle() - key(instanceId) { -// FloconDialog( -// onDismissRequest = onCloseRequest, -// ) { - NetworkMocksContent( - mocks = mocks, - modifier = Modifier.fillMaxWidth(), - onAction = viewModel::onAction, - ) -// } + + NetworkMocksContent( + mocks = mocks, + modifier = Modifier.fillMaxWidth(), + onAction = viewModel::onAction, + ) // editionWindow?.let { // NetworkEditionWindow( @@ -63,7 +54,6 @@ fun NetworkMocksWindow( // onSave = viewModel::addMock, // ) // } - } } sealed interface NetworkMockAction { diff --git a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconDialog.kt b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconDialog.kt index 0abcb678c..adb2f4c85 100644 --- a/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconDialog.kt +++ b/FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconDialog.kt @@ -3,13 +3,10 @@ package io.github.openflocon.library.designsystem.components import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.RoundedCornerShape @@ -18,7 +15,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties @@ -29,11 +25,12 @@ import io.github.openflocon.library.designsystem.components.escape.EscapeHandler fun FloconDialog( onDismissRequest: () -> Unit, modifier: Modifier = Modifier, + properties: DialogProperties = DialogProperties(), content: @Composable () -> Unit ) { Dialog( onDismissRequest = onDismissRequest, - properties = DialogProperties(), + properties = properties, ) { EscapeHandler { onDismissRequest() diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/DialogScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/DialogScene.kt new file mode 100644 index 000000000..4228108ab --- /dev/null +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/DialogScene.kt @@ -0,0 +1,100 @@ +package io.github.openflocon.navigation.scene + +import androidx.compose.runtime.Composable +import androidx.compose.ui.window.DialogProperties +import androidx.navigation3.runtime.NavEntry +import androidx.navigation3.scene.OverlayScene +import androidx.navigation3.scene.Scene +import androidx.navigation3.scene.SceneStrategy +import androidx.navigation3.scene.SceneStrategyScope +import io.github.openflocon.library.designsystem.components.FloconDialog +import io.github.openflocon.navigation.scene.DialogSceneStrategy.Companion.dialog + +/** + * Copy pasta from default scene strategy, to impl ours + */ +internal class DialogScene( + override val key: Any, + private val entry: NavEntry, + override val previousEntries: List>, + override val overlaidEntries: List>, + private val dialogProperties: DialogProperties, + private val onBack: () -> Unit, +) : OverlayScene { + + override val entries: List> = listOf(entry) + + override val content: @Composable (() -> Unit) = { + FloconDialog( + onDismissRequest = onBack, + properties = dialogProperties + ) { + entry.Content() + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as DialogScene<*> + + return key == other.key && + previousEntries == other.previousEntries && + overlaidEntries == other.overlaidEntries && + entry == other.entry && + dialogProperties == other.dialogProperties + } + + override fun hashCode(): Int { + return key.hashCode() * 31 + + previousEntries.hashCode() * 31 + + overlaidEntries.hashCode() * 31 + + entry.hashCode() * 31 + + dialogProperties.hashCode() * 31 + } + + override fun toString(): String { + return "DialogScene(key=$key, entry=$entry, previousEntries=$previousEntries, overlaidEntries=$overlaidEntries, dialogProperties=$dialogProperties)" + } +} + +/** + * A [SceneStrategy] that displays entries that have added [dialog] to their [NavEntry.metadata] + * within a [Dialog] instance. + * + * This strategy should always be added before any non-overlay scene strategies. + */ +public class DialogSceneStrategy() : SceneStrategy { + + public override fun SceneStrategyScope.calculateScene( + entries: List> + ): Scene? { + val lastEntry = entries.lastOrNull() + val dialogProperties = lastEntry?.metadata?.get(DIALOG_KEY) as? DialogProperties + return dialogProperties?.let { properties -> + DialogScene( + key = lastEntry.contentKey, + entry = lastEntry, + previousEntries = entries.dropLast(1), + overlaidEntries = entries.dropLast(1), + dialogProperties = properties, + onBack = onBack, + ) + } + } + + public companion object { + /** + * Function to be called on the [NavEntry.metadata] to mark this entry as something that + * should be displayed within a [Dialog]. + * + * @param dialogProperties properties that should be passed to the containing [Dialog]. + */ + public fun dialog( + dialogProperties: DialogProperties = DialogProperties() + ): Map = mapOf(DIALOG_KEY to dialogProperties) + + internal const val DIALOG_KEY = "dialog" + } +} From 5316d168220b85d4daf65207f8a46af162e0d3ee Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Mon, 3 Nov 2025 15:19:17 +0100 Subject: [PATCH 26/28] feature: Add inner scene --- .../navigation/scene/InnerWindowScene.kt | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/InnerWindowScene.kt diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/InnerWindowScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/InnerWindowScene.kt new file mode 100644 index 000000000..0de24f05d --- /dev/null +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/InnerWindowScene.kt @@ -0,0 +1,98 @@ +package io.github.openflocon.navigation.scene + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.sharp.Close +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.dp +import androidx.navigation3.runtime.NavEntry +import androidx.navigation3.scene.OverlayScene +import androidx.navigation3.scene.Scene +import androidx.navigation3.scene.SceneStrategy +import androidx.navigation3.scene.SceneStrategyScope +import io.github.openflocon.library.designsystem.FloconTheme +import io.github.openflocon.library.designsystem.components.FloconIcon +import io.github.openflocon.library.designsystem.components.FloconIconTonalButton +import io.github.openflocon.library.designsystem.components.FloconSurface + +@Immutable +internal data class InnerWindowScene( + override val key: Any, + private val entry: NavEntry, + override val previousEntries: List>, + override val overlaidEntries: List>, + private val onBack: () -> Unit, +) : OverlayScene { + + override val entries: List> = listOf(entry) + + override val content: @Composable (() -> Unit) = { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .fillMaxSize() + .background(Color.Black.copy(alpha = 0.5f)) + .clickable(onClick = onBack, indication = null, interactionSource = remember { MutableInteractionSource() }) + ) { + FloconSurface( + shape = FloconTheme.shapes.small, + modifier = Modifier.fillMaxSize(0.9f) + ) { + entry.Content() + } + FloconIconTonalButton( + onClick = onBack, + modifier = Modifier + .align(Alignment.TopEnd) + .offset { + IntOffset( + x = -16.dp.roundToPx(), + y = 16.dp.roundToPx() + ) + } + ) { + FloconIcon( + imageVector = Icons.Sharp.Close + ) + } + } + } +} + +public class InnerWindowSceneStrategy() : SceneStrategy { + + public override fun SceneStrategyScope.calculateScene( + entries: List> + ): Scene? { + val lastEntry = entries.lastOrNull() ?: return null + + if (lastEntry.metadata[INNER_WINDOW_KEY] == true) { + return InnerWindowScene( + key = lastEntry.contentKey, + entry = lastEntry, + previousEntries = entries.dropLast(1), + overlaidEntries = entries.dropLast(1), + onBack = onBack, + ) + } + + return null + } + + public companion object { + private val INNER_WINDOW_KEY = InnerWindowScene::class.qualifiedName!! + + public fun innerWindow(): Map = mapOf(INNER_WINDOW_KEY to true) + } +} From c8d1bb6dbd9d7d7b1a539a0ebc1fb56818db97df Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Mon, 10 Nov 2025 09:54:22 +0100 Subject: [PATCH 27/28] fix: Discussion --- .../network/detail/model/NetworkDetailHeaderUi.kt | 2 -- .../network/detail/model/NetworkDetailViewState.kt | 10 +--------- .../openflocon/navigation/FloconNavigationState.kt | 3 +++ 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailHeaderUi.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailHeaderUi.kt index e7b3a64c8..aa1e7ab4f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailHeaderUi.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailHeaderUi.kt @@ -1,10 +1,8 @@ package io.github.openflocon.flocondesktop.features.network.detail.model import androidx.compose.runtime.Immutable -import kotlinx.serialization.Serializable @Immutable -@Serializable data class NetworkDetailHeaderUi( val name: String, val value: String, diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailViewState.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailViewState.kt index 82a92efa5..5d0d47274 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailViewState.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/detail/model/NetworkDetailViewState.kt @@ -3,10 +3,8 @@ package io.github.openflocon.flocondesktop.features.network.detail.model import androidx.compose.runtime.Immutable import io.github.openflocon.flocondesktop.features.network.list.model.NetworkMethodUi import io.github.openflocon.flocondesktop.features.network.list.model.NetworkStatusUi -import kotlinx.serialization.Serializable @Immutable -@Serializable data class NetworkDetailViewState( val callId: String, val fullUrl: String, @@ -32,10 +30,8 @@ data class NetworkDetailViewState( val response: Response?, ) { @Immutable - @Serializable sealed interface Response { @Immutable - @Serializable data class Success( val body: String, val responseBodyIsNotBlank: Boolean, @@ -43,15 +39,14 @@ data class NetworkDetailViewState( val size: String, val headers: List?, ) : Response + @Immutable - @Serializable data class Error( val issue: String, ) : Response } @Immutable - @Serializable data class GraphQlSection( val queryName: String, val method: NetworkMethodUi, @@ -59,14 +54,11 @@ data class NetworkDetailViewState( ) @Immutable - @Serializable sealed interface Method { @Immutable - @Serializable data class Http(val method: NetworkMethodUi) : Method @Immutable - @Serializable data class MethodName(val name: String) : Method } } diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt index c4422d261..4429a8cfa 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/FloconNavigationState.kt @@ -1,8 +1,10 @@ package io.github.openflocon.navigation +import androidx.compose.runtime.Immutable import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.snapshots.SnapshotStateList +@Immutable interface FloconNavigationState { val stack: SnapshotStateList @@ -16,6 +18,7 @@ interface FloconNavigationState { } +@Immutable class MainFloconNavigationState(initialScreen: FloconRoute = LoadingRoute) : FloconNavigationState { private val _stack = mutableStateListOf(initialScreen) From 49f0dfc14be41ec247d98ad66526454b5aa0d2eb Mon Sep 17 00:00:00 2001 From: TEYSSANDIER Raphael Date: Mon, 10 Nov 2025 14:20:51 +0100 Subject: [PATCH 28/28] fix: Discussion --- .../openflocon/flocondesktop/app/MenuScene.kt | 2 +- .../analytics/AnalyticsDetailViewModel.kt | 34 +++++++++++++++++++ .../features/analytics/AnalyticsViewModel.kt | 16 +++------ .../flocondesktop/features/analytics/DI.kt | 1 + .../features/analytics/Navigation.kt | 18 ++++++++++ .../analytics/view/AnalyticsDetailView.kt | 34 ++++++++++++++----- .../analytics/view/AnalyticsScreen.kt | 25 +++++--------- .../list/view/BadNetworkQualityWindow.kt | 1 - .../list/view/NetworkBadQualityContent.kt | 1 - .../network/list/view/NetworkScreen.kt | 4 +-- .../mock/list/view/NetworkMocksScreen.kt | 19 ++++++----- .../openflocon/navigation/scene/PanelScene.kt | 2 +- 12 files changed, 105 insertions(+), 52 deletions(-) create mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/AnalyticsDetailViewModel.kt diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt index 572c501b7..d88cce8c7 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/MenuScene.kt @@ -53,7 +53,7 @@ data class MenuScene( get() = Unit override val content: @Composable (() -> Unit) = { - var expanded by remember { mutableStateOf(false) } + var expanded by remember { mutableStateOf(true) } val width by animateDpAsState(targetValue = if (expanded) PanelMaxWidth else PanelMinWidth) var windowSize by remember { mutableStateOf(IntSize.Zero) } val position by animateDpAsState( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/AnalyticsDetailViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/AnalyticsDetailViewModel.kt new file mode 100644 index 000000000..5cfa921c0 --- /dev/null +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/AnalyticsDetailViewModel.kt @@ -0,0 +1,34 @@ +package io.github.openflocon.flocondesktop.features.analytics + +import androidx.lifecycle.ViewModel +import io.github.openflocon.domain.analytics.usecase.ObserveAnalyticsByIdUseCase +import io.github.openflocon.domain.device.usecase.ObserveCurrentDeviceIdAndPackageNameUseCase +import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed +import io.github.openflocon.flocondesktop.features.analytics.mapper.mapToDetailUi +import io.github.openflocon.flocondesktop.features.analytics.model.AnalyticsDetailUiModel +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.filterNotNull + +class AnalyticsDetailViewModel( + id: String, + observeCurrentDeviceIdAndPackageNameUseCase: ObserveCurrentDeviceIdAndPackageNameUseCase, + observeAnalyticsByIdUseCase: ObserveAnalyticsByIdUseCase +) : ViewModel() { + + val uiState = combine( + observeAnalyticsByIdUseCase(id).filterNotNull(), + observeCurrentDeviceIdAndPackageNameUseCase() + ) { analytics, current -> + analytics.mapToDetailUi(current) + } + .stateInWhileSubscribed( + default = AnalyticsDetailUiModel( + id = id, + dateFormatted = "", + eventName = "", + isFromOldAppInstance = false, + properties = emptyList() + ) + ) + +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/AnalyticsViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/AnalyticsViewModel.kt index 17b644ae2..c6cb61774 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/AnalyticsViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/AnalyticsViewModel.kt @@ -29,6 +29,7 @@ import io.github.openflocon.flocondesktop.features.analytics.model.AnalyticsScre import io.github.openflocon.flocondesktop.features.analytics.model.AnalyticsStateUiModel import io.github.openflocon.flocondesktop.features.analytics.model.DeviceAnalyticsUiModel import io.github.openflocon.library.designsystem.common.asState +import io.github.openflocon.navigation.MainFloconNavigationState import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -38,7 +39,6 @@ import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @@ -47,7 +47,7 @@ class AnalyticsViewModel( private val dispatcherProvider: DispatcherProvider, private val feedbackDisplayer: FeedbackDisplayer, private val analyticsSelectorDelegate: AnalyticsSelectorDelegate, - observeCurrentDeviceIdAndPackageNameUseCase: ObserveCurrentDeviceIdAndPackageNameUseCase, + private val observeCurrentDeviceIdAndPackageNameUseCase: ObserveCurrentDeviceIdAndPackageNameUseCase, observeCurrentDeviceAnalyticsContentUseCase: ObserveCurrentDeviceAnalyticsContentUseCase, private val resetCurrentDeviceSelectedAnalyticsUseCase: ResetCurrentDeviceSelectedAnalyticsUseCase, private val removeAnalyticsItemUseCase: RemoveAnalyticsItemUseCase, @@ -55,10 +55,11 @@ class AnalyticsViewModel( private val removeOldSessionsAnalyticsUseCase: RemoveOldSessionsAnalyticsUseCase, private val exportAnalyticsToCsv: ExportAnalyticsToCsvUseCase, private val observeAnalyticsByIdUseCase: ObserveAnalyticsByIdUseCase, + private val navigationState: MainFloconNavigationState ) : ViewModel() { private val _filterText = mutableStateOf("") - val filterText : State = _filterText.asState() + val filterText: State = _filterText.asState() private val _screenState = MutableStateFlow( AnalyticsScreenUiState( @@ -140,14 +141,7 @@ class AnalyticsViewModel( } is AnalyticsAction.OnClick -> { - val newId = action.item.id - _selectedItemId.update { - if (it == newId) { - null - } else { - newId - } - } + navigationState.navigate(AnalyticsRoutes.Detail(action.item.id)) } is AnalyticsAction.Remove -> removeAnalyticsItemUseCase(action.item.id) diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/DI.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/DI.kt index 4198bec42..cb76de0f7 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/DI.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/DI.kt @@ -7,5 +7,6 @@ import org.koin.dsl.module val analyticsModule = module { viewModelOf(::AnalyticsViewModel) + viewModelOf(::AnalyticsDetailViewModel) factoryOf(::AnalyticsSelectorDelegate) } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt index 20680470b..5d358f6b7 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/Navigation.kt @@ -2,8 +2,11 @@ package io.github.openflocon.flocondesktop.features.analytics import androidx.navigation3.runtime.EntryProviderScope import io.github.openflocon.flocondesktop.app.MenuSceneStrategy +import io.github.openflocon.flocondesktop.features.analytics.view.AnalyticsDetailView import io.github.openflocon.flocondesktop.features.analytics.view.AnalyticsScreen import io.github.openflocon.navigation.FloconRoute +import io.github.openflocon.navigation.PanelRoute +import io.github.openflocon.navigation.scene.PanelSceneStrategy import kotlinx.serialization.Serializable sealed interface AnalyticsRoutes : FloconRoute { @@ -11,6 +14,11 @@ sealed interface AnalyticsRoutes : FloconRoute { @Serializable data object Main : AnalyticsRoutes + @Serializable + data class Detail( + val id: String + ) : AnalyticsRoutes, PanelRoute + } fun EntryProviderScope.analyticsRoutes() { @@ -19,4 +27,14 @@ fun EntryProviderScope.analyticsRoutes() { ) { AnalyticsScreen() } + entry( + metadata = PanelSceneStrategy.panel( + pinnable = false, + closable = true + ) + ) { + AnalyticsDetailView( + id = it.id + ) + } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/view/AnalyticsDetailView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/view/AnalyticsDetailView.kt index f9df2787c..b676915ad 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/view/AnalyticsDetailView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/view/AnalyticsDetailView.kt @@ -19,31 +19,47 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Text import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import io.github.openflocon.flocondesktop.features.analytics.AnalyticsDetailViewModel import io.github.openflocon.flocondesktop.features.analytics.model.AnalyticsDetailUiModel -import io.github.openflocon.flocondesktop.features.analytics.model.AnalyticsRowUiModel import io.github.openflocon.library.designsystem.FloconTheme import io.github.openflocon.library.designsystem.components.FloconHorizontalDivider import io.github.openflocon.library.designsystem.components.FloconVerticalScrollbar import io.github.openflocon.library.designsystem.components.rememberFloconScrollbarAdapter +import org.koin.compose.viewmodel.koinViewModel +import org.koin.core.parameter.parametersOf @Composable fun AnalyticsDetailView( - state: AnalyticsDetailUiModel, - modifier: Modifier = Modifier + id: String +) { + val viewModel = koinViewModel { + parametersOf(id) + } + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + Content( + uiState = uiState + ) +} + +@Composable +private fun Content( + uiState: AnalyticsDetailUiModel ) { val scrollState = rememberScrollState() val linesLabelWidth: Dp = 130.dp val scrollAdapter = rememberFloconScrollbarAdapter(scrollState) Box( - modifier - .background(FloconTheme.colorPalette.primary) + Modifier.background(FloconTheme.colorPalette.primary) ) { SelectionContainer( modifier = Modifier.fillMaxSize() @@ -56,14 +72,14 @@ fun AnalyticsDetailView( AnalyticsDetailLineTextView( modifier = Modifier.fillMaxWidth(), label = "Name", - value = state.eventName, + value = uiState.eventName, labelWidth = linesLabelWidth, withDivider = false, ) AnalyticsDetailLineTextView( modifier = Modifier.fillMaxWidth(), label = "Time", - value = state.dateFormatted, + value = uiState.dateFormatted, labelWidth = linesLabelWidth, withDivider = false, ) @@ -77,7 +93,7 @@ fun AnalyticsDetailView( shape = FloconTheme.shapes.medium ) ) { - state.properties.forEachIndexed { index, property -> + uiState.properties.forEachIndexed { index, property -> AnalyticsDetailLineTextView( modifier = Modifier.fillMaxWidth(), label = property.name, @@ -85,7 +101,7 @@ fun AnalyticsDetailView( labelWidth = linesLabelWidth, withDivider = true, ) - if (index != state.properties.lastIndex) { + if (index != uiState.properties.lastIndex) { FloconHorizontalDivider( modifier = Modifier.fillMaxWidth(), color = FloconTheme.colorPalette.secondary diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/view/AnalyticsScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/view/AnalyticsScreen.kt index 0b2399959..55c9349bb 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/view/AnalyticsScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/view/AnalyticsScreen.kt @@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.rememberScrollState import androidx.compose.material.icons.Icons @@ -56,7 +55,6 @@ import io.github.openflocon.library.designsystem.components.FloconFeature import io.github.openflocon.library.designsystem.components.FloconOverflow import io.github.openflocon.library.designsystem.components.FloconPageTopBar import io.github.openflocon.library.designsystem.components.FloconVerticalScrollbar -import io.github.openflocon.library.designsystem.components.panel.FloconPanel import io.github.openflocon.library.designsystem.components.rememberFloconScrollbarAdapter import kotlinx.coroutines.flow.flowOf import org.jetbrains.compose.ui.tooling.preview.Preview @@ -232,26 +230,21 @@ fun AnalyticsScreen( ) } } - FloconPanel( - contentState = selectedItem, - onClose = { onAction(AnalyticsAction.ClosePanel) }, - ) { - AnalyticsDetailView( - modifier = Modifier.fillMaxSize(), - state = it - ) - } } @Composable @Preview private fun AnalyticsScreenPreview() { val rows = remember { - flowOf(PagingData.from(listOf( - previewAnalyticsRowUiModel(), - previewAnalyticsRowUiModel(), - previewAnalyticsRowUiModel(), - ))) + flowOf( + PagingData.from( + listOf( + previewAnalyticsRowUiModel(), + previewAnalyticsRowUiModel(), + previewAnalyticsRowUiModel(), + ) + ) + ) }.collectAsLazyPagingItems() FloconTheme { AnalyticsScreen( diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/BadNetworkQualityWindow.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/BadNetworkQualityWindow.kt index 3d2179510..c716af155 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/BadNetworkQualityWindow.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/BadNetworkQualityWindow.kt @@ -2,7 +2,6 @@ package io.github.openflocon.flocondesktop.features.network.badquality.list.view -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/NetworkBadQualityContent.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/NetworkBadQualityContent.kt index 37f8ba0b1..4857d65f3 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/NetworkBadQualityContent.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/badquality/list/view/NetworkBadQualityContent.kt @@ -3,7 +3,6 @@ package io.github.openflocon.flocondesktop.features.network.badquality.list.view import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.Text diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt index 4bd7ae70d..f4702af86 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt @@ -347,9 +347,7 @@ fun NetworkScreen( deletedJson.forEach { states.remove(it) } addedJson.forEach { - states.put( - it, createFloconWindowState(), - ) + states[it] = createFloconWindowState() } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt index ab99ddb5a..0b8f8d98c 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/list/view/NetworkMocksScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import io.github.openflocon.flocondesktop.features.network.mock.NetworkMocksViewModel +import io.github.openflocon.flocondesktop.features.network.mock.edition.view.NetworkEditionWindow import io.github.openflocon.flocondesktop.features.network.mock.list.model.MockNetworkLineUiModel import io.github.openflocon.flocondesktop.features.network.mock.list.model.previewMockNetworkLineUiModel import io.github.openflocon.library.designsystem.FloconTheme @@ -45,15 +46,15 @@ fun NetworkMocksWindow( onAction = viewModel::onAction, ) -// editionWindow?.let { -// NetworkEditionWindow( -// instanceId = it.windowInstanceId, -// state = it.selectedMockUiModel, -// onCloseRequest = viewModel::cancelMockCreation, -// onCancel = viewModel::cancelMockCreation, -// onSave = viewModel::addMock, -// ) -// } + editionWindow?.let { + NetworkEditionWindow( + instanceId = it.windowInstanceId, + state = it.selectedMockUiModel, + onCloseRequest = viewModel::cancelMockCreation, + onCancel = viewModel::cancelMockCreation, + onSave = viewModel::addMock, + ) + } } sealed interface NetworkMockAction { diff --git a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt index 7090691d9..99e97f883 100644 --- a/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt +++ b/FloconDesktop/navigation/src/commonMain/kotlin/io/github/openflocon/navigation/scene/PanelScene.kt @@ -63,7 +63,7 @@ data class PanelScene( Icons.Outlined.Close ) } - if (onPin != null) { + if (onPin != null && properties.pinnable) { // TODO Use only one FloconIconTonalButton( onClick = { scope.launch {