From 471af18f5e2868b446559814b64ec033310cd2a3 Mon Sep 17 00:00:00 2001 From: Danil Nikolaev Date: Mon, 5 Aug 2024 02:11:03 +0300 Subject: [PATCH] simple navigation with Voyager --- composeApp/build.gradle.kts | 2 +- .../kotlin/dev/meloda/overseerr/App.kt | 71 ++------------- .../dev/meloda/overseerr/di/AppModule.kt | 18 ++++ .../dev/meloda/overseerr/di/MainModule.kt | 9 -- .../overseerr/login/model/LoginScreenState.kt | 4 - .../login/presentation/LoginScreen.kt | 10 --- .../overseerr/network/di/NetworkModule.kt | 13 +++ .../{ => screens}/login/LoginViewModel.kt | 2 +- .../overseerr/screens/login/di/LoginModule.kt | 9 ++ .../screens/login/model/LoginScreenState.kt | 4 + .../screens/login/presentation/LoginScreen.kt | 87 +++++++++++++++++++ .../overseerr/screens/url/UrlViewModel.kt | 6 ++ .../overseerr/screens/url/di/UrlModule.kt | 11 +++ .../screens/url/presentation/UrlScreen.kt | 33 +++++++ gradle/libs.versions.toml | 1 + 15 files changed, 190 insertions(+), 90 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/dev/meloda/overseerr/di/AppModule.kt delete mode 100644 composeApp/src/commonMain/kotlin/dev/meloda/overseerr/di/MainModule.kt delete mode 100644 composeApp/src/commonMain/kotlin/dev/meloda/overseerr/login/model/LoginScreenState.kt delete mode 100644 composeApp/src/commonMain/kotlin/dev/meloda/overseerr/login/presentation/LoginScreen.kt create mode 100644 composeApp/src/commonMain/kotlin/dev/meloda/overseerr/network/di/NetworkModule.kt rename composeApp/src/commonMain/kotlin/dev/meloda/overseerr/{ => screens}/login/LoginViewModel.kt (70%) create mode 100644 composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/di/LoginModule.kt create mode 100644 composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/model/LoginScreenState.kt create mode 100644 composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/presentation/LoginScreen.kt create mode 100644 composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/url/UrlViewModel.kt create mode 100644 composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/url/di/UrlModule.kt create mode 100644 composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/url/presentation/UrlScreen.kt diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 9030209..417c59f 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -62,6 +62,7 @@ kotlin { implementation(libs.coil.network.ktor) implementation(libs.kotlinx.coroutines.core) implementation(libs.ktor.core) + implementation(libs.ktor.client.cio) implementation(libs.kotlinx.serialization.json) implementation(libs.multiplatformSettings) implementation(libs.koin.core) @@ -94,7 +95,6 @@ kotlin { iosMain.dependencies { implementation(libs.ktor.client.darwin) } - } } diff --git a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/App.kt b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/App.kt index 5133b2f..76dafa1 100644 --- a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/App.kt +++ b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/App.kt @@ -1,78 +1,19 @@ package dev.meloda.overseerr -import androidx.compose.foundation.layout.* -import androidx.compose.material3.* +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Surface import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import dev.meloda.overseerr.model.Platform +import cafe.adriel.voyager.navigator.Navigator +import dev.meloda.overseerr.screens.url.presentation.UrlScreen import dev.meloda.overseerr.theme.AppTheme import org.koin.compose.KoinContext -import org.koin.compose.koinInject -@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun App() = KoinContext { - val platform: Platform = koinInject() - AppTheme { - var loginValue by rememberSaveable { - mutableStateOf("") - } - var passwordValue by rememberSaveable { - mutableStateOf("") - } - - Scaffold( - topBar = { - TopAppBar( - title = { - Text(text = "Log in") - } - ) - - Text( - text = "Current platform: ${platform.name}", - style = MaterialTheme.typography.displayLarge - ) - } - ) { padding -> - Column( - modifier = Modifier.fillMaxSize() - .padding(padding), - horizontalAlignment = Alignment.CenterHorizontally - ) { - TextField( - modifier = Modifier.fillMaxWidth(0.9f), - value = loginValue, - onValueChange = { newText -> loginValue = newText }, - placeholder = { Text(text = "Login") } - ) - - Spacer(modifier = Modifier.height(16.dp)) - - TextField( - modifier = Modifier.fillMaxWidth(0.9f), - value = passwordValue, - onValueChange = { newText -> passwordValue = newText }, - placeholder = { Text(text = "Password") } - ) - - Spacer(modifier = Modifier.height(16.dp)) - - Button( - onClick = { - - } - ) { - Text(text = "Authorize") - } - } + Surface(modifier = Modifier.fillMaxSize()) { + Navigator(UrlScreen()) } } } diff --git a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/di/AppModule.kt b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/di/AppModule.kt new file mode 100644 index 0000000..f101a41 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/di/AppModule.kt @@ -0,0 +1,18 @@ +package dev.meloda.overseerr.di + +import dev.meloda.overseerr.model.Platform +import dev.meloda.overseerr.network.di.networkModule +import dev.meloda.overseerr.screens.login.di.loginModule +import dev.meloda.overseerr.screens.url.di.urlModule +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module + +val appModule = module { + singleOf(::Platform) + + includes( + networkModule, + loginModule, + urlModule + ) +} diff --git a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/di/MainModule.kt b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/di/MainModule.kt deleted file mode 100644 index a356837..0000000 --- a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/di/MainModule.kt +++ /dev/null @@ -1,9 +0,0 @@ -package dev.meloda.overseerr.di - -import dev.meloda.overseerr.model.Platform -import org.koin.core.module.dsl.singleOf -import org.koin.dsl.module - -val appModule = module { - singleOf(::Platform) -} diff --git a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/login/model/LoginScreenState.kt b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/login/model/LoginScreenState.kt deleted file mode 100644 index 571ea3b..0000000 --- a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/login/model/LoginScreenState.kt +++ /dev/null @@ -1,4 +0,0 @@ -package dev.meloda.overseerr.login.model - -class LoginScreenState { -} diff --git a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/login/presentation/LoginScreen.kt b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/login/presentation/LoginScreen.kt deleted file mode 100644 index 67094b1..0000000 --- a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/login/presentation/LoginScreen.kt +++ /dev/null @@ -1,10 +0,0 @@ -package dev.meloda.overseerr.login.presentation - -import androidx.compose.runtime.Composable -import dev.icerock.moko.mvvm.compose.getViewModel -import dev.meloda.overseerr.login.LoginViewModel - -@Composable -fun LoginScreen(viewModel: LoginViewModel) { - -} diff --git a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/network/di/NetworkModule.kt b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/network/di/NetworkModule.kt new file mode 100644 index 0000000..5ada39c --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/network/di/NetworkModule.kt @@ -0,0 +1,13 @@ +package dev.meloda.overseerr.network.di + +import io.ktor.client.* +import io.ktor.client.engine.cio.* +import org.koin.dsl.module + +val networkModule = module { + single { + HttpClient(CIO) { + + } + } +} diff --git a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/login/LoginViewModel.kt b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/LoginViewModel.kt similarity index 70% rename from composeApp/src/commonMain/kotlin/dev/meloda/overseerr/login/LoginViewModel.kt rename to composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/LoginViewModel.kt index 7431af2..65e4d3d 100644 --- a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/login/LoginViewModel.kt +++ b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/LoginViewModel.kt @@ -1,4 +1,4 @@ -package dev.meloda.overseerr.login +package dev.meloda.overseerr.screens.login import dev.icerock.moko.mvvm.viewmodel.ViewModel diff --git a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/di/LoginModule.kt b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/di/LoginModule.kt new file mode 100644 index 0000000..ff6a35f --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/di/LoginModule.kt @@ -0,0 +1,9 @@ +package dev.meloda.overseerr.screens.login.di + +import dev.icerock.moko.mvvm.compose.viewModelFactory +import dev.meloda.overseerr.screens.login.LoginViewModel +import org.koin.dsl.module + +val loginModule = module { + viewModelFactory(::LoginViewModel) +} diff --git a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/model/LoginScreenState.kt b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/model/LoginScreenState.kt new file mode 100644 index 0000000..a966512 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/model/LoginScreenState.kt @@ -0,0 +1,4 @@ +package dev.meloda.overseerr.screens.login.model + +class LoginScreenState { +} diff --git a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/presentation/LoginScreen.kt b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/presentation/LoginScreen.kt new file mode 100644 index 0000000..6bdf9ba --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/login/presentation/LoginScreen.kt @@ -0,0 +1,87 @@ +package dev.meloda.overseerr.screens.login.presentation + +import androidx.compose.foundation.layout.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.rounded.ArrowBack +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow + +class LoginScreen : Screen { + + @OptIn(ExperimentalMaterial3Api::class) + @Composable + override fun Content() { + val navigator = LocalNavigator.currentOrThrow + + var loginValue by rememberSaveable { + mutableStateOf("") + } + var passwordValue by rememberSaveable { + mutableStateOf("") + } + + Scaffold( + topBar = { + TopAppBar( + title = { + Text(text = "Log in") + }, + navigationIcon = { + IconButton( + onClick = navigator::pop + ) { + Icon( + imageVector = Icons.AutoMirrored.Rounded.ArrowBack, + contentDescription = null + ) + } + } + ) + } + ) { padding -> + Column( + modifier = Modifier.fillMaxSize() + .padding(padding), + horizontalAlignment = Alignment.CenterHorizontally + ) { + + + TextField( + modifier = Modifier.fillMaxWidth(0.9f), + value = loginValue, + onValueChange = { newText -> loginValue = newText }, + placeholder = { Text(text = "Login") } + ) + + Spacer(modifier = Modifier.height(16.dp)) + + TextField( + modifier = Modifier.fillMaxWidth(0.9f), + value = passwordValue, + onValueChange = { newText -> passwordValue = newText }, + placeholder = { Text(text = "Password") } + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Button( + onClick = { + + } + ) { + Text(text = "Authorize") + } + } + } + } +} diff --git a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/url/UrlViewModel.kt b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/url/UrlViewModel.kt new file mode 100644 index 0000000..5c959d1 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/url/UrlViewModel.kt @@ -0,0 +1,6 @@ +package dev.meloda.overseerr.screens.url + +import dev.icerock.moko.mvvm.viewmodel.ViewModel + +class UrlViewModel : ViewModel() { +} diff --git a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/url/di/UrlModule.kt b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/url/di/UrlModule.kt new file mode 100644 index 0000000..d0e304d --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/url/di/UrlModule.kt @@ -0,0 +1,11 @@ +package dev.meloda.overseerr.screens.url.di + +import dev.icerock.moko.mvvm.compose.viewModelFactory +import dev.meloda.overseerr.screens.url.UrlViewModel +import org.koin.dsl.module + +val urlModule = module { + viewModelFactory { + UrlViewModel() + } +} diff --git a/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/url/presentation/UrlScreen.kt b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/url/presentation/UrlScreen.kt new file mode 100644 index 0000000..5e70afe --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/meloda/overseerr/screens/url/presentation/UrlScreen.kt @@ -0,0 +1,33 @@ +package dev.meloda.overseerr.screens.url.presentation + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Button +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow +import dev.meloda.overseerr.screens.login.presentation.LoginScreen + +class UrlScreen : Screen { + + @Composable + override fun Content() { + val navigator = LocalNavigator.currentOrThrow + Scaffold(modifier = Modifier.fillMaxSize()) { + Column(modifier = Modifier.fillMaxSize()) { + Text(text = "Input url screen") + Button( + onClick = { + navigator.push(LoginScreen()) + } + ) { + Text(text = "Next") + } + } + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7b04e05..80d744a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,6 +26,7 @@ kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutine kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } ktor-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } +ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" } ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" } ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } ktor-client-js = { module = "io.ktor:ktor-client-js", version.ref = "ktor" }