Добавлена ViewModelBase

This commit is contained in:
Roman Pytkov
2024-11-23 13:27:37 +03:00
parent bd0183da79
commit 0407f04162
13 changed files with 127 additions and 41 deletions

View File

@@ -1,6 +1,6 @@
[versions] [versions]
agp = "8.7.1" agp = "8.7.1"
kotlin = "2.0.21" kotlin = "2.0.10"
coreKtx = "1.15.0" coreKtx = "1.15.0"
junit = "4.13.2" junit = "4.13.2"
junitVersion = "1.2.1" junitVersion = "1.2.1"
@@ -15,7 +15,7 @@ navigation = "2.8.3"
hiltNavigation = "1.2.0" hiltNavigation = "1.2.0"
yandexAuthSdk = "3.1.2" yandexAuthSdk = "3.1.2"
daggerHilt = "2.52" daggerHilt = "2.52"
ksp = "2.0.20-1.0.25" ksp = "2.0.10-1.0.24"
room = "2.6.1" room = "2.6.1"
retrofit = "2.11.0" retrofit = "2.11.0"
gson = "2.11.0" gson = "2.11.0"

View File

@@ -18,10 +18,10 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
@@ -30,10 +30,10 @@ import com.github.nullptroma.wallenc.presentation.navigation.NavBarItemData
import com.github.nullptroma.wallenc.presentation.navigation.rememberNavigationState import com.github.nullptroma.wallenc.presentation.navigation.rememberNavigationState
import com.github.nullptroma.wallenc.presentation.screens.main.MainRoute import com.github.nullptroma.wallenc.presentation.screens.main.MainRoute
import com.github.nullptroma.wallenc.presentation.screens.main.MainScreen import com.github.nullptroma.wallenc.presentation.screens.main.MainScreen
import com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault.LocalVaultRoute import com.github.nullptroma.wallenc.presentation.screens.main.MainViewModel
import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsRoute
import com.github.nullptroma.wallenc.presentation.screens.settings.SettingsRoute import com.github.nullptroma.wallenc.presentation.screens.settings.SettingsRoute
import com.github.nullptroma.wallenc.presentation.screens.settings.SettingsScreen import com.github.nullptroma.wallenc.presentation.screens.settings.SettingsScreen
import com.github.nullptroma.wallenc.presentation.screens.settings.SettingsViewModel
import com.github.nullptroma.wallenc.presentation.theme.WallencTheme import com.github.nullptroma.wallenc.presentation.theme.WallencTheme
@@ -48,23 +48,14 @@ fun WallencUi() {
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun WallencNavRoot() { fun WallencNavRoot(viewModel: WallencViewModel = hiltViewModel()) {
val navState = rememberNavigationState() val navState = rememberNavigationState()
val mainNavState = rememberNavigationState() val mainNavState = rememberNavigationState()
val mainScreenRoutes = rememberSaveable {
mutableMapOf(
LocalVaultRoute::class.qualifiedName!! to LocalVaultRoute(),
RemoteVaultsRoute::class.qualifiedName!! to RemoteVaultsRoute()
)
}
val topLevelRoutes = rememberSaveable { val mainViewModel: MainViewModel = hiltViewModel()
mutableMapOf( val settingsViewModel: SettingsViewModel = hiltViewModel()
MainRoute::class.qualifiedName!! to MainRoute(),
SettingsRoute::class.qualifiedName!! to SettingsRoute("Base settings") val topLevelRoutes = viewModel.routes
)
}
val topLevelNavBarItems = remember { val topLevelNavBarItems = remember {
mapOf( mapOf(
@@ -118,7 +109,7 @@ fun WallencNavRoot() {
MainScreen( MainScreen(
modifier = Modifier.padding(innerPaddings), modifier = Modifier.padding(innerPaddings),
navState = mainNavState, navState = mainNavState,
routes = mainScreenRoutes viewModel = mainViewModel
) )
} }
composable<SettingsRoute>(enterTransition = { composable<SettingsRoute>(enterTransition = {
@@ -126,8 +117,7 @@ fun WallencNavRoot() {
}, exitTransition = { }, exitTransition = {
fadeOut(tween(200)) fadeOut(tween(200))
}) { }) {
val route: SettingsRoute = it.toRoute() SettingsScreen(Modifier.padding(innerPaddings), settingsViewModel)
SettingsScreen(Modifier.padding(innerPaddings), route.text)
} }
} }
} }

View File

@@ -0,0 +1,33 @@
package com.github.nullptroma.wallenc.presentation
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi
import androidx.lifecycle.viewmodel.compose.saveable
import com.github.nullptroma.wallenc.presentation.screens.ScreenRoute
import com.github.nullptroma.wallenc.presentation.screens.main.MainRoute
import com.github.nullptroma.wallenc.presentation.screens.settings.SettingsRoute
import com.github.nullptroma.wallenc.presentation.viewmodel.ViewModelBase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlin.collections.set
@HiltViewModel
class WallencViewModel @javax.inject.Inject constructor(savedStateHandle: SavedStateHandle) :
ViewModelBase<Unit>(Unit) {
@OptIn(SavedStateHandleSaveableApi::class)
var routes by savedStateHandle.saveable {
mutableStateOf(
mapOf<String, ScreenRoute>(
MainRoute::class.qualifiedName!! to MainRoute(),
SettingsRoute::class.qualifiedName!! to SettingsRoute()
)
)
}
private set
fun updateRoute(qualifiedName: String, route: ScreenRoute) {
routes = routes.toMutableMap().apply {
this[qualifiedName] = route
}
}
}

View File

@@ -16,7 +16,6 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -24,14 +23,17 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.toRoute
import com.github.nullptroma.wallenc.presentation.R import com.github.nullptroma.wallenc.presentation.R
import com.github.nullptroma.wallenc.presentation.navigation.NavBarItemData import com.github.nullptroma.wallenc.presentation.navigation.NavBarItemData
import com.github.nullptroma.wallenc.presentation.navigation.NavigationState import com.github.nullptroma.wallenc.presentation.navigation.NavigationState
import com.github.nullptroma.wallenc.presentation.navigation.rememberNavigationState import com.github.nullptroma.wallenc.presentation.navigation.rememberNavigationState
import com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault.LocalVaultRoute import com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault.LocalVaultRoute
import com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault.LocalVaultScreen import com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault.LocalVaultScreen
import com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault.LocalVaultViewModel
import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsRoute import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsRoute
import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsScreen import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsScreen
import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsViewModel
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -40,13 +42,11 @@ fun MainScreen(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: MainViewModel = hiltViewModel(), viewModel: MainViewModel = hiltViewModel(),
navState: NavigationState = rememberNavigationState(), navState: NavigationState = rememberNavigationState(),
routes: MutableMap<String, MainRoute> = rememberSaveable {
mutableMapOf(
LocalVaultRoute::class.qualifiedName!! to LocalVaultRoute(),
RemoteVaultsRoute::class.qualifiedName!! to RemoteVaultsRoute()
)
}
) { ) {
val routes = viewModel.routes
val localVaultViewModel: LocalVaultViewModel = hiltViewModel()
val remoteVaultsViewModel: RemoteVaultsViewModel = hiltViewModel()
val topLevelNavBarItems = remember { val topLevelNavBarItems = remember {
mapOf( mapOf(
LocalVaultRoute::class.qualifiedName!! to NavBarItemData( LocalVaultRoute::class.qualifiedName!! to NavBarItemData(
@@ -94,14 +94,21 @@ fun MainScreen(
}, exitTransition = { }, exitTransition = {
fadeOut(tween(200)) fadeOut(tween(200))
}) { }) {
LocalVaultScreen(modifier = Modifier.padding(innerPaddings)) val route: LocalVaultRoute = it.toRoute()
LocalVaultScreen(
modifier = Modifier.padding(innerPaddings),
viewModel = localVaultViewModel
)
} }
composable<RemoteVaultsRoute>(enterTransition = { composable<RemoteVaultsRoute>(enterTransition = {
fadeIn(tween(200)) fadeIn(tween(200))
}, exitTransition = { }, exitTransition = {
fadeOut(tween(200)) fadeOut(tween(200))
}) { }) {
RemoteVaultsScreen(modifier = Modifier.padding(innerPaddings)) RemoteVaultsScreen(
modifier = Modifier.padding(innerPaddings),
viewModel = remoteVaultsViewModel
)
} }
} }
} }

View File

@@ -1,9 +1,33 @@
package com.github.nullptroma.wallenc.presentation.screens.main package com.github.nullptroma.wallenc.presentation.screens.main
import androidx.lifecycle.ViewModel import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi
import androidx.lifecycle.viewmodel.compose.saveable
import com.github.nullptroma.wallenc.presentation.screens.ScreenRoute
import com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault.LocalVaultRoute
import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsRoute
import com.github.nullptroma.wallenc.presentation.viewmodel.ViewModelBase
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
@HiltViewModel @HiltViewModel
class MainViewModel @javax.inject.Inject constructor(): ViewModel() { class MainViewModel @javax.inject.Inject constructor(savedStateHandle: SavedStateHandle) :
ViewModelBase<MainScreenState>(MainScreenState("default string")) {
@OptIn(SavedStateHandleSaveableApi::class)
var routes by savedStateHandle.saveable {
mutableStateOf(
mapOf<String, ScreenRoute>(
LocalVaultRoute::class.qualifiedName!! to LocalVaultRoute(),
RemoteVaultsRoute::class.qualifiedName!! to RemoteVaultsRoute()
)
)
}
private set
fun updateRoute(qualifiedName: String, route: ScreenRoute) {
routes = routes.toMutableMap().apply {
this[qualifiedName] = route
}
}
} }

View File

@@ -3,13 +3,17 @@ package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.va
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun LocalVaultScreen(modifier: Modifier = Modifier, fun LocalVaultScreen(modifier: Modifier = Modifier,
viewModel: LocalVaultViewModel = hiltViewModel()) { viewModel: LocalVaultViewModel = hiltViewModel()) {
Text("Local vault screen")
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
Text(uiState.value)
} }

View File

@@ -1,10 +1,11 @@
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
import androidx.lifecycle.ViewModel import com.github.nullptroma.wallenc.presentation.viewmodel.ViewModelBase
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class LocalVaultViewModel @Inject constructor(): ViewModel() { class LocalVaultViewModel @Inject constructor()
: ViewModelBase<LocalVaultScreenState>(LocalVaultScreenState("default")) {
} }

View File

@@ -1,10 +1,11 @@
package com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes package com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes
import androidx.lifecycle.ViewModel import com.github.nullptroma.wallenc.presentation.viewmodel.ViewModelBase
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class RemoteVaultsViewModel @Inject constructor(): ViewModel() { class RemoteVaultsViewModel @Inject constructor() :
ViewModelBase<RemoteVaultsScreenState>(RemoteVaultsScreenState("")) {
} }

View File

@@ -6,4 +6,4 @@ import kotlinx.serialization.Serializable
@Serializable @Serializable
@Parcelize @Parcelize
class SettingsRoute(val text: String): ScreenRoute() class SettingsRoute: ScreenRoute()

View File

@@ -11,9 +11,9 @@ import androidx.compose.ui.res.stringResource
import com.github.nullptroma.wallenc.presentation.R import com.github.nullptroma.wallenc.presentation.R
@Composable @Composable
fun SettingsScreen(modifier: Modifier, text: String) { fun SettingsScreen(modifier: Modifier, viewModel: SettingsViewModel) {
Column (modifier = modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) { Column (modifier = modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
Text(text = stringResource(id = R.string.settings_title)) Text(text = stringResource(id = R.string.settings_title))
Text(text = text) // Text(text = viewModel)
} }
} }

View File

@@ -0,0 +1,3 @@
package com.github.nullptroma.wallenc.presentation.screens.settings
data class SettingsScreenState(val value: String)

View File

@@ -0,0 +1,9 @@
package com.github.nullptroma.wallenc.presentation.screens.settings
import com.github.nullptroma.wallenc.presentation.viewmodel.ViewModelBase
import dagger.hilt.android.lifecycle.HiltViewModel
@HiltViewModel
class SettingsViewModel @javax.inject.Inject constructor() :
ViewModelBase<SettingsScreenState>(SettingsScreenState("default string")) {
}

View File

@@ -0,0 +1,14 @@
package com.github.nullptroma.wallenc.presentation.viewmodel
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
abstract class ViewModelBase<TState>(initState: TState) : ViewModel() {
protected val mutableUiState = MutableStateFlow<TState>(initState)
val uiState: StateFlow<TState>
get() = mutableUiState.asStateFlow()
}