Skip to content

Bind settings persistence to lifecycle#228

Merged
Goooler merged 2 commits into
trunkfrom
do-on-dispose
May 12, 2026
Merged

Bind settings persistence to lifecycle#228
Goooler merged 2 commits into
trunkfrom
do-on-dispose

Conversation

@Goooler
Copy link
Copy Markdown
Owner

@Goooler Goooler commented May 12, 2026

Replace dispose-triggered Global scope writes with lifecycle observer callbacks and ViewModel-scoped persistence so settings are saved from onStop without escaping the screen lifecycle.

Refs #226.

Goooler and others added 2 commits May 12, 2026 23:04
Replace dispose-triggered Global scope writes with lifecycle observer callbacks and ViewModel-scoped persistence so settings are saved from onStop without escaping the screen lifecycle.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Intended to use non-viewModel scope as we need the action to be called on disposed.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to ensure settings persistence happens from lifecycle callbacks (e.g., onStop) rather than Compose onDispose, so persistence is better aligned with screen lifecycle and avoids late/disposed-triggered writes.

Changes:

  • Convert settings ViewModels to implement DefaultLifecycleObserver and persist/clear on onStop.
  • Update Settings Compose screens to register/unregister their ViewModel as a lifecycle observer via LocalLifecycleOwner.
  • Adjust “reset” behavior to rely on the onStop persistence path rather than immediately clearing in a Global coroutine.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
ui/settings/src/main/kotlin/com/github/kr328/clash/settings/vm/OverrideSettingsViewModel.kt Switch persistence trigger to DefaultLifecycleObserver.onStop (currently still uses Global.launch).
ui/settings/src/main/kotlin/com/github/kr328/clash/settings/vm/MetaFeatureSettingsViewModel.kt Same onStop-based persistence/clear behavior for meta feature overrides (currently still uses Global.launch).
ui/settings/src/main/kotlin/com/github/kr328/clash/settings/vm/AccessControlViewModel.kt Move selection persistence + optional service restart to onStop (currently still uses Global.launch).
ui/settings/src/main/kotlin/com/github/kr328/clash/settings/ui/OverrideSettingsScreen.kt Register/unregister the ViewModel as a lifecycle observer using LocalLifecycleOwner.
ui/settings/src/main/kotlin/com/github/kr328/clash/settings/ui/MetaFeatureSettingsScreen.kt Register/unregister the ViewModel as a lifecycle observer using LocalLifecycleOwner.
ui/settings/src/main/kotlin/com/github/kr328/clash/settings/ui/AccessControlScreen.kt Register/unregister the ViewModel as a lifecycle observer using LocalLifecycleOwner.
Comments suppressed due to low confidence (1)

ui/settings/src/main/kotlin/com/github/kr328/clash/settings/vm/AccessControlViewModel.kt:70

  • onStop() performs persistence + service restart logic inside Global.launch, which is not tied to the ViewModel/screen lifecycle and may continue running after the screen is gone. Consider moving this work to viewModelScope.launch(Dispatchers.IO) (and update/remove the stale comment about needing a non-ViewModel scope for disposal) so it matches the lifecycle-bound persistence approach described in the PR.
  override fun onStop(owner: LifecycleOwner) {
    // Intended to use non-viewModel scope as we need the action to be called on disposed.
    Global.launch {
      val selected = uiState.value.selected
      val persistedSelection = serviceStore.accessControlPackages

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +33 to +37
override fun onStop(owner: LifecycleOwner) {
// Intended to use non-viewModel scope as we need the action to be called on disposed.
Global.launch {
if (skipPersist) return@launch
withClash { patchOverride(Clash.OverrideSlot.Persist, configuration.value) }
withClash {
if (skipPersist) clearOverride(Clash.OverrideSlot.Persist)
Comment on lines +42 to +46
override fun onStop(owner: LifecycleOwner) {
// Intended to use non-viewModel scope as we need the action to be called on disposed.
Global.launch {
if (skipPersist) return@launch
withClash { patchOverride(Clash.OverrideSlot.Persist, configuration.value) }
withClash {
if (skipPersist) clearOverride(Clash.OverrideSlot.Persist)
@Goooler Goooler merged commit 9dc3ab2 into trunk May 12, 2026
8 checks passed
@Goooler Goooler deleted the do-on-dispose branch May 12, 2026 15:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants