Skip to content

Commit fb69141

Browse files
committed
bugfix: edit param screen
1 parent 5509aea commit fb69141

6 files changed

Lines changed: 119 additions & 75 deletions

File tree

app/src/main/kotlin/com/androidvip/sysctlgui/ui/main/MainScreen.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import androidx.compose.animation.slideInVertically
1010
import androidx.compose.animation.slideOutVertically
1111
import androidx.compose.material3.ExperimentalMaterial3Api
1212
import androidx.compose.material3.Scaffold
13+
import androidx.compose.material3.SnackbarDuration
1314
import androidx.compose.material3.SnackbarHost
1415
import androidx.compose.material3.SnackbarHostState
1516
import androidx.compose.runtime.Composable
@@ -37,7 +38,8 @@ fun MainScreen(viewModel: MainViewModel = koinViewModel()) {
3738
if (effect is MainViewEffect.ShowSnackbar) {
3839
val result = snackbarHostState.showSnackbar(
3940
message = effect.message,
40-
actionLabel = effect.actionLabel
41+
actionLabel = effect.actionLabel,
42+
duration = SnackbarDuration.Long
4143
)
4244
viewModel.onEvent(MainViewEvent.OnSnackbarResult(result))
4345
}

app/src/main/kotlin/com/androidvip/sysctlgui/ui/params/browse/ParamBrowseViewModel.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ class ParamBrowseViewModel(
6565
setState { copy(loading = true) }
6666
runCatching {
6767
val newParamsDeferred = async { getParams(File(parentParam.path)) }
68-
val directoryDocumentationDeferred = async { getParamDocumentation(parentParam) }
68+
val directoryDocumentationDeferred = async {
69+
runCatching { getParamDocumentation(parentParam) }.getOrNull()
70+
}
6971

7072
val newParams = newParamsDeferred.await()
7173
val directoryDocumentation = directoryDocumentationDeferred.await()

app/src/main/kotlin/com/androidvip/sysctlgui/ui/params/edit/EditParamScreen.kt

Lines changed: 87 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.androidvip.sysctlgui.ui.params.edit
22

33
import android.content.ClipData
44
import android.widget.Toast
5+
import androidx.activity.compose.BackHandler
56
import androidx.compose.animation.AnimatedContent
67
import androidx.compose.animation.AnimatedVisibility
78
import androidx.compose.animation.SizeTransform
@@ -12,6 +13,7 @@ import androidx.compose.animation.slideOutVertically
1213
import androidx.compose.animation.togetherWith
1314
import androidx.compose.foundation.background
1415
import androidx.compose.foundation.combinedClickable
16+
import androidx.compose.foundation.interaction.MutableInteractionSource
1517
import androidx.compose.foundation.layout.Arrangement
1618
import androidx.compose.foundation.layout.Box
1719
import androidx.compose.foundation.layout.Column
@@ -97,7 +99,7 @@ fun EditParamScreen(
9799
val context = LocalContext.current
98100
val state = viewModel.uiState.collectAsStateWithLifecycle()
99101
val taskerListOptions = listOf("Primary", "Secondary")
100-
var showSelectTaskerListDialog by rememberSaveable { mutableStateOf(true) }
102+
var showSelectTaskerListDialog by rememberSaveable { mutableStateOf(false) }
101103
var selectedOptionIndex by rememberSaveable {
102104
mutableIntStateOf(Consts.LIST_NUMBER_PRIMARY_TASKER)
103105
}
@@ -156,6 +158,7 @@ fun EditParamScreen(
156158
viewModel.onEvent(EditParamViewEvent.ApplyPressed(it))
157159
},
158160
onTaskerClicked = {
161+
showSelectTaskerListDialog = it
159162
viewModel.onEvent(EditParamViewEvent.TaskerTogglePressed(it, selectedOptionIndex))
160163
},
161164
onDocsReadMorePressed = {
@@ -229,6 +232,8 @@ private fun EditParamContent(
229232
modifier = Modifier
230233
.combinedClickable(
231234
enabled = true,
235+
indication = null,
236+
interactionSource = remember { MutableInteractionSource() },
232237
onClick = {
233238
Toast.makeText(context, "Long press to copy", Toast.LENGTH_SHORT).show()
234239
},
@@ -287,7 +292,7 @@ private fun EditParamContent(
287292
)
288293
}
289294

290-
if (param.isTaskerParam && state.taskerAvailable) {
295+
AnimatedVisibility(visible = param.isTaskerParam && state.taskerAvailable) {
291296
val listName = taskerListNameResolver(param.taskerList)
292297
AssistChip(
293298
onClick = { onTaskerClicked(true) },
@@ -337,6 +342,11 @@ private fun ParamValueContent(
337342
var editedValue by remember(param.value) { mutableStateOf(param.value) }
338343
val view = LocalView.current
339344

345+
BackHandler(
346+
enabled = isEditing,
347+
onBack = { isEditing = false }
348+
)
349+
340350
HorizontalDivider()
341351

342352
Row(
@@ -454,75 +464,90 @@ private fun ParamDocs(
454464
color = MaterialTheme.colorScheme.onBackground
455465
)
456466

457-
if (documentation != null) {
458-
val documentationText = if (!documentation.documentationHtml.isNullOrEmpty()) {
459-
AnnotatedString.fromHtml(
460-
htmlString = documentation.documentationHtml.orEmpty(),
461-
linkStyles = TextLinkStyles(
462-
style = MaterialTheme.typography.bodyMedium.toSpanStyle().copy(
463-
color = MaterialTheme.colorScheme.primary,
464-
textDecoration = TextDecoration.Underline,
465-
fontWeight = FontWeight.Medium
466-
),
467-
pressedStyle = MaterialTheme.typography.bodyMedium.toSpanStyle().copy(
468-
color = MaterialTheme.colorScheme.tertiary,
469-
textDecoration = TextDecoration.Underline,
470-
fontWeight = FontWeight.Medium
471-
)
472-
)
467+
AnimatedContent(targetState = documentation != null) { documentationAvailable ->
468+
if (documentationAvailable && documentation != null) {
469+
DocumentationContent(
470+
documentation = documentation,
471+
onReadMorePressed = onReadMorePressed
473472
)
474473
} else {
475-
AnnotatedString(documentation.documentationText)
476-
}
477-
478-
SelectionContainer {
479-
Text(
474+
Card(
480475
modifier = Modifier
481476
.fillMaxWidth()
482-
.padding(vertical = 8.dp),
483-
text = documentationText,
484-
style = MaterialTheme.typography.bodyMedium,
485-
color = MaterialTheme.colorScheme.onSurfaceVariant
486-
)
477+
.padding(24.dp),
478+
colors = CardDefaults.cardColors(
479+
containerColor = MaterialTheme.colorScheme.errorContainer
480+
)
481+
) {
482+
Row(
483+
modifier = Modifier.padding(24.dp),
484+
horizontalArrangement = Arrangement.spacedBy(
485+
16.dp,
486+
Alignment.CenterHorizontally
487+
)
488+
) {
489+
Icon(
490+
imageVector = Icons.Rounded.Warning,
491+
contentDescription = stringResource(android.R.string.dialog_alert_title),
492+
tint = MaterialTheme.colorScheme.onErrorContainer
493+
)
494+
Text(
495+
text = "No documentation available",
496+
style = MaterialTheme.typography.bodyLarge.copy(),
497+
fontWeight = FontWeight.Medium,
498+
color = MaterialTheme.colorScheme.onErrorContainer
499+
)
500+
}
501+
}
487502
}
503+
}
504+
}
505+
}
488506

489-
TextButton(
490-
onClick = onReadMorePressed,
491-
modifier = Modifier
492-
.padding(vertical = 8.dp)
493-
.align(Alignment.End)
494-
) {
495-
Text(text = "Read more")
496-
}
507+
@Composable
508+
private fun DocumentationContent(
509+
documentation: ParamDocumentation,
510+
onReadMorePressed: () -> Unit
511+
) {
512+
Column {
513+
val documentationText = if (!documentation.documentationHtml.isNullOrEmpty()) {
514+
AnnotatedString.fromHtml(
515+
htmlString = documentation.documentationHtml.orEmpty(),
516+
linkStyles = TextLinkStyles(
517+
style = MaterialTheme.typography.bodyMedium.toSpanStyle().copy(
518+
color = MaterialTheme.colorScheme.primary,
519+
textDecoration = TextDecoration.Underline,
520+
fontWeight = FontWeight.Medium
521+
),
522+
pressedStyle = MaterialTheme.typography.bodyMedium.toSpanStyle().copy(
523+
color = MaterialTheme.colorScheme.tertiary,
524+
textDecoration = TextDecoration.Underline,
525+
fontWeight = FontWeight.Medium
526+
)
527+
)
528+
)
497529
} else {
498-
Card(
530+
AnnotatedString(documentation.documentationText)
531+
}
532+
533+
SelectionContainer {
534+
Text(
499535
modifier = Modifier
500536
.fillMaxWidth()
501-
.padding(24.dp),
502-
colors = CardDefaults.cardColors(
503-
containerColor = MaterialTheme.colorScheme.errorContainer
504-
)
505-
) {
506-
Row(
507-
modifier = Modifier.padding(24.dp),
508-
horizontalArrangement = Arrangement.spacedBy(
509-
16.dp,
510-
Alignment.CenterHorizontally
511-
)
512-
) {
513-
Icon(
514-
imageVector = Icons.Rounded.Warning,
515-
contentDescription = stringResource(android.R.string.dialog_alert_title),
516-
tint = MaterialTheme.colorScheme.onErrorContainer
517-
)
518-
Text(
519-
text = "No documentation available",
520-
style = MaterialTheme.typography.bodyLarge.copy(),
521-
fontWeight = FontWeight.Medium,
522-
color = MaterialTheme.colorScheme.onErrorContainer
523-
)
524-
}
525-
}
537+
.padding(vertical = 8.dp),
538+
text = documentationText,
539+
style = MaterialTheme.typography.bodyMedium,
540+
color = MaterialTheme.colorScheme.onSurfaceVariant
541+
)
542+
}
543+
544+
TextButton(
545+
onClick = onReadMorePressed,
546+
modifier = Modifier
547+
.padding(vertical = 8.dp)
548+
.align(Alignment.End)
549+
) {
550+
Text(text = "Read more")
526551
}
527552
}
528553
}

app/src/main/kotlin/com/androidvip/sysctlgui/ui/params/edit/EditParamViewModel.kt

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import com.androidvip.sysctlgui.domain.usecase.GetUserParamByNameUseCase
1212
import com.androidvip.sysctlgui.domain.usecase.IsTaskerInstalledUseCase
1313
import com.androidvip.sysctlgui.domain.usecase.UpsertUserParamUseCase
1414
import com.androidvip.sysctlgui.helpers.UiKernelParamMapper
15-
import com.androidvip.sysctlgui.models.UiKernelParam
1615
import com.androidvip.sysctlgui.utils.BaseViewModel
1716
import kotlinx.coroutines.launch
1817

@@ -37,16 +36,18 @@ class EditParamViewModel(
3736
?: getRuntimeParam(paramName)
3837
?: return@launch setEffect { EditParamViewEffect.GoBack }
3938

40-
val documentation = getDocumentation(param)
41-
4239
setState {
4340
copy(
4441
kernelParam = UiKernelParamMapper.map(param),
4542
taskerAvailable = isTaskerInstalled(),
46-
keyboardType = guessKeyboardType(param.value),
47-
documentation = documentation,
43+
keyboardType = guessKeyboardType(param.value)
4844
)
4945
}
46+
47+
val documentation = runCatching { getDocumentation(param) }.getOrNull()
48+
setState {
49+
copy(documentation = documentation)
50+
}
5051
}
5152
}
5253

@@ -56,15 +57,15 @@ class EditParamViewModel(
5657
when (event) {
5758
is EditParamViewEvent.ApplyPressed -> applyKernelParam(event.newValue)
5859
is EditParamViewEvent.UndoRequested -> {
59-
previousKernelParamValue?.let { applyKernelParam(it) }
60+
previousKernelParamValue?.let { applyKernelParam(it, true) }
6061
}
6162
is EditParamViewEvent.DocumentationReadMoreClicked -> onDocumentationReadMoreClicked()
6263
is EditParamViewEvent.FavoriteTogglePressed -> onFavoriteTogglePressed(event.newState)
6364
is EditParamViewEvent.TaskerTogglePressed -> onTaskerTogglePressed(event.newState, event.listId)
6465
}
6566
}
6667

67-
private fun applyKernelParam(newValue: String) {
68+
private fun applyKernelParam(newValue: String, isUndo: Boolean = false) {
6869
val oldParam = currentState.kernelParam
6970
viewModelScope.launch {
7071
val newParam = oldParam.copy(value = newValue)
@@ -73,7 +74,11 @@ class EditParamViewModel(
7374
upsertUserParam(newParam)
7475
}.onSuccess {
7576
setState { copy(kernelParam = newParam) }
76-
setEffect { EditParamViewEffect.ShowApplySuccess(oldParam.value) }
77+
if (!isUndo) {
78+
setEffect {
79+
EditParamViewEffect.ShowApplySuccess(previousValue = oldParam.value)
80+
}
81+
}
7782
previousKernelParamValue = oldParam.value
7883
}.onFailure {
7984
Log.e("EditParamViewModel", "Failed to apply param", it)

data/src/main/java/com/androidvip/sysctlgui/data/repository/DocumentationRepositoryImpl.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.androidvip.sysctlgui.domain.models.KernelParam
55
import com.androidvip.sysctlgui.domain.models.ParamDocumentation
66
import com.androidvip.sysctlgui.domain.repository.AppPrefs
77
import com.androidvip.sysctlgui.domain.repository.DocumentationRepository
8+
import kotlinx.coroutines.withTimeout
89

910
/**
1011
* Repository for fetching documentation for kernel parameters.
@@ -14,7 +15,6 @@ import com.androidvip.sysctlgui.domain.repository.DocumentationRepository
1415
*
1516
* @property offlineDataSource The data source for fetching documentation offline.
1617
* @property onlineDataSource The data source for fetching documentation online.
17-
* @property appPrefs The application preferences, used to determine whether to use online or
1818
* offline documentation.
1919
*/
2020
class DocumentationRepositoryImpl(
@@ -26,9 +26,15 @@ class DocumentationRepositoryImpl(
2626
online: Boolean
2727
): ParamDocumentation? {
2828
return if (online) {
29-
onlineDataSource.getDocumentation(param)
29+
withTimeout(REQUEST_TIMEOUT_MS) {
30+
onlineDataSource.getDocumentation(param)
31+
}
3032
} else {
3133
offlineDataSource.getDocumentation(param)
3234
}
3335
}
36+
37+
companion object {
38+
private const val REQUEST_TIMEOUT_MS = 3000L
39+
}
3440
}

data/src/main/java/com/androidvip/sysctlgui/data/repository/UserRepositoryImpl.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ class UserRepositoryImpl(
3131
}
3232

3333
override suspend fun upsertUserParam(param: KernelParam) = withContext(coroutineContext) {
34-
paramDao.upsert(KernelParamDTO.fromKernelParam(param))
34+
val currentDatabaseParam = getParamByName(param.name)
35+
val newParam = KernelParamDTO.fromKernelParam(param).copy(
36+
id = currentDatabaseParam?.id ?: 0
37+
)
38+
paramDao.upsert(newParam)
3539
}
3640

3741
override suspend fun upsertUserParams(params: List<KernelParam>) =

0 commit comments

Comments
 (0)