From 8fa8bda75e6c989f2d22d034b0d5b8ce97388150 Mon Sep 17 00:00:00 2001 From: Adit Lal Date: Sun, 16 Jun 2024 12:14:11 +0530 Subject: [PATCH] UI Setup --- build.gradle.kts | 3 +- composeApp/build.gradle.kts | 3 ++ .../src/androidMain/AndroidManifest.xml | 7 +++-- .../com/app/academy/notes/MainActivity.kt | 4 +-- .../app/academy/notes/NotesAppApplication.kt | 10 ++++++ .../commonMain/kotlin/com/app/academy/App.kt | 31 +++++++++++++++++++ .../{App.kt => com/app/academy/DemoScreen.kt} | 18 +++++------ .../kotlin/com/app/academy/HomeScreen.kt | 21 +++++++++++++ .../kotlin/com/app/academy/NotesNavigation.kt | 12 +++++++ .../com/app/academy/theme/NotesAppTheme.kt | 13 ++++++++ composeApp/src/desktopMain/kotlin/main.kt | 3 +- .../src/iosMain/kotlin/MainViewController.kt | 3 +- composeApp/src/wasmJsMain/kotlin/main.kt | 3 +- gradle/libs.versions.toml | 7 ++++- iosApp/iosApp/ui/home/HomeScreen.swift | 7 +++++ settings.gradle.kts | 1 - .../notes/utils/NativeStateFlow.android.kt | 9 ++++++ .../architect/notes/utils/NativeStateFlow.kt | 5 ++- .../notes/utils/NativeStateFlow.ios.kt | 21 +++++++++++++ 19 files changed, 157 insertions(+), 24 deletions(-) create mode 100644 composeApp/src/androidMain/kotlin/com/app/academy/notes/NotesAppApplication.kt create mode 100644 composeApp/src/commonMain/kotlin/com/app/academy/App.kt rename composeApp/src/commonMain/kotlin/{App.kt => com/app/academy/DemoScreen.kt} (83%) create mode 100644 composeApp/src/commonMain/kotlin/com/app/academy/HomeScreen.kt create mode 100644 composeApp/src/commonMain/kotlin/com/app/academy/NotesNavigation.kt create mode 100644 composeApp/src/commonMain/kotlin/com/app/academy/theme/NotesAppTheme.kt create mode 100644 iosApp/iosApp/ui/home/HomeScreen.swift create mode 100644 shared/src/androidMain/kotlin/app/architect/notes/utils/NativeStateFlow.android.kt create mode 100644 shared/src/iosMain/kotlin/app/architect/notes/utils/NativeStateFlow.ios.kt diff --git a/build.gradle.kts b/build.gradle.kts index ec93b69..4064277 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,4 +7,5 @@ plugins { alias(libs.plugins.compose.compiler) apply false alias(libs.plugins.kotlinJvm) apply false alias(libs.plugins.kotlinMultiplatform) apply false -} \ No newline at end of file + alias(libs.plugins.jetbrains.kotlin.android) apply false +} diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 64ae6af..e7df99f 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -64,6 +64,9 @@ kotlin { implementation(compose.components.resources) implementation(compose.components.uiToolingPreview) implementation(projects.shared) + implementation(libs.voyager.navigator) + implementation(libs.voyager.navigator.transitions) + implementation(libs.voyager.screenmodel) } desktopMain.dependencies { implementation(compose.desktop.currentOs) diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml index c5db0b1..ff9ccec 100644 --- a/composeApp/src/androidMain/AndroidManifest.xml +++ b/composeApp/src/androidMain/AndroidManifest.xml @@ -2,6 +2,7 @@ + android:exported="true"> @@ -20,4 +21,4 @@ - \ No newline at end of file + diff --git a/composeApp/src/androidMain/kotlin/com/app/academy/notes/MainActivity.kt b/composeApp/src/androidMain/kotlin/com/app/academy/notes/MainActivity.kt index 67eba90..eb4b60f 100644 --- a/composeApp/src/androidMain/kotlin/com/app/academy/notes/MainActivity.kt +++ b/composeApp/src/androidMain/kotlin/com/app/academy/notes/MainActivity.kt @@ -1,6 +1,6 @@ package com.app.academy.notes -import App +import com.app.academy.App import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent @@ -21,4 +21,4 @@ class MainActivity : ComponentActivity() { @Composable fun AppAndroidPreview() { App() -} \ No newline at end of file +} diff --git a/composeApp/src/androidMain/kotlin/com/app/academy/notes/NotesAppApplication.kt b/composeApp/src/androidMain/kotlin/com/app/academy/notes/NotesAppApplication.kt new file mode 100644 index 0000000..ada24db --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com/app/academy/notes/NotesAppApplication.kt @@ -0,0 +1,10 @@ +package app.architect.notes + +import android.app.Application + +class NotesAppApplication : Application() { + + override fun onCreate() { + super.onCreate() + } +} diff --git a/composeApp/src/commonMain/kotlin/com/app/academy/App.kt b/composeApp/src/commonMain/kotlin/com/app/academy/App.kt new file mode 100644 index 0000000..ff6da52 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/app/academy/App.kt @@ -0,0 +1,31 @@ +package com.app.academy + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.Image +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.Button +import androidx.compose.material.MaterialTheme +import androidx.compose.material.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 app.architect.notes.utils.Greeting +import com.app.academy.theme.NotesAppTheme +import kmpnotes.composeapp.generated.resources.Res +import kmpnotes.composeapp.generated.resources.compose_multiplatform +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.ui.tooling.preview.Preview + +@Composable +@Preview +fun App() { + NotesAppTheme { + NotesAppNavigation() + } +} diff --git a/composeApp/src/commonMain/kotlin/App.kt b/composeApp/src/commonMain/kotlin/com/app/academy/DemoScreen.kt similarity index 83% rename from composeApp/src/commonMain/kotlin/App.kt rename to composeApp/src/commonMain/kotlin/com/app/academy/DemoScreen.kt index 5877753..d496f58 100644 --- a/composeApp/src/commonMain/kotlin/App.kt +++ b/composeApp/src/commonMain/kotlin/com/app/academy/DemoScreen.kt @@ -1,10 +1,10 @@ +package com.app.academy + import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.Image -import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material.Button -import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -14,21 +14,18 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import app.architect.notes.utils.Greeting +import cafe.adriel.voyager.core.screen.Screen import kmpnotes.composeapp.generated.resources.Res import kmpnotes.composeapp.generated.resources.compose_multiplatform import org.jetbrains.compose.resources.painterResource -import org.jetbrains.compose.ui.tooling.preview.Preview - -@Composable -@Preview -fun App() { - val darkEnabled = isSystemInDarkTheme() - MaterialTheme() { +object DemoScreen : Screen { + @Composable + override fun Content() { var showContent by remember { mutableStateOf(false) } Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { Button(onClick = { showContent = !showContent }) { - Text("Click me! - $darkEnabled") + Text("Click me!") } AnimatedVisibility(showContent) { val greeting = remember { Greeting().greet() } @@ -43,4 +40,5 @@ fun App() { } } } + } diff --git a/composeApp/src/commonMain/kotlin/com/app/academy/HomeScreen.kt b/composeApp/src/commonMain/kotlin/com/app/academy/HomeScreen.kt new file mode 100644 index 0000000..9dd6b6e --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/app/academy/HomeScreen.kt @@ -0,0 +1,21 @@ +package com.app.academy + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import cafe.adriel.voyager.core.screen.Screen + +object HomeScreen : Screen { + @Composable + override fun Content() { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Text(text = "To be built") + } + } +} diff --git a/composeApp/src/commonMain/kotlin/com/app/academy/NotesNavigation.kt b/composeApp/src/commonMain/kotlin/com/app/academy/NotesNavigation.kt new file mode 100644 index 0000000..569eea6 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/app/academy/NotesNavigation.kt @@ -0,0 +1,12 @@ +package com.app.academy + +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.navigator.Navigator +import cafe.adriel.voyager.transitions.SlideTransition + +@Composable +fun NotesAppNavigation() { + Navigator(screen = HomeScreen) { + SlideTransition(navigator = it) + } +} diff --git a/composeApp/src/commonMain/kotlin/com/app/academy/theme/NotesAppTheme.kt b/composeApp/src/commonMain/kotlin/com/app/academy/theme/NotesAppTheme.kt new file mode 100644 index 0000000..b8500b3 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/app/academy/theme/NotesAppTheme.kt @@ -0,0 +1,13 @@ +package com.app.academy.theme + +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable + +@Composable +fun NotesAppTheme( + content: @Composable () -> Unit +) { + MaterialTheme( + content = content + ) +} diff --git a/composeApp/src/desktopMain/kotlin/main.kt b/composeApp/src/desktopMain/kotlin/main.kt index 48836f5..b495c5f 100644 --- a/composeApp/src/desktopMain/kotlin/main.kt +++ b/composeApp/src/desktopMain/kotlin/main.kt @@ -1,5 +1,6 @@ import androidx.compose.ui.window.Window import androidx.compose.ui.window.application +import com.app.academy.App fun main() = application { Window( @@ -8,4 +9,4 @@ fun main() = application { ) { App() } -} \ No newline at end of file +} diff --git a/composeApp/src/iosMain/kotlin/MainViewController.kt b/composeApp/src/iosMain/kotlin/MainViewController.kt index fa143d4..f3b94c5 100644 --- a/composeApp/src/iosMain/kotlin/MainViewController.kt +++ b/composeApp/src/iosMain/kotlin/MainViewController.kt @@ -1,3 +1,4 @@ import androidx.compose.ui.window.ComposeUIViewController +import com.app.academy.App -fun MainViewController() = ComposeUIViewController { App() } \ No newline at end of file +fun MainViewController() = ComposeUIViewController { App() } diff --git a/composeApp/src/wasmJsMain/kotlin/main.kt b/composeApp/src/wasmJsMain/kotlin/main.kt index d2fd60c..b2f0a13 100644 --- a/composeApp/src/wasmJsMain/kotlin/main.kt +++ b/composeApp/src/wasmJsMain/kotlin/main.kt @@ -1,5 +1,6 @@ import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.window.ComposeViewport +import com.app.academy.App import kotlinx.browser.document @OptIn(ExperimentalComposeUiApi::class) @@ -7,4 +8,4 @@ fun main() { ComposeViewport(document.body!!) { App() } -} \ No newline at end of file +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5640fcd..14af02e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,8 @@ sqlDelight = "2.0.1" material3Android = "1.2.1" lifecycleViewmodelCompose = "2.7.0" material3 = "1.2.1" - +kotlinVersion = "2.0.0" +voyager = "1.0.0" [libraries] androidx-core = { module = "androidx.test:core", version.ref = "core" } @@ -59,6 +60,9 @@ kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-c native-driver-v200 = { module = "app.cash.sqldelight:native-driver", version.ref = "nativeDriver" } androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycleViewmodelCompose" } runtime-v200 = { module = "app.cash.sqldelight:runtime", version.ref = "runtime" } +voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } +voyager-navigator-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" } +voyager-screenmodel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyager" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" } @@ -70,3 +74,4 @@ ktor = { id = "io.ktor.plugin", version.ref = "ktor" } kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } kotlinxSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } sqldelight = { id = "app.cash.sqldelight", version.ref = "sqlDelight" } +jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinVersion" } diff --git a/iosApp/iosApp/ui/home/HomeScreen.swift b/iosApp/iosApp/ui/home/HomeScreen.swift new file mode 100644 index 0000000..bda93f9 --- /dev/null +++ b/iosApp/iosApp/ui/home/HomeScreen.swift @@ -0,0 +1,7 @@ +import Foundation +import SwiftUI +import shared + +struct HomeScreen : View { + +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 78efe06..535a1b3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,5 +30,4 @@ dependencyResolutionManagement { include(":composeApp") include(":server") -include(":androidApp") include(":shared") diff --git a/shared/src/androidMain/kotlin/app/architect/notes/utils/NativeStateFlow.android.kt b/shared/src/androidMain/kotlin/app/architect/notes/utils/NativeStateFlow.android.kt new file mode 100644 index 0000000..ec2d70d --- /dev/null +++ b/shared/src/androidMain/kotlin/app/architect/notes/utils/NativeStateFlow.android.kt @@ -0,0 +1,9 @@ +package app.architect.notes.utils + +import kotlinx.coroutines.flow.StateFlow + +/** + * A cross platform implementation of [StateFlow]. + */ +actual class NativeStateFlow actual constructor(source: StateFlow) : + StateFlow by source diff --git a/shared/src/commonMain/kotlin/app/architect/notes/utils/NativeStateFlow.kt b/shared/src/commonMain/kotlin/app/architect/notes/utils/NativeStateFlow.kt index 1808fb3..4c05dbd 100644 --- a/shared/src/commonMain/kotlin/app/architect/notes/utils/NativeStateFlow.kt +++ b/shared/src/commonMain/kotlin/app/architect/notes/utils/NativeStateFlow.kt @@ -1,6 +1,5 @@ -package com.example.notes.utils +package app.architect.notes.utils -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow /** @@ -11,4 +10,4 @@ expect class NativeStateFlow(source: StateFlow) : StateFlow /** * Used to convert a [StateFlow] to a [NativeStateFlow] */ -fun StateFlow.asNativeStateFlow() = NativeStateFlow(this) \ No newline at end of file +fun StateFlow.asNativeStateFlow() = NativeStateFlow(this) diff --git a/shared/src/iosMain/kotlin/app/architect/notes/utils/NativeStateFlow.ios.kt b/shared/src/iosMain/kotlin/app/architect/notes/utils/NativeStateFlow.ios.kt new file mode 100644 index 0000000..c1eb2fd --- /dev/null +++ b/shared/src/iosMain/kotlin/app/architect/notes/utils/NativeStateFlow.ios.kt @@ -0,0 +1,21 @@ +package app.architect.notes.utils + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.DisposableHandle +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch + +/** + * A cross platform implementation of [StateFlow]. + */ +actual class NativeStateFlow actual constructor(source: StateFlow) : StateFlow by source { + + fun subscribe(onCollect: (T) -> Unit): DisposableHandle { + val scope = MainScope().apply { + launch(Dispatchers.Main) { collect(onCollect) } + } + return DisposableHandle { scope.cancel() } + } +}