Skip to content

Commit 6b872b3

Browse files
committed
bugfix: browse screen back button v3
1 parent 857e588 commit 6b872b3

4 files changed

Lines changed: 63 additions & 6 deletions

File tree

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.androidvip.sysctlgui.ui.main
22

3+
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
34
import androidx.compose.animation.AnimatedVisibility
45
import androidx.compose.animation.expandVertically
56
import androidx.compose.animation.fadeIn
@@ -52,6 +53,8 @@ private fun MainScreenContent(
5253
navController: NavHostController,
5354
snackbarHostState: SnackbarHostState
5455
) {
56+
val onBackPressedDispatcherOwner = LocalOnBackPressedDispatcherOwner.current
57+
5558
Scaffold(
5659
topBar = {
5760
AnimatedVisibility(
@@ -65,7 +68,9 @@ private fun MainScreenContent(
6568
showSearch = state.showSearchAction,
6669
showBack = state.showBackButton,
6770
onSearchPressed = { navController.navigate(UiRoute.Search) },
68-
onBackPressed = { navController.popBackStack() }
71+
onBackPressed = {
72+
onBackPressedDispatcherOwner?.onBackPressedDispatcher?.onBackPressed()
73+
}
6974
)
7075
}
7176
},

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

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ import androidx.compose.foundation.layout.height
2020
import androidx.compose.foundation.layout.padding
2121
import androidx.compose.foundation.lazy.LazyColumn
2222
import androidx.compose.foundation.lazy.rememberLazyListState
23+
import androidx.compose.material.ExperimentalMaterialApi
24+
import androidx.compose.material.pullrefresh.PullRefreshIndicator
25+
import androidx.compose.material.pullrefresh.pullRefresh
26+
import androidx.compose.material.pullrefresh.rememberPullRefreshState
2327
import androidx.compose.material3.ExperimentalMaterial3Api
2428
import androidx.compose.material3.Icon
2529
import androidx.compose.material3.MaterialTheme
@@ -31,6 +35,7 @@ import androidx.compose.runtime.derivedStateOf
3135
import androidx.compose.runtime.getValue
3236
import androidx.compose.runtime.mutableStateOf
3337
import androidx.compose.runtime.remember
38+
import androidx.compose.runtime.rememberCoroutineScope
3439
import androidx.compose.runtime.setValue
3540
import androidx.compose.runtime.snapshotFlow
3641
import androidx.compose.ui.Alignment
@@ -57,13 +62,16 @@ import com.androidvip.sysctlgui.ui.main.MainViewModel
5762
import com.androidvip.sysctlgui.ui.main.MainViewState
5863
import com.androidvip.sysctlgui.ui.params.DocumentationBottomSheet
5964
import com.androidvip.sysctlgui.utils.browse
65+
import kotlinx.coroutines.delay
6066
import kotlinx.coroutines.flow.distinctUntilChanged
6167
import kotlinx.coroutines.flow.filter
6268
import kotlinx.coroutines.flow.map
69+
import kotlinx.coroutines.launch
6370
import org.koin.compose.viewmodel.koinViewModel
6471
import java.io.File
72+
import kotlin.time.Duration.Companion.seconds
6573

66-
@OptIn(ExperimentalMaterial3Api::class)
74+
@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
6775
@Composable
6876
fun ParamBrowseScreen(
6977
mainViewModel: MainViewModel = koinViewModel(),
@@ -115,7 +123,9 @@ fun ParamBrowseScreen(
115123
backEnabled = state.backEnabled,
116124
onBackPressed = {
117125
viewModel.onEvent(ParamBrowseViewEvent.BackRequested)
118-
}
126+
},
127+
isRefreshing = state.loading,
128+
onRefresh = { viewModel.onEvent(ParamBrowseViewEvent.RefreshRequested) }
119129
)
120130

121131
documentation?.let {
@@ -126,6 +136,8 @@ fun ParamBrowseScreen(
126136
}
127137
}
128138

139+
140+
@OptIn(ExperimentalMaterialApi::class)
129141
@Composable
130142
private fun ParamBrowseScreenContent(
131143
params: List<UiKernelParam>,
@@ -135,8 +147,11 @@ private fun ParamBrowseScreenContent(
135147
onDocumentationClicked: (ParamDocumentation) -> Unit,
136148
backEnabled: Boolean = false,
137149
onBackPressed: () -> Unit,
150+
isRefreshing: Boolean,
151+
onRefresh: () -> Unit
138152
) {
139153
val listState = rememberLazyListState()
154+
val pullRefreshState = rememberPullRefreshState(refreshing = isRefreshing, onRefresh = onRefresh)
140155
var headerVisible by remember { mutableStateOf(backEnabled) }
141156

142157
BackHandler(enabled = backEnabled, onBack = onBackPressed)
@@ -173,7 +188,11 @@ private fun ParamBrowseScreenContent(
173188

174189
val finalHeaderVisible = (headerVisible || isAtTop) && backEnabled
175190

176-
Box(modifier = Modifier.fillMaxSize()) {
191+
Box(
192+
modifier = Modifier
193+
.fillMaxSize()
194+
.pullRefresh(pullRefreshState),
195+
) {
177196
val spacerHeight by animateDpAsState(if (finalHeaderVisible) 56.dp else 0.dp)
178197
LazyColumn(
179198
state = listState,
@@ -226,6 +245,14 @@ private fun ParamBrowseScreenContent(
226245
onClicked = { onDocumentationClicked(documentation!!) }
227246
)
228247
}
248+
249+
PullRefreshIndicator(
250+
refreshing = isRefreshing,
251+
state = pullRefreshState,
252+
modifier = Modifier.align(Alignment.TopCenter),
253+
backgroundColor = MaterialTheme.colorScheme.surfaceContainerHighest,
254+
contentColor = MaterialTheme.colorScheme.tertiary
255+
)
229256
}
230257
}
231258

@@ -287,6 +314,8 @@ internal fun ParamBrowseScreenContentPreview() {
287314
var params by remember(currentPath) {
288315
mutableStateOf(mapFilesToParams(File(currentPath).listFiles()))
289316
}
317+
var isRefreshingPreview by remember { mutableStateOf(false) }
318+
val scope = rememberCoroutineScope()
290319

291320
SysctlGuiTheme(dynamicColor = true) {
292321
Box(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
@@ -307,6 +336,14 @@ internal fun ParamBrowseScreenContentPreview() {
307336
onDocumentationClicked = {},
308337
backEnabled = currentPath != root.path,
309338
onBackPressed = { currentPath = File(currentPath).parent ?: root.path },
339+
isRefreshing = isRefreshingPreview,
340+
onRefresh = {
341+
scope.launch {
342+
isRefreshingPreview = true
343+
delay(2.seconds)
344+
isRefreshingPreview = false
345+
}
346+
}
310347
)
311348
}
312349
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.androidvip.sysctlgui.domain.models.ParamDocumentation
44
import com.androidvip.sysctlgui.models.UiKernelParam
55

66
data class ParamBrowseState(
7+
val loading: Boolean = false,
78
val params: List<UiKernelParam> = emptyList(),
89
val currentPath: String = "",
910
val backEnabled: Boolean = false,
@@ -20,4 +21,5 @@ sealed interface ParamBrowseViewEvent {
2021
data class ParamClicked(val param: UiKernelParam) : ParamBrowseViewEvent
2122
data class DocumentationClicked(val docs: ParamDocumentation) : ParamBrowseViewEvent
2223
object BackRequested : ParamBrowseViewEvent
24+
object RefreshRequested : ParamBrowseViewEvent
2325
}

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@ class ParamBrowseViewModel(
2727

2828
init {
2929
viewModelScope.launch {
30+
setState { copy(loading = true) }
3031
val startingDirectory = File(Consts.PROC_SYS)
3132
val params = getParams(startingDirectory)
3233

3334
setState {
3435
copy(
3536
params = params,
36-
currentPath = startingDirectory.absolutePath
37+
currentPath = startingDirectory.absolutePath,
38+
loading = false
3739
)
3840
}
3941
}
@@ -47,11 +49,20 @@ class ParamBrowseViewModel(
4749

4850
ParamBrowseViewEvent.BackRequested -> onBackRequested()
4951
is ParamBrowseViewEvent.ParamClicked -> onParamClicked(event.param)
52+
ParamBrowseViewEvent.RefreshRequested -> handleRefreshRequested()
5053
}
5154
}
5255

56+
private fun handleRefreshRequested() {
57+
val currentPath = currentState.currentPath
58+
if (currentPath == Consts.PROC_SYS) return
59+
60+
fetchChildParams(currentPath)
61+
}
62+
5363
private fun fetchChildParams(parentParam: UiKernelParam) {
5464
viewModelScope.launch {
65+
setState { copy(loading = true) }
5566
runCatching {
5667
val newParamsDeferred = async { getParams(File(parentParam.path)) }
5768
val directoryDocumentationDeferred = async { getParamDocumentation(parentParam) }
@@ -64,11 +75,13 @@ class ParamBrowseViewModel(
6475
params = newParams,
6576
currentPath = parentParam.path,
6677
backEnabled = parentParam.path != Consts.PROC_SYS,
67-
documentation = directoryDocumentation
78+
documentation = directoryDocumentation,
79+
loading = false
6880
)
6981
}
7082
}.onFailure {
7183
setEffect { ParamBrowseViewEffect.ShowError(it.message ?: "Unknown error") }
84+
setState { copy(loading = false) }
7285
}
7386
}
7487
}

0 commit comments

Comments
 (0)