mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-05 19:08:23 +00:00
Offer backup restore after relogin even when publishing is disabled
maybeOfferRestore gated on the BACKUP_APPLICATIONS pref, but updatePrefsForLogout wipes prefs_<npub> by design, so after a logout->login round trip the flag always read false and the restore prompt could never appear - the exact case restore exists for. Fetching is a read of a public self-authored event, so drop the publish-consent gate and rely on the local-apps check; publishing still requires the toggle.
This commit is contained in:
@@ -211,7 +211,12 @@ class AccountStateViewModel(npub: String?) : ViewModel() {
|
|||||||
|
|
||||||
fun maybeOfferRestore(account: Account) {
|
fun maybeOfferRestore(account: Account) {
|
||||||
if (BuildFlavorChecker.isOfflineFlavor()) return
|
if (BuildFlavorChecker.isOfflineFlavor()) return
|
||||||
if (!LocalPreferences.getBackupApplications(Amber.instance, account.npub)) return
|
|
||||||
|
// No BACKUP_APPLICATIONS gate here: that flag is publish consent for the
|
||||||
|
// daily worker and is deliberately wiped on logout, so it can never be
|
||||||
|
// true on a logout→login round trip — the main case restore exists for.
|
||||||
|
// Fetching is a read of a public, self-authored event; the dao check
|
||||||
|
// below skips accounts whose local apps are still present.
|
||||||
|
|
||||||
Amber.instance.applicationIOScope.launch {
|
Amber.instance.applicationIOScope.launch {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package com.greenart7c3.nostrsigner.ui
|
||||||
|
|
||||||
|
import com.greenart7c3.nostrsigner.Amber
|
||||||
|
import com.greenart7c3.nostrsigner.BuildFlavorChecker
|
||||||
|
import com.greenart7c3.nostrsigner.LocalPreferences
|
||||||
|
import com.greenart7c3.nostrsigner.database.ApplicationDao
|
||||||
|
import com.greenart7c3.nostrsigner.service.ApplicationBackup
|
||||||
|
import com.greenart7c3.nostrsigner.service.installAmberInstance
|
||||||
|
import com.greenart7c3.nostrsigner.service.newTestAccount
|
||||||
|
import io.mockk.coEvery
|
||||||
|
import io.mockk.coVerify
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.mockkObject
|
||||||
|
import io.mockk.unmockkObject
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class AccountStateViewModelRestoreTest {
|
||||||
|
// Unconfined so maybeOfferRestore's internal launch runs to completion on the
|
||||||
|
// calling thread; every ApplicationBackup call it makes is a mocked immediate.
|
||||||
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Unconfined)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
mockkObject(BuildFlavorChecker)
|
||||||
|
every { BuildFlavorChecker.isOfflineFlavor() } returns false
|
||||||
|
|
||||||
|
mockkObject(LocalPreferences)
|
||||||
|
every { LocalPreferences.currentAccount(any()) } returns null
|
||||||
|
every { LocalPreferences.allSavedAccounts(any()) } returns emptyList()
|
||||||
|
coEvery { LocalPreferences.warmAccountCache(any()) } returns Unit
|
||||||
|
every { LocalPreferences.loadFromEncryptedStorageSync(any(), any()) } returns null
|
||||||
|
// Post-logout state: updatePrefsForLogout wipes prefs_<npub>, so the
|
||||||
|
// publish-consent flag reads false on relogin.
|
||||||
|
every { LocalPreferences.getBackupApplications(any(), any()) } returns false
|
||||||
|
|
||||||
|
val dao = mockk<ApplicationDao>(relaxed = true)
|
||||||
|
coEvery { dao.getAll(any()) } returns emptyList()
|
||||||
|
val amber = mockk<Amber>(relaxed = true)
|
||||||
|
every { amber.applicationIOScope } returns scope
|
||||||
|
every { amber.dao(any()) } returns dao
|
||||||
|
installAmberInstance(amber)
|
||||||
|
|
||||||
|
mockkObject(ApplicationBackup)
|
||||||
|
coEvery { ApplicationBackup.resolveReadRelays(any()) } returns setOf(mockk())
|
||||||
|
coEvery { ApplicationBackup.fetchLatestBackupEvent(any(), any()) } returns null
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
unmockkObject(BuildFlavorChecker)
|
||||||
|
unmockkObject(LocalPreferences)
|
||||||
|
unmockkObject(ApplicationBackup)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `maybeOfferRestore reaches relay fetch even with backup publishing disabled`() {
|
||||||
|
val viewModel = AccountStateViewModel(null)
|
||||||
|
val account = newTestAccount(scope)
|
||||||
|
|
||||||
|
viewModel.maybeOfferRestore(account)
|
||||||
|
|
||||||
|
coVerify {
|
||||||
|
ApplicationBackup.resolveReadRelays(account)
|
||||||
|
ApplicationBackup.fetchLatestBackupEvent(account, any())
|
||||||
|
}
|
||||||
|
assertNull(viewModel.restorePrompt.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user