47e77d4ba508
fix: open populated phones directly at pairing (v2.7.13)
- time
- 2026-07-28 21:22 UTC · 2 months ago
- machine
- koh2
- agent
- gpt-5
- session
- normal mesh pairing scan
- parent
- 7c32509a6aa3
↓ peach-android-47e77d4b.tar.gzatlas at this save
files changed4 files
app/build.gradle+2 −2app/src/main/java/com/peachpasswords/ui/pairing/AdoptVaultScreen.kt+1 −19app/src/main/java/com/peachpasswords/ui/pairing/AdoptVaultViewModel.kt+6 −17app/src/test/java/com/peachpasswords/ui/pairing/AdoptVaultSafetyTest.kt+8 −0app/build.gradle+2 −2
@@ -16,8 +16,8 @@1616 applicationId "com.peachpasswords"1717 minSdk 261818 targetSdk 3519- versionCode 24013920- versionName "2.7.12"19+ versionCode 24014020+ versionName "2.7.13"2121 2222 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"2323 vectorDrawables {app/src/main/java/com/peachpasswords/ui/pairing/AdoptVaultScreen.kt+1 −19
@@ -73,7 +73,7 @@7373 verticalArrangement = Arrangement.Center,7474 ) {7575 Text(76- if (vm.joining) "Re-pair a device" else "I already have Peach",76+ if (vm.joining) "Pair a device" else "I already have Peach",7777 color = peachColors.T0,7878 fontFamily = PeachType.Display,7979 fontSize = 26.sp,@@ -96,24 +96,6 @@9696 }9797 9898 when (val current = state) {99- AdoptVaultUiState.Disclosure -> {100- Body(101- "This device already has a vault. Scanning a QR from a second browser, " +102- "tablet, or phone is allowed as long as it holds the same vault " +103- "(same recovery words).",104- )105- Spacer(Modifier.height(PeachSpacing.md))106- Body(107- "You'll see the same short code on both screens. The codes must match " +108- "before anything is shared — that's what proves the other device is " +109- "really the one you pointed the camera at, not a relay or middleman.",110- )111- Spacer(Modifier.height(PeachSpacing.lg))112- PillButton("Continue", LocalPeachAccent.current, filled = true) {113- vm.acceptDisclosure()114- }115- }116-11799 AdoptVaultUiState.Password -> {118100 Body(119101 "Choose the password this phone will use. It never leaves this device; " +app/src/main/java/com/peachpasswords/ui/pairing/AdoptVaultViewModel.kt+6 −17
@@ -42,12 +42,6 @@4242 4343 sealed interface AdoptVaultUiState {4444 data object Password : AdoptVaultUiState45- /**46- * Existing-vault mode only. Pairing is allowed only when the incoming root47- * key identifies this same vault; Peach refuses to combine populated48- * vaults because separately imported copies can otherwise nearly double.49- */50- data object Disclosure : AdoptVaultUiState5145 data object Pair : AdoptVaultUiState5246 data object Connecting : AdoptVaultUiState5347 /**@@ -83,7 +77,7 @@8377 val joining: Boolean = vault.hasVault()8478 8579 private val _state = MutableStateFlow<AdoptVaultUiState>(86- if (joining) AdoptVaultUiState.Disclosure else AdoptVaultUiState.Password,80+ initialAdoptVaultState(joining),8781 )8882 val state: StateFlow<AdoptVaultUiState> = _state.asStateFlow()8983 @@ -101,13 +95,6 @@10195 return true10296 }10397 104- /** The user has read what joining does to this device's recovery words. */105- fun acceptDisclosure() {106- if (_state.value is AdoptVaultUiState.Disclosure) {107- _state.value = AdoptVaultUiState.Pair108- }109- }110-11198 fun adopt(invitation: String) {11299 if (_state.value !is AdoptVaultUiState.Pair) return113100 val parsed = parsePairingInvitation(invitation)@@ -239,8 +226,7 @@239226 confirmation?.complete(false)240227 confirmation = null241228 clearPassword()242- _state.value =243- if (joining) AdoptVaultUiState.Disclosure else AdoptVaultUiState.Password229+ _state.value = initialAdoptVaultState(joining)244230 }245231 246232 private fun receiverDeps(): AdoptionReceiverDeps =@@ -365,6 +351,9 @@365351 }366352 }367353 354+internal fun initialAdoptVaultState(hasVault: Boolean): AdoptVaultUiState =355+ if (hasVault) AdoptVaultUiState.Pair else AdoptVaultUiState.Password356+368357 /**369358 * Pairing is not a merge tool. A populated destination may re-pair only when370359 * both sides already derive the same vault id. Different ids must stop before@@ -379,4 +368,4 @@379368 throw IllegalStateException("JOIN_POPULATED_VAULT_BLOCKED")380369 }381370 return localVaultId382-}\ No newline at end of file371+}app/src/test/java/com/peachpasswords/ui/pairing/AdoptVaultSafetyTest.kt+8 −0
@@ -5,6 +5,14 @@55 import org.junit.Test66 77 class AdoptVaultSafetyTest {8+ @Test fun populated_vault_starts_at_pairing_without_a_repair_disclosure() {9+ assertEquals(AdoptVaultUiState.Pair, initialAdoptVaultState(hasVault = true))10+ }11+12+ @Test fun empty_install_still_collects_a_local_password_first() {13+ assertEquals(AdoptVaultUiState.Password, initialAdoptVaultState(hasVault = false))14+ }15+816 @Test fun same_vault_identity_may_repair_without_mutation() {917 val id = "ab".repeat(32)1018