simple navigation with Voyager
This commit is contained in:
@@ -62,6 +62,7 @@ kotlin {
|
|||||||
implementation(libs.coil.network.ktor)
|
implementation(libs.coil.network.ktor)
|
||||||
implementation(libs.kotlinx.coroutines.core)
|
implementation(libs.kotlinx.coroutines.core)
|
||||||
implementation(libs.ktor.core)
|
implementation(libs.ktor.core)
|
||||||
|
implementation(libs.ktor.client.cio)
|
||||||
implementation(libs.kotlinx.serialization.json)
|
implementation(libs.kotlinx.serialization.json)
|
||||||
implementation(libs.multiplatformSettings)
|
implementation(libs.multiplatformSettings)
|
||||||
implementation(libs.koin.core)
|
implementation(libs.koin.core)
|
||||||
@@ -94,7 +95,6 @@ kotlin {
|
|||||||
iosMain.dependencies {
|
iosMain.dependencies {
|
||||||
implementation(libs.ktor.client.darwin)
|
implementation(libs.ktor.client.darwin)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,78 +1,19 @@
|
|||||||
package dev.meloda.overseerr
|
package dev.meloda.overseerr
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.runtime.Composable
|
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.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import cafe.adriel.voyager.navigator.Navigator
|
||||||
import dev.meloda.overseerr.model.Platform
|
import dev.meloda.overseerr.screens.url.presentation.UrlScreen
|
||||||
import dev.meloda.overseerr.theme.AppTheme
|
import dev.meloda.overseerr.theme.AppTheme
|
||||||
import org.koin.compose.KoinContext
|
import org.koin.compose.KoinContext
|
||||||
import org.koin.compose.koinInject
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun App() = KoinContext {
|
internal fun App() = KoinContext {
|
||||||
val platform: Platform = koinInject()
|
|
||||||
|
|
||||||
AppTheme {
|
AppTheme {
|
||||||
var loginValue by rememberSaveable {
|
Surface(modifier = Modifier.fillMaxSize()) {
|
||||||
mutableStateOf("")
|
Navigator(UrlScreen())
|
||||||
}
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
package dev.meloda.overseerr.login.model
|
|
||||||
|
|
||||||
class LoginScreenState {
|
|
||||||
}
|
|
||||||
-10
@@ -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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package dev.meloda.overseerr.login
|
package dev.meloda.overseerr.screens.login
|
||||||
|
|
||||||
import dev.icerock.moko.mvvm.viewmodel.ViewModel
|
import dev.icerock.moko.mvvm.viewmodel.ViewModel
|
||||||
|
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
package dev.meloda.overseerr.screens.login.model
|
||||||
|
|
||||||
|
class LoginScreenState {
|
||||||
|
}
|
||||||
+87
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package dev.meloda.overseerr.screens.url
|
||||||
|
|
||||||
|
import dev.icerock.moko.mvvm.viewmodel.ViewModel
|
||||||
|
|
||||||
|
class UrlViewModel : ViewModel() {
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+33
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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-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" }
|
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-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-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }
|
||||||
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", 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" }
|
ktor-client-js = { module = "io.ktor:ktor-client-js", version.ref = "ktor" }
|
||||||
|
|||||||
Reference in New Issue
Block a user