Skip to content

Commit 122a258

Browse files
committed
refactor: edit param compose screen 2/2
1 parent 7309b6b commit 122a258

15 files changed

Lines changed: 137 additions & 389 deletions

File tree

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

Lines changed: 34 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,36 @@ package com.androidvip.sysctlgui.ui.params.edit
33
import android.app.Activity
44
import android.content.Intent
55
import android.os.Bundle
6-
import android.view.MenuItem
7-
import android.view.View
6+
import androidx.activity.ComponentActivity
7+
import androidx.activity.compose.setContent
8+
import androidx.annotation.StringRes
89
import androidx.appcompat.app.AlertDialog
9-
import androidx.appcompat.app.AppCompatActivity
1010
import androidx.lifecycle.lifecycleScope
1111
import com.androidvip.sysctlgui.R
1212
import com.androidvip.sysctlgui.data.models.KernelParam
13-
import com.androidvip.sysctlgui.domain.usecase.ApplyParamsUseCase
14-
import com.androidvip.sysctlgui.domain.usecase.UpdateUserParamUseCase
15-
import com.androidvip.sysctlgui.showAsLight
13+
import com.androidvip.sysctlgui.design.theme.SysctlGuiTheme
1614
import com.androidvip.sysctlgui.toast
1715
import com.androidvip.sysctlgui.ui.params.user.RemovableParamAdapter
18-
import com.google.android.material.snackbar.Snackbar
1916
import kotlinx.coroutines.launch
20-
import org.koin.android.ext.android.inject
2117
import org.koin.androidx.viewmodel.ext.android.viewModel
2218

23-
class EditKernelParamActivity : AppCompatActivity() {
19+
class EditKernelParamActivity : ComponentActivity() {
2420
private val viewModel by viewModel<EditParamViewModel>()
25-
private val applyParamsUseCase: ApplyParamsUseCase by inject()
26-
private val updateUserParamUseCase: UpdateUserParamUseCase by inject()
27-
28-
private lateinit var kernelParameter: KernelParam
21+
private val isEditingSavedParam: Boolean
22+
get() = intent.getBooleanExtra(
23+
RemovableParamAdapter.EXTRA_EDIT_SAVED_PARAM,
24+
false
25+
)
2926

3027
override fun onCreate(savedInstanceState: Bundle?) {
3128
super.onCreate(savedInstanceState)
3229

30+
setContent {
31+
SysctlGuiTheme {
32+
EditParamScreen(viewModel = viewModel)
33+
}
34+
}
35+
3336
lifecycleScope.launch {
3437
viewModel.effect.collect(::handleViewEffect)
3538
}
@@ -42,47 +45,6 @@ class EditKernelParamActivity : AppCompatActivity() {
4245
handleIntent(intent ?: return)
4346
}
4447

45-
override fun onOptionsItemSelected(item: MenuItem): Boolean {
46-
when (item.itemId) {
47-
android.R.id.home -> onBackPressed()
48-
R.id.action_favorite -> {
49-
if (kernelParameter.favorite) {
50-
kernelParameter.favorite = false
51-
item.setIcon(R.drawable.ic_favorite_unselected)
52-
} else {
53-
kernelParameter.favorite = true
54-
item.setIcon(R.drawable.ic_favorite_selected)
55-
}
56-
57-
lifecycleScope.launch {
58-
updateUserParamUseCase(kernelParameter)
59-
}
60-
return true
61-
}
62-
63-
R.id.action_tasker -> {
64-
selectTaskerListAsDialog { taskerList ->
65-
if (kernelParameter.taskerParam) {
66-
kernelParameter.taskerParam = false
67-
item.setIcon(R.drawable.ic_action_tasker_add)
68-
toast(getString(R.string.removed_from_tasker_list, taskerList))
69-
} else {
70-
kernelParameter.favorite = true
71-
item.setIcon(R.drawable.ic_action_tasker_remove)
72-
toast(getString(R.string.added_to_tasker_list, taskerList))
73-
}
74-
75-
kernelParameter.taskerList = taskerList
76-
lifecycleScope.launch {
77-
updateUserParamUseCase(kernelParameter)
78-
}
79-
}
80-
return true
81-
}
82-
}
83-
return super.onOptionsItemSelected(item)
84-
}
85-
8648
private fun handleIntent(intent: Intent) {
8749
val extraParam = RemovableParamAdapter.EXTRA_PARAM
8850
val param = intent.getParcelableExtra(extraParam) as? KernelParam
@@ -99,7 +61,17 @@ class EditKernelParamActivity : AppCompatActivity() {
9961
}
10062

10163
private fun handleViewEffect(effect: EditParamViewEffect) {
64+
when (effect) {
65+
EditParamViewEffect.NavigateBack -> onBackPressedDispatcher.onBackPressed()
66+
EditParamViewEffect.ShowTaskerListSelection -> {
67+
selectTaskerListAsDialog { listId ->
68+
viewModel.onEvent(EditParamViewEvent.TaskerListSelected(listId))
69+
}
70+
}
10271

72+
is EditParamViewEffect.ShowApplyError -> doAfterParamNotApplied(effect.messageRes)
73+
is EditParamViewEffect.ShowApplySuccess -> doAfterParamApplied()
74+
}
10375
}
10476

10577
private fun selectTaskerListAsDialog(block: (Int) -> Unit) {
@@ -116,48 +88,22 @@ class EditKernelParamActivity : AppCompatActivity() {
11688
}
11789
}
11890

119-
private suspend fun applyParam() {
120-
val isEditingSavedParam = intent.getBooleanExtra(
121-
RemovableParamAdapter.EXTRA_EDIT_SAVED_PARAM,
122-
false
123-
)
124-
125-
val newValue = "binding.editParamInput.text.toString()"
126-
kernelParameter.value = newValue
127-
128-
val result = runCatching { applyParamsUseCase(kernelParameter) }
129-
val feedback = if (result.isSuccess) {
91+
private fun doAfterParamApplied() {
92+
if (isEditingSavedParam) {
13093
setResult(Activity.RESULT_OK)
131-
updateUserParamUseCase(kernelParameter)
132-
getString(R.string.done)
133-
} else {
134-
setResult(Activity.RESULT_CANCELED)
135-
getString(R.string.apply_failure_format, result.exceptionOrNull()?.message.orEmpty())
94+
toast(R.string.done)
95+
finish()
13696
}
97+
}
13798

99+
private fun doAfterParamNotApplied(@StringRes messageRes: Int) {
100+
toast(messageRes)
138101
if (isEditingSavedParam) {
139-
toast(feedback)
102+
setResult(Activity.RESULT_CANCELED)
140103
finish()
141-
} else {
142-
Snackbar.make(
143-
View(this),
144-
feedback,
145-
Snackbar.LENGTH_LONG
146-
).setAction(R.string.undo) {
147-
lifecycleScope.launchWhenResumed {
148-
updateUserParamUseCase(kernelParameter)
149-
}
150-
}.showAsLight()
151104
}
152105
}
153106

154-
private fun isTaskerInstalled(): Boolean {
155-
return runCatching {
156-
packageManager.getPackageInfo("net.dinglisch.android.taskerm", 0)
157-
true
158-
}.getOrDefault(false)
159-
}
160-
161107
companion object {
162108
const val NAME_TRANSITION_NAME = "transition_title"
163109
const val VALUE_TRANSITION_NAME = "transition_value"

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

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ import androidx.compose.material3.MaterialTheme
3131
import androidx.compose.material3.OutlinedTextField
3232
import androidx.compose.material3.Scaffold
3333
import androidx.compose.material3.SmallFloatingActionButton
34+
import androidx.compose.material3.SnackbarHost
35+
import androidx.compose.material3.SnackbarHostState
36+
import androidx.compose.material3.SnackbarResult
3437
import androidx.compose.material3.Text
3538
import androidx.compose.material3.TopAppBar
3639
import androidx.compose.runtime.Composable
40+
import androidx.compose.runtime.LaunchedEffect
3741
import androidx.compose.runtime.collectAsState
3842
import androidx.compose.runtime.derivedStateOf
3943
import androidx.compose.runtime.getValue
@@ -58,6 +62,7 @@ import com.androidvip.sysctlgui.data.models.KernelParam
5862
@Composable
5963
fun EditParamScreen(viewModel: EditParamViewModel) {
6064
val state by viewModel.uiState.collectAsState()
65+
val snackbarHostState = remember { SnackbarHostState() }
6166
val listState = rememberLazyListState()
6267
val expandedFabState = remember {
6368
derivedStateOf {
@@ -80,6 +85,7 @@ fun EditParamScreen(viewModel: EditParamViewModel) {
8085
}
8186
)
8287
},
88+
snackbarHost = { SnackbarHost(snackbarHostState) },
8389
floatingActionButton = {
8490
FloatingActionButtonColumn(
8591
onReset = { viewModel.onEvent(EditParamViewEvent.ResetPressed) },
@@ -99,7 +105,7 @@ fun EditParamScreen(viewModel: EditParamViewModel) {
99105
item {
100106
ParamValues(
101107
param = state.param,
102-
appliedValue = state.appliedValue,
108+
appliedValue = state.restoreValue,
103109
keyboardType = state.keyboardType,
104110
singleLine = state.singleLine
105111
)
@@ -115,6 +121,26 @@ fun EditParamScreen(viewModel: EditParamViewModel) {
115121
item { ParamDocs(info = state.paramInfo) }
116122
}
117123
}
124+
125+
val successMessage = stringResource(id = R.string.done)
126+
val undoMessage = stringResource(id = R.string.undo)
127+
LaunchedEffect(key1 = Unit) {
128+
viewModel.effect.collect { effect ->
129+
when (effect) {
130+
is EditParamViewEffect.ShowApplySuccess -> {
131+
val result = snackbarHostState.showSnackbar(
132+
message = successMessage,
133+
actionLabel = undoMessage
134+
)
135+
136+
if (result == SnackbarResult.ActionPerformed) {
137+
viewModel.onEvent(EditParamViewEvent.ResetPressed)
138+
}
139+
}
140+
else -> Unit
141+
}
142+
}
143+
}
118144
}
119145

120146
@Composable
@@ -240,6 +266,7 @@ private fun ParamValues(
240266
imeAction = ImeAction.Done
241267
),
242268
maxLines = 3,
269+
singleLine = singleLine,
243270
value = typedValue,
244271
onValueChange = { typedValue = it }
245272
)
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package com.androidvip.sysctlgui.ui.params.edit
22

3-
sealed interface EditParamViewEffect {
3+
import androidx.annotation.StringRes
44

5+
sealed interface EditParamViewEffect {
6+
class ShowApplyError(@StringRes val messageRes: Int) : EditParamViewEffect
7+
object ShowApplySuccess : EditParamViewEffect
8+
object NavigateBack : EditParamViewEffect
9+
object ShowTaskerListSelection : EditParamViewEffect
510
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ sealed interface EditParamViewEvent {
1010
object TaskerPressed : EditParamViewEvent
1111
object ApplyPressed : EditParamViewEvent
1212
object ResetPressed : EditParamViewEvent
13+
class TaskerListSelected(val listId: Int) : EditParamViewEvent
1314
class ParamValueInputChanged(val newValue: String) : EditParamViewEvent
1415
}

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

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@ import android.content.Context
44
import android.content.pm.PackageManager
55
import android.os.Build
66
import androidx.compose.ui.text.input.KeyboardType
7+
import androidx.lifecycle.viewModelScope
78
import com.androidvip.sysctlgui.R
89
import com.androidvip.sysctlgui.data.models.KernelParam
10+
import com.androidvip.sysctlgui.domain.exceptions.ApplyValueException
11+
import com.androidvip.sysctlgui.domain.exceptions.CommitModeException
912
import com.androidvip.sysctlgui.domain.repository.AppPrefs
1013
import com.androidvip.sysctlgui.domain.usecase.ApplyParamsUseCase
1114
import com.androidvip.sysctlgui.domain.usecase.UpdateUserParamUseCase
1215
import com.androidvip.sysctlgui.readLines
1316
import com.androidvip.sysctlgui.utils.BaseViewModel
1417
import java.io.InputStream
18+
import kotlinx.coroutines.launch
1519

1620
class EditParamViewModel(
1721
private val prefs: AppPrefs,
@@ -22,15 +26,30 @@ class EditParamViewModel(
2226

2327
override fun onEvent(event: EditParamViewEvent) {
2428
when (event) {
25-
EditParamViewEvent.ApplyPressed -> TODO()
26-
EditParamViewEvent.BackPressed -> TODO()
27-
EditParamViewEvent.FavoritePressed -> TODO()
29+
EditParamViewEvent.ApplyPressed -> {
30+
applyParam(currentState.param.copy(value = currentState.typedValue))
31+
}
32+
EditParamViewEvent.BackPressed -> {
33+
setEffect { EditParamViewEffect.NavigateBack }
34+
}
35+
EditParamViewEvent.FavoritePressed -> {
36+
updateParam(currentState.param.copy(favorite = !currentState.param.favorite))
37+
}
38+
is EditParamViewEvent.TaskerListSelected -> {
39+
updateParam(currentState.param.copy(taskerList = event.listId))
40+
}
2841
is EditParamViewEvent.ParamValueInputChanged -> {
2942
setState { copy(typedValue = event.newValue) }
3043
}
31-
is EditParamViewEvent.ReceivedParam -> setInitialState(event.param, event.context)
32-
EditParamViewEvent.ResetPressed -> TODO()
33-
EditParamViewEvent.TaskerPressed -> TODO()
44+
is EditParamViewEvent.ReceivedParam -> {
45+
setInitialState(event.param, event.context)
46+
}
47+
EditParamViewEvent.ResetPressed -> {
48+
applyParam(currentState.param.copy(value = currentState.restoreValue))
49+
}
50+
EditParamViewEvent.TaskerPressed -> {
51+
setEffect { EditParamViewEffect.ShowTaskerListSelection }
52+
}
3453
}
3554
}
3655

@@ -42,7 +61,7 @@ class EditParamViewModel(
4261
setState {
4362
copy(
4463
param = param,
45-
appliedValue = param.value,
64+
restoreValue = param.value,
4665
typedValue = param.value,
4766
paramInfo = findParamInfo(param, context),
4867
taskerAvailable = isTaskerInstalled(context),
@@ -52,6 +71,38 @@ class EditParamViewModel(
5271
}
5372
}
5473

74+
private fun applyParam(param: KernelParam) {
75+
viewModelScope.launch {
76+
runCatching {
77+
applyParams(param)
78+
}.onFailure {
79+
val messageRes = when (it) {
80+
is ApplyValueException -> R.string.apply_value_error
81+
is CommitModeException -> R.string.commit_value_error
82+
else -> R.string.error
83+
}
84+
setEffect { EditParamViewEffect.ShowApplyError(messageRes) }
85+
}.onSuccess {
86+
setEffect { EditParamViewEffect.ShowApplySuccess }
87+
setState {
88+
copy(param = param, hasApplied = param.value != currentState.restoreValue)
89+
}
90+
}
91+
}
92+
}
93+
94+
private fun updateParam(param: KernelParam) {
95+
viewModelScope.launch {
96+
runCatching {
97+
updateUserParam(param)
98+
}.onFailure {
99+
setEffect { EditParamViewEffect.ShowApplyError(R.string.error) }
100+
}.onSuccess {
101+
setState { copy(param = param) }
102+
}
103+
}
104+
}
105+
55106
private fun getKeyboardTypeForValue(paramValue: String): KeyboardType {
56107
if (!prefs.guessInputType) return KeyboardType.Text
57108

@@ -71,7 +122,7 @@ class EditParamViewModel(
71122
"string",
72123
packageName
73124
)
74-
val stringRes = if (resId != 0) runCatching { getString(resId) }.getOrNull() else null
125+
val stringRes = runCatching { getString(resId) }.getOrNull()
75126

76127
// Prefer the documented string resource
77128
if (stringRes != null) return stringRes
@@ -121,7 +172,7 @@ class EditParamViewModel(
121172
.last()
122173
}.getOrNull()
123174

124-
return if (!info.isNullOrEmpty()) info else null
175+
return info.takeIf { it.isNullOrEmpty().not() }
125176
}
126177

127178
private fun isTaskerInstalled(context: Context): Boolean {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import com.androidvip.sysctlgui.data.models.KernelParam
55

66
data class EditParamViewState(
77
val param: KernelParam = KernelParam(),
8-
val appliedValue: String = "", // Backup,
8+
val restoreValue: String = "", // Backup,
99
val typedValue: String = "",
1010
val hasApplied: Boolean = false,
1111
val paramInfo: String? = null,

0 commit comments

Comments
 (0)