Skip to content

Commit

Permalink
Move expand state into VM
Browse files Browse the repository at this point in the history
  • Loading branch information
pyamsoft committed Dec 31, 2024
1 parent e6ee0f6 commit 9712b68
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 9 deletions.
14 changes: 14 additions & 0 deletions app/src/main/java/com/pyamsoft/tetherfi/info/InfoEntry.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package com.pyamsoft.tetherfi.info
import androidx.activity.ComponentActivity
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.pyamsoft.pydroid.arch.SaveStateDisposableEffect
import com.pyamsoft.pydroid.ui.inject.ComposableInjector
import com.pyamsoft.pydroid.ui.inject.rememberComposableInjector
import com.pyamsoft.pydroid.ui.util.rememberNotNull
Expand All @@ -40,6 +41,14 @@ internal class InfoInjector : ComposableInjector() {
}
}

/** On mount hooks */
@Composable
private fun MountHooks(
viewModel: InfoViewModeler,
) {
SaveStateDisposableEffect(viewModel)
}

@Composable
fun InfoEntry(
modifier: Modifier = Modifier,
Expand All @@ -52,6 +61,10 @@ fun InfoEntry(
val component = rememberComposableInjector { InfoInjector() }
val viewModel = rememberNotNull(component.viewModel)

MountHooks(
viewModel = viewModel,
)

InfoScreen(
modifier = modifier,
state = viewModel,
Expand All @@ -61,5 +74,6 @@ fun InfoEntry(
onShowQRCode = onShowQRCode,
onShowSlowSpeedHelp = onShowSlowSpeedHelp,
onTogglePasswordVisibility = { viewModel.handleTogglePasswordVisibility() },
onToggleShowOptions = { viewModel.handleToggleOptions(it) },
)
}
3 changes: 3 additions & 0 deletions info/src/main/java/com/pyamsoft/tetherfi/info/InfoScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ fun InfoScreen(
onTogglePasswordVisibility: () -> Unit,
onShowQRCode: () -> Unit,
onShowSlowSpeedHelp: () -> Unit,
onToggleShowOptions: (InfoViewOptionsType) -> Unit,
) {
LazyColumn(
modifier = modifier,
Expand Down Expand Up @@ -87,6 +88,7 @@ fun InfoScreen(
onTogglePasswordVisibility = onTogglePasswordVisibility,
onShowQRCode = onShowQRCode,
onShowSlowSpeedHelp = onShowSlowSpeedHelp,
onToggleShowOptions = onToggleShowOptions,
)

item(
Expand All @@ -110,5 +112,6 @@ private fun PreviewInfoScreen() {
onTogglePasswordVisibility = {},
onShowQRCode = {},
onShowSlowSpeedHelp = {},
onToggleShowOptions = {},
)
}
41 changes: 41 additions & 0 deletions info/src/main/java/com/pyamsoft/tetherfi/info/InfoViewModeler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

package com.pyamsoft.tetherfi.info

import androidx.compose.runtime.saveable.SaveableStateRegistry
import com.pyamsoft.pydroid.arch.AbstractViewModeler
import com.pyamsoft.pydroid.core.cast
import javax.inject.Inject
import kotlinx.coroutines.flow.update

Expand All @@ -26,7 +28,46 @@ internal constructor(
override val state: MutableInfoViewState,
) : InfoViewState by state, AbstractViewModeler<InfoViewState>(state) {

override fun registerSaveState(
registry: SaveableStateRegistry
): List<SaveableStateRegistry.Entry> =
mutableListOf<SaveableStateRegistry.Entry>().apply {
registry
.registerProvider(KEY_SHOW_HTTP_OPTIONS) { state.showHttpOptions.value }
.also { add(it) }

registry
.registerProvider(KEY_SHOW_SOCKS_OPTIONS) { state.showSocksOptions.value }
.also { add(it) }
}

override fun consumeRestoredState(registry: SaveableStateRegistry) {
registry.consumeRestored(KEY_SHOW_HTTP_OPTIONS)?.cast<Boolean>()?.also {
state.showHttpOptions.value = it
}

registry.consumeRestored(KEY_SHOW_SOCKS_OPTIONS)?.cast<Boolean>()?.also {
state.showSocksOptions.value = it
}
}

fun handleTogglePasswordVisibility() {
state.isPasswordVisible.update { !it }
}

fun handleToggleOptions(type: InfoViewOptionsType) =
when (type) {
InfoViewOptionsType.HTTP -> {
state.showHttpOptions.update { !it }
}
InfoViewOptionsType.SOCKS -> {
state.showSocksOptions.update { !it }
}
}

companion object {

private const val KEY_SHOW_HTTP_OPTIONS = "show_http_options"
private const val KEY_SHOW_SOCKS_OPTIONS = "show_socks_options"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,21 @@ import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

enum class InfoViewOptionsType {
HTTP,
SOCKS,
}

@Stable
interface InfoViewState : UiViewState {
val isPasswordVisible: StateFlow<Boolean>
val showHttpOptions: StateFlow<Boolean>
val showSocksOptions: StateFlow<Boolean>
}

@Stable
class MutableInfoViewState @Inject internal constructor() : InfoViewState {
override val isPasswordVisible = MutableStateFlow(false)
override val showHttpOptions = MutableStateFlow(false)
override val showSocksOptions = MutableStateFlow(false)
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ internal fun LazyListScope.renderConnectionInstructions(
onShowQRCode: () -> Unit,
onTogglePasswordVisibility: () -> Unit,
onShowSlowSpeedHelp: () -> Unit,
onToggleShowOptions: (InfoViewOptionsType) -> Unit,
) {
item(
contentType = ConnectionInstructionContentTypes.SPACER,
Expand Down Expand Up @@ -92,6 +93,7 @@ internal fun LazyListScope.renderConnectionInstructions(
serverViewState = serverViewState,
onTogglePasswordVisibility = onTogglePasswordVisibility,
onShowQRCode = onShowQRCode,
onToggleShowOptions = onToggleShowOptions,
)

item(
Expand Down Expand Up @@ -129,6 +131,7 @@ private fun PreviewConnectionInstructions(state: InfoViewState, server: TestServ
onTogglePasswordVisibility = {},
onShowQRCode = {},
onShowSlowSpeedHelp = {},
onToggleShowOptions = {},
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -46,6 +45,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.pyamsoft.pydroid.theme.keylines
import com.pyamsoft.pydroid.ui.haptics.LocalHapticManager
import com.pyamsoft.tetherfi.core.FeatureFlags
import com.pyamsoft.tetherfi.info.InfoViewOptionsType
import com.pyamsoft.tetherfi.info.InfoViewState
import com.pyamsoft.tetherfi.info.MutableInfoViewState
import com.pyamsoft.tetherfi.info.R
Expand Down Expand Up @@ -77,6 +77,7 @@ internal fun LazyListScope.renderDeviceSetup(
serverViewState: ServerViewState,
onShowQRCode: () -> Unit,
onTogglePasswordVisibility: () -> Unit,
onToggleShowOptions: (InfoViewOptionsType) -> Unit,
) {
item(
contentType = DeviceSetupContentTypes.SETTINGS,
Expand Down Expand Up @@ -238,21 +239,22 @@ internal fun LazyListScope.renderDeviceSetup(
style = MaterialTheme.typography.bodyLarge,
)

// TODO(Peter): Move into VM scope
val (showHttpOptions, setShowHttpOptions) = remember { mutableStateOf(false) }
val (showSocksOptions, setShowSocksOptions) = remember { mutableStateOf(false) }

Column(
modifier = Modifier.padding(top = MaterialTheme.keylines.baseline),
) {
val showHttpOptions by state.showHttpOptions.collectAsStateWithLifecycle()

if (featureFlags.isSocksProxyEnabled) {
Row(
modifier = Modifier.clickable { setShowHttpOptions(!showHttpOptions) },
modifier = Modifier.clickable { onToggleShowOptions(InfoViewOptionsType.HTTP) },
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = stringResource(R.string.view_http_options),
style = MaterialTheme.typography.labelLarge,
style =
MaterialTheme.typography.labelLarge.copy(
color = MaterialTheme.colorScheme.onSurfaceVariant,
),
)

Icon(
Expand All @@ -261,6 +263,7 @@ internal fun LazyListScope.renderDeviceSetup(
if (showHttpOptions) Icons.AutoMirrored.Filled.KeyboardArrowRight
else Icons.Filled.KeyboardArrowDown,
contentDescription = stringResource(R.string.view_http_options),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
Expand Down Expand Up @@ -338,13 +341,18 @@ internal fun LazyListScope.renderDeviceSetup(
Column(
modifier = Modifier.padding(top = MaterialTheme.keylines.baseline),
) {
val showSocksOptions by state.showSocksOptions.collectAsStateWithLifecycle()

Row(
modifier = Modifier.clickable { setShowSocksOptions(!showSocksOptions) },
modifier = Modifier.clickable { onToggleShowOptions(InfoViewOptionsType.SOCKS) },
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = stringResource(R.string.view_socks_options),
style = MaterialTheme.typography.labelLarge,
style =
MaterialTheme.typography.labelLarge.copy(
color = MaterialTheme.colorScheme.onSurfaceVariant,
),
)

Icon(
Expand All @@ -353,6 +361,7 @@ internal fun LazyListScope.renderDeviceSetup(
if (showSocksOptions) Icons.AutoMirrored.Filled.KeyboardArrowRight
else Icons.Filled.KeyboardArrowDown,
contentDescription = stringResource(R.string.view_http_options),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}

Expand Down Expand Up @@ -441,6 +450,7 @@ private fun PreviewDeviceSetup(state: InfoViewState, server: TestServerState) {
state = state,
onTogglePasswordVisibility = {},
onShowQRCode = {},
onToggleShowOptions = {},
)
}
}
Expand Down

0 comments on commit 9712b68

Please sign in to comment.