Skip to content

Commit

Permalink
Start using typesafe navigation in BooleanConfiguration
Browse files Browse the repository at this point in the history
  • Loading branch information
erikeelde committed Sep 16, 2024
1 parent 76cf46c commit bf96e08
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 78 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package se.eelde.toggles.booleanconfiguration

import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
Expand All @@ -26,22 +27,53 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.coroutines.launch
import se.eelde.toggles.routes.BooleanConfiguration
import se.eelde.toggles.routes.StringConfiguration

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("ComposeViewModelInjection")
@Composable
fun BooleanValueView(
modifier: Modifier = Modifier,
viewModel: FragmentBooleanValueViewModel = hiltViewModel(),
booleanConfiguration: BooleanConfiguration,
back: () -> Unit,
) {
val viewModel: BooleanValueViewModel =
hiltViewModel<BooleanValueViewModel, BooleanValueViewModel.Factory>(
creationCallback = { factory ->
factory.create(booleanConfiguration)
}
)

val viewState by viewModel.state.collectAsStateWithLifecycle()

val scope = rememberCoroutineScope()

BooleanValueView(
viewState = viewState,
save = { scope.launch { viewModel.saveClick() } },
revert = { scope.launch { viewModel.revertClick() } },
checkedChanged = { viewModel.checkedChanged(it) },
popBackStack = back,
)
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
@Suppress("LongParameterList")
fun BooleanValueView(
viewState: ViewState,
save: () -> Unit,
revert: () -> Unit,
checkedChanged: (Boolean) -> Unit,
popBackStack: () -> Unit,
modifier: Modifier = Modifier,
) {
Scaffold(
topBar = {
TopAppBar(
title = { Text("Boolean configuration") },
navigationIcon =
{
IconButton(onClick = { back() }) {
IconButton(onClick = { popBackStack() }) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = null
Expand All @@ -51,63 +83,47 @@ fun BooleanValueView(
)
},
) { paddingValues ->
BooleanValueView(
uiState = viewState,
popBackStack = { back() },
revert = { viewModel.revertClick() },
save = { viewModel.saveClick() },
setBooleanValue = { viewModel.checkedChanged(it) },
modifier = modifier.padding(paddingValues),
)
}
}

@Composable
@Suppress("LongParameterList")
internal fun BooleanValueView(
uiState: ViewState,
popBackStack: () -> Unit,
setBooleanValue: (Boolean) -> Unit,
revert: suspend () -> Unit,
save: suspend () -> Unit,
modifier: Modifier = Modifier,
) {
val scope = rememberCoroutineScope()

Surface(modifier = modifier.padding(16.dp)) {
Column {
Text(
modifier = Modifier.padding(8.dp),
style = MaterialTheme.typography.headlineMedium,
text = uiState.title ?: ""
)
val scope = rememberCoroutineScope()
Surface(modifier = modifier
.padding(paddingValues)
.padding(16.dp)) {
Column {
Text(
modifier = Modifier.padding(8.dp),
style = MaterialTheme.typography.headlineMedium,
text = viewState.title ?: ""
)

Switch(
modifier = Modifier
.padding(8.dp)
.align(End),
checked = uiState.checked ?: false,
onCheckedChange = { setBooleanValue(it) }
)
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
Button(modifier = Modifier.padding(8.dp), onClick = {
scope.launch {
revert()
popBackStack()
Switch(
modifier = Modifier
.padding(8.dp)
.align(End),
checked = viewState.checked ?: false,
onCheckedChange = {
checkedChanged(it)
}
)
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
Button(modifier = Modifier.padding(8.dp), onClick = {
scope.launch {
revert()
popBackStack()
}
}) {
Text("Revert")
}
}) {
Text("Revert")
}

Button(modifier = Modifier.padding(8.dp), onClick = {
scope.launch {
save()
popBackStack()
Button(modifier = Modifier.padding(8.dp), onClick = {
scope.launch {
save()
popBackStack()
}
}) {
Text("Save")
}
}) {
Text("Save")
}
}
}
}
}

Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package se.eelde.toggles.booleanconfiguration

import android.app.Application
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
Expand All @@ -16,8 +18,8 @@ import se.eelde.toggles.database.WrenchConfigurationValue
import se.eelde.toggles.database.dao.application.TogglesConfigurationDao
import se.eelde.toggles.database.dao.application.TogglesConfigurationValueDao
import se.eelde.toggles.provider.notifyUpdate
import se.eelde.toggles.routes.BooleanConfiguration
import java.util.Date
import javax.inject.Inject

data class ViewState(
val title: String? = null,
Expand All @@ -34,22 +36,29 @@ private sealed class PartialViewState {
object Reverting : PartialViewState()
}

@HiltViewModel
class FragmentBooleanValueViewModel @Inject internal constructor(
savedStateHandle: SavedStateHandle,
@HiltViewModel(assistedFactory = BooleanValueViewModel.Factory::class)
class BooleanValueViewModel @AssistedInject internal constructor(
private val application: Application,
private val configurationDao: TogglesConfigurationDao,
private val configurationValueDao: TogglesConfigurationValueDao
private val configurationValueDao: TogglesConfigurationValueDao,
@Assisted booleanConfiguration: BooleanConfiguration
) : ViewModel() {

@AssistedFactory
interface Factory {
fun create(
booleanConfiguration: BooleanConfiguration
): BooleanValueViewModel
}

private val configurationId = booleanConfiguration.configurationId
private val scopeId = booleanConfiguration.scopeId

private val _state = MutableStateFlow(reduce(ViewState(), PartialViewState.Empty))

val state: StateFlow<ViewState>
get() = _state

private val configurationId: Long = savedStateHandle.get<Long>("configurationId")!!
private val scopeId: Long = savedStateHandle.get<Long>("scopeId")!!

private var selectedConfigurationValue: WrenchConfigurationValue? = null

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import se.eelde.toggles.routes.StringConfiguration
private fun StringValueViewPreview() {
TogglesTheme {
StringValueView(
state = ViewState(title = "The title", stringValue = "This is value"),
viewState = ViewState(title = "The title", stringValue = "This is value"),
setStringValue = {},
save = {},
revert = {},
Expand All @@ -62,7 +62,7 @@ fun StringValueView(
val scope = rememberCoroutineScope()

StringValueView(
state = viewState,
viewState = viewState,
setStringValue = { viewModel.setStringValue(it) },
save = { scope.launch { viewModel.saveClick() } },
revert = { viewModel.revertClick() },
Expand All @@ -74,7 +74,7 @@ fun StringValueView(
@OptIn(ExperimentalMaterial3Api::class)
@Suppress("LongParameterList")
internal fun StringValueView(
state: ViewState,
viewState: ViewState,
setStringValue: (String) -> Unit,
save: suspend () -> Unit,
revert: suspend () -> Unit,
Expand Down Expand Up @@ -104,12 +104,12 @@ internal fun StringValueView(
Text(
modifier = Modifier.padding(8.dp),
style = MaterialTheme.typography.headlineMedium,
text = state.title ?: ""
text = viewState.title ?: ""
)
OutlinedTextField(
modifier = Modifier
.fillMaxWidth(),
value = state.stringValue ?: "",
value = viewState.stringValue ?: "",
onValueChange = { setStringValue(it) },
)
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
Expand Down
15 changes: 6 additions & 9 deletions toggles-app/src/main/java/se/eelde/toggles/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import se.eelde.toggles.help.HelpView
import se.eelde.toggles.integerconfiguration.IntegerValueView
import se.eelde.toggles.oss.OssView
import se.eelde.toggles.routes.Applications
import se.eelde.toggles.routes.BooleanConfiguration
import se.eelde.toggles.routes.Configurations
import se.eelde.toggles.routes.Help
import se.eelde.toggles.routes.Oss
Expand Down Expand Up @@ -63,7 +64,7 @@ fun Navigation(
)
configurationsNavigations(
navigateToBooleanConfiguration = { scopeId: Long, configurationId: Long ->
navController.navigate("configuration/$configurationId/$scopeId/boolean")
navController.navigate(BooleanConfiguration(configurationId, scopeId))
},
navigateToIntegerConfiguration = { scopeId: Long, configurationId: Long ->
navController.navigate("configuration/$configurationId/$scopeId/integer")
Expand All @@ -83,14 +84,10 @@ fun Navigation(
navController.navigate("scopes/$applicationId")
}
) { navController.popBackStack() }
composable(
"configuration/{configurationId}/{scopeId}/boolean",
arguments = listOf(
navArgument("configurationId") { type = NavType.LongType },
navArgument("scopeId") { type = NavType.LongType }
)
) {
BooleanValueView { navController.popBackStack() }
composable<BooleanConfiguration> { backStackEntry ->
val booleanConfiguration: BooleanConfiguration = backStackEntry.toRoute()

BooleanValueView(booleanConfiguration) { navController.popBackStack() }
}
composable(
"scopes/{applicationId}",
Expand Down

0 comments on commit bf96e08

Please sign in to comment.