Skip to content

Commit 3a2f808

Browse files
committed
Refactor downgrade warning logic and relocate models
- Move `TranslationTarget` to its own file in the `model` package. - Introduce `DowngradeWarning` model to replace event-based warning triggers. - Update `DetailsState` and `DetailsViewModel` to manage downgrade warning state directly rather than via `DetailsEvent`. - Add `OnDismissDowngradeWarning` action to `DetailsAction`. - Refactor `DetailsRoot` to handle the downgrade warning dialog based on state changes. - Cleanup unused imports and organize resource references in `DetailsRoot`.
1 parent c20b976 commit 3a2f808

7 files changed

Lines changed: 111 additions & 76 deletions

File tree

feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsAction.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ package zed.rainxch.details.presentation
33
import org.jetbrains.compose.resources.StringResource
44
import zed.rainxch.core.domain.model.GithubRelease
55
import zed.rainxch.details.domain.model.ReleaseCategory
6+
import zed.rainxch.details.presentation.model.TranslationTarget
67

78
sealed interface DetailsAction {
89
data object Retry : DetailsAction
910
data object InstallPrimary : DetailsAction
11+
data object OnDismissDowngradeWarning : DetailsAction
1012
data object UninstallApp : DetailsAction
1113
data class DownloadAsset(
1214
val downloadUrl: String,

feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsEvent.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,5 @@ package zed.rainxch.details.presentation
22

33
sealed interface DetailsEvent {
44
data class OnOpenRepositoryInApp(val repositoryId: Long) : DetailsEvent
5-
data class InstallTrackingFailed(val message: String) : DetailsEvent
65
data class OnMessage(val message: String) : DetailsEvent
7-
data class ShowDowngradeWarning(
8-
val packageName: String,
9-
val currentVersion: String,
10-
val targetVersion: String
11-
) : DetailsEvent
126
}

feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsRoot.kt

Lines changed: 79 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -40,26 +40,23 @@ import androidx.compose.material3.TopAppBarDefaults
4040
import androidx.compose.runtime.Composable
4141
import androidx.compose.runtime.CompositionLocalProvider
4242
import androidx.compose.runtime.getValue
43-
import androidx.compose.runtime.mutableStateOf
4443
import androidx.compose.runtime.remember
4544
import androidx.compose.runtime.rememberCoroutineScope
46-
import androidx.compose.runtime.setValue
4745
import androidx.compose.ui.Alignment
4846
import androidx.compose.ui.Modifier
4947
import androidx.compose.ui.draw.shadow
5048
import androidx.compose.ui.graphics.Brush
5149
import androidx.compose.ui.graphics.Color
50+
import androidx.compose.ui.tooling.preview.Preview
5251
import androidx.compose.ui.unit.dp
5352
import androidx.lifecycle.compose.collectAsStateWithLifecycle
54-
import zed.rainxch.githubstore.core.presentation.res.*
5553
import io.github.fletchmckee.liquid.LiquidState
5654
import io.github.fletchmckee.liquid.liquefiable
5755
import io.github.fletchmckee.liquid.liquid
5856
import io.github.fletchmckee.liquid.rememberLiquidState
5957
import kotlinx.coroutines.launch
6058
import org.jetbrains.compose.resources.getString
6159
import org.jetbrains.compose.resources.stringResource
62-
import androidx.compose.ui.tooling.preview.Preview
6360
import org.koin.compose.viewmodel.koinViewModel
6461
import zed.rainxch.core.presentation.theme.GithubStoreTheme
6562
import zed.rainxch.core.presentation.utils.ObserveAsEvents
@@ -72,7 +69,26 @@ import zed.rainxch.details.presentation.components.sections.logs
7269
import zed.rainxch.details.presentation.components.sections.stats
7370
import zed.rainxch.details.presentation.components.sections.whatsNew
7471
import zed.rainxch.details.presentation.components.states.ErrorState
72+
import zed.rainxch.details.presentation.model.TranslationTarget
7573
import zed.rainxch.details.presentation.utils.LocalTopbarLiquidState
74+
import zed.rainxch.githubstore.core.presentation.res.Res
75+
import zed.rainxch.githubstore.core.presentation.res.add_to_favourites
76+
import zed.rainxch.githubstore.core.presentation.res.cancel
77+
import zed.rainxch.githubstore.core.presentation.res.dismiss
78+
import zed.rainxch.githubstore.core.presentation.res.downgrade_requires_uninstall
79+
import zed.rainxch.githubstore.core.presentation.res.downgrade_warning_message
80+
import zed.rainxch.githubstore.core.presentation.res.install_permission_blocked_message
81+
import zed.rainxch.githubstore.core.presentation.res.install_permission_unavailable
82+
import zed.rainxch.githubstore.core.presentation.res.navigate_back
83+
import zed.rainxch.githubstore.core.presentation.res.open_repository
84+
import zed.rainxch.githubstore.core.presentation.res.open_with_external_installer
85+
import zed.rainxch.githubstore.core.presentation.res.remove_from_favourites
86+
import zed.rainxch.githubstore.core.presentation.res.repository_not_starred
87+
import zed.rainxch.githubstore.core.presentation.res.repository_starred
88+
import zed.rainxch.githubstore.core.presentation.res.share_repository
89+
import zed.rainxch.githubstore.core.presentation.res.star_from_github
90+
import zed.rainxch.githubstore.core.presentation.res.uninstall_first
91+
import zed.rainxch.githubstore.core.presentation.res.unstar_from_github
7692

7793
@Composable
7894
fun DetailsRoot(
@@ -84,37 +100,56 @@ fun DetailsRoot(
84100
val state by viewModel.state.collectAsStateWithLifecycle()
85101
val snackbarHostState = remember { SnackbarHostState() }
86102
val coroutineScope = rememberCoroutineScope()
87-
var downgradeWarning by remember {
88-
mutableStateOf<DetailsEvent.ShowDowngradeWarning?>(null)
89-
}
90103

91104
ObserveAsEvents(viewModel.events) { event ->
92105
when (event) {
93106
is DetailsEvent.OnOpenRepositoryInApp -> {
94107
onOpenRepositoryInApp(event.repositoryId)
95108
}
96109

97-
is DetailsEvent.InstallTrackingFailed -> {
98-
99-
}
100-
101110
is DetailsEvent.OnMessage -> {
102111
coroutineScope.launch {
103112
snackbarHostState.showSnackbar(event.message)
104113
}
105114
}
115+
}
116+
}
106117

107-
is DetailsEvent.ShowDowngradeWarning -> {
108-
downgradeWarning = event
118+
DetailsScreen(
119+
state = state,
120+
snackbarHostState = snackbarHostState,
121+
onAction = { action ->
122+
when (action) {
123+
DetailsAction.OnNavigateBackClick -> {
124+
onNavigateBack()
125+
}
126+
127+
is DetailsAction.OpenDeveloperProfile -> {
128+
onNavigateToDeveloperProfile(action.username)
129+
}
130+
131+
is DetailsAction.OnMessage -> {
132+
coroutineScope.launch {
133+
snackbarHostState.showSnackbar(getString(action.messageText))
134+
}
135+
}
136+
137+
else -> {
138+
viewModel.onAction(action)
139+
}
109140
}
110141
}
111-
}
142+
)
112143

113-
downgradeWarning?.let { warning ->
144+
state.downgradeWarning?.let { warning ->
114145
AlertDialog(
115-
onDismissRequest = { downgradeWarning = null },
146+
onDismissRequest = {
147+
viewModel.onAction(DetailsAction.OnDismissDowngradeWarning)
148+
},
116149
title = {
117-
Text(text = stringResource(Res.string.downgrade_requires_uninstall))
150+
Text(
151+
text = stringResource(Res.string.downgrade_requires_uninstall)
152+
)
118153
},
119154
text = {
120155
Text(
@@ -128,7 +163,7 @@ fun DetailsRoot(
128163
confirmButton = {
129164
TextButton(
130165
onClick = {
131-
downgradeWarning = null
166+
viewModel.onAction(DetailsAction.OnDismissDowngradeWarning)
132167
viewModel.onAction(DetailsAction.UninstallApp)
133168
}
134169
) {
@@ -139,8 +174,14 @@ fun DetailsRoot(
139174
}
140175
},
141176
dismissButton = {
142-
TextButton(onClick = { downgradeWarning = null }) {
143-
Text(text = stringResource(Res.string.cancel))
177+
TextButton(
178+
onClick = {
179+
viewModel.onAction(DetailsAction.OnDismissDowngradeWarning)
180+
}
181+
) {
182+
Text(
183+
text = stringResource(Res.string.cancel)
184+
)
144185
}
145186
}
146187
)
@@ -177,32 +218,6 @@ fun DetailsRoot(
177218
}
178219
)
179220
}
180-
181-
DetailsScreen(
182-
state = state,
183-
snackbarHostState = snackbarHostState,
184-
onAction = { action ->
185-
when (action) {
186-
DetailsAction.OnNavigateBackClick -> {
187-
onNavigateBack()
188-
}
189-
190-
is DetailsAction.OpenDeveloperProfile -> {
191-
onNavigateToDeveloperProfile(action.username)
192-
}
193-
194-
is DetailsAction.OnMessage -> {
195-
coroutineScope.launch {
196-
snackbarHostState.showSnackbar(getString(action.messageText))
197-
}
198-
}
199-
200-
else -> {
201-
viewModel.onAction(action)
202-
}
203-
}
204-
}
205-
)
206221
}
207222

208223
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@@ -226,7 +241,9 @@ fun DetailsScreen(
226241
)
227242
},
228243
snackbarHost = {
229-
SnackbarHost(snackbarHostState)
244+
SnackbarHost(
245+
hostState = snackbarHostState
246+
)
230247
},
231248
containerColor = MaterialTheme.colorScheme.background,
232249
modifier = Modifier.liquefiable(liquidTopbarState)
@@ -242,7 +259,12 @@ fun DetailsScreen(
242259
onLanguageSelected = { language ->
243260
when (state.languagePickerTarget) {
244261
TranslationTarget.About -> onAction(DetailsAction.TranslateAbout(language.code))
245-
TranslationTarget.WhatsNew -> onAction(DetailsAction.TranslateWhatsNew(language.code))
262+
TranslationTarget.WhatsNew -> onAction(
263+
DetailsAction.TranslateWhatsNew(
264+
language.code
265+
)
266+
)
267+
246268
null -> {}
247269
}
248270
onAction(DetailsAction.DismissLanguagePicker)
@@ -524,16 +546,16 @@ private fun DetailsTopbar(
524546
)
525547
.then(
526548
if (isLiquidFrostAvailable()) {
527-
Modifier.liquid(liquidTopbarState) {
528-
this.shape = CutCornerShape(0.dp)
529-
if (isLiquidFrostAvailable()) {
530-
this.frost = 5.dp
549+
Modifier.liquid(liquidTopbarState) {
550+
this.shape = CutCornerShape(0.dp)
551+
if (isLiquidFrostAvailable()) {
552+
this.frost = 5.dp
553+
}
554+
this.curve = .25f
555+
this.refraction = .05f
556+
this.dispersion = .1f
531557
}
532-
this.curve = .25f
533-
this.refraction = .05f
534-
this.dispersion = .1f
535-
}
536-
} else Modifier.background(MaterialTheme.colorScheme.surfaceContainerHighest))
558+
} else Modifier.background(MaterialTheme.colorScheme.surfaceContainerHighest))
537559
)
538560
}
539561

feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsState.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import zed.rainxch.core.domain.model.GithubUserProfile
88
import zed.rainxch.core.domain.model.InstalledApp
99
import zed.rainxch.details.domain.model.ReleaseCategory
1010
import zed.rainxch.details.domain.model.RepoStats
11+
import zed.rainxch.details.presentation.model.DowngradeWarning
1112
import zed.rainxch.details.presentation.model.DownloadStage
1213
import zed.rainxch.details.presentation.model.InstallLogItem
1314
import zed.rainxch.details.presentation.model.TranslationState
15+
import zed.rainxch.details.presentation.model.TranslationTarget
1416

1517
data class DetailsState(
1618
val isLoading: Boolean = true,
@@ -67,6 +69,8 @@ data class DetailsState(
6769

6870
val isComingFromUpdate: Boolean = false,
6971

72+
val downgradeWarning: DowngradeWarning? = null,
73+
7074
val showExternalInstallerPrompt: Boolean = false,
7175
val pendingInstallFilePath: String? = null,
7276
) {
@@ -76,9 +80,4 @@ data class DetailsState(
7680
ReleaseCategory.PRE_RELEASE -> allReleases.filter { it.isPrerelease }
7781
ReleaseCategory.ALL -> allReleases
7882
}
79-
}
80-
81-
sealed interface TranslationTarget {
82-
data object About : TranslationTarget
83-
data object WhatsNew : TranslationTarget
8483
}

feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import zed.rainxch.core.domain.utils.ShareManager
4242
import zed.rainxch.details.domain.model.ReleaseCategory
4343
import zed.rainxch.details.domain.repository.DetailsRepository
4444
import zed.rainxch.details.domain.repository.TranslationRepository
45+
import zed.rainxch.details.presentation.model.DowngradeWarning
4546
import zed.rainxch.details.presentation.model.DownloadStage
4647
import zed.rainxch.details.presentation.model.InstallLogItem
4748
import zed.rainxch.details.presentation.model.LogResult
@@ -322,6 +323,12 @@ class DetailsViewModel(
322323
loadInitial()
323324
}
324325

326+
DetailsAction.OnDismissDowngradeWarning -> {
327+
_state.update { it.copy(
328+
downgradeWarning = null
329+
) }
330+
}
331+
325332
DetailsAction.InstallPrimary -> {
326333
val primary = _state.value.primaryAsset
327334
val release = _state.value.selectedRelease
@@ -340,15 +347,13 @@ class DetailsViewModel(
340347
)
341348

342349
if (isDowngrade) {
343-
viewModelScope.launch {
344-
_events.send(
345-
DetailsEvent.ShowDowngradeWarning(
346-
packageName = installedApp.packageName,
347-
currentVersion = installedApp.installedVersion,
348-
targetVersion = release.tagName
349-
)
350+
_state.update { it.copy(
351+
downgradeWarning = DowngradeWarning(
352+
packageName = installedApp.packageName,
353+
currentVersion = installedApp.installedVersion,
354+
targetVersion = release.tagName
350355
)
351-
}
356+
) }
352357
return
353358
}
354359
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package zed.rainxch.details.presentation.model
2+
3+
data class DowngradeWarning(
4+
val packageName: String,
5+
val currentVersion: String,
6+
val targetVersion: String
7+
)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package zed.rainxch.details.presentation.model
2+
3+
sealed interface TranslationTarget {
4+
data object About : TranslationTarget
5+
data object WhatsNew : TranslationTarget
6+
}

0 commit comments

Comments
 (0)