fix(settings): isolate instant-zap defaults per account (port wisp #576)

This commit is contained in:
The Daniel
2026-06-12 13:16:49 -04:00
parent 7fe8568292
commit b33c55c31c
2 changed files with 53 additions and 9 deletions
@@ -60,31 +60,71 @@ class InterfacePreferences(context: Context) {
// ── Instant (a.k.a. quick) zaps ─────────────────────────────────────────
// Hold-to-zap on the post-card fires immediately at the configured
// amount when enabled; tap still opens the composer.
//
// Keys are scoped per-account via activePubkey (companion object) so
// switching accounts never inherits the previous account's values.
// Call reload(pubkey) on every account switch to update the scope.
fun isQuickZapEnabled(): Boolean = prefs.getBoolean("quick_zap_enabled", false)
fun setQuickZapEnabled(enabled: Boolean) = prefs.edit().putBoolean("quick_zap_enabled", enabled).apply()
private fun quickZapKey(base: String): String =
activePubkey?.let { "${base}_$it" } ?: base
fun getQuickZapAmountSats(): Long = prefs.getLong("quick_zap_amount_sats", 100L).coerceIn(1L, QUICK_ZAP_MAX_SATS)
fun isQuickZapEnabled(): Boolean = prefs.getBoolean(quickZapKey("quick_zap_enabled"), false)
fun setQuickZapEnabled(enabled: Boolean) =
prefs.edit().putBoolean(quickZapKey("quick_zap_enabled"), enabled).apply()
fun getQuickZapAmountSats(): Long =
prefs.getLong(quickZapKey("quick_zap_amount_sats"), 21L).coerceIn(1L, QUICK_ZAP_MAX_SATS)
fun setQuickZapAmountSats(amount: Long) {
// Hard clamp at 10K sats so an instant zap never bypasses the soft
// confirmation dialog in the ZapSheet (which fires at >10K).
val clamped = amount.coerceIn(1L, QUICK_ZAP_MAX_SATS)
prefs.edit().putLong("quick_zap_amount_sats", clamped).apply()
prefs.edit().putLong(quickZapKey("quick_zap_amount_sats"), clamped).apply()
}
fun getQuickZapAmountFiat(): Double =
prefs.getString("quick_zap_amount_fiat", "0.10")?.toDoubleOrNull()?.coerceAtLeast(0.0) ?: 0.10
prefs.getString(quickZapKey("quick_zap_amount_fiat"), "0.10")?.toDoubleOrNull()?.coerceAtLeast(0.0) ?: 0.10
fun setQuickZapAmountFiat(amount: Double) {
// Fiat clamp happens at fire time against the cached exchange rate
// (callers in ZapSheet do `min(localFiat, sats→fiat(10_000))`).
val clamped = amount.coerceAtLeast(0.0)
prefs.edit().putString("quick_zap_amount_fiat", clamped.toString()).apply()
prefs.edit().putString(quickZapKey("quick_zap_amount_fiat"), clamped.toString()).apply()
}
fun getQuickZapMessage(): String = prefs.getString("quick_zap_message", "") ?: ""
fun setQuickZapMessage(message: String) = prefs.edit().putString("quick_zap_message", message).apply()
fun getQuickZapMessage(): String = prefs.getString(quickZapKey("quick_zap_message"), "") ?: ""
fun setQuickZapMessage(message: String) =
prefs.edit().putString(quickZapKey("quick_zap_message"), message).apply()
/**
* Update the active account scope for instant-zap keys. Call on every
* account switch AND at initial app launch. On the very first call with
* a non-null pubkey (activePubkey was null), migrates any values that
* were stored under the old unscoped keys so existing settings survive
* the upgrade to per-account storage.
*/
fun reload(pubkey: String?) {
val wasNull = activePubkey == null
activePubkey = pubkey
if (wasNull && pubkey != null) migrateGlobalIfNeeded(pubkey)
}
private fun migrateGlobalIfNeeded(pubkey: String) {
val migKey = "quick_zap_migrated_v1_$pubkey"
if (prefs.getBoolean(migKey, false)) return
val edit = prefs.edit().putBoolean(migKey, true)
if (!prefs.contains("quick_zap_amount_sats_$pubkey") && prefs.contains("quick_zap_amount_sats"))
edit.putLong("quick_zap_amount_sats_$pubkey", prefs.getLong("quick_zap_amount_sats", 21L))
if (!prefs.contains("quick_zap_amount_fiat_$pubkey") && prefs.contains("quick_zap_amount_fiat"))
prefs.getString("quick_zap_amount_fiat", null)?.let { edit.putString("quick_zap_amount_fiat_$pubkey", it) }
if (!prefs.contains("quick_zap_enabled_$pubkey") && prefs.contains("quick_zap_enabled"))
edit.putBoolean("quick_zap_enabled_$pubkey", prefs.getBoolean("quick_zap_enabled", false))
if (!prefs.contains("quick_zap_message_$pubkey") && prefs.contains("quick_zap_message"))
prefs.getString("quick_zap_message", null)?.let { edit.putString("quick_zap_message_$pubkey", it) }
edit.apply()
}
companion object {
/** Shared across all InterfacePreferences instances — updated by reload(). */
@Volatile var activePubkey: String? = null
val postUndoTimerOptions = listOf(5, 10, 15, 20, 30)
const val QUICK_ZAP_MAX_SATS = 10_000L
}
@@ -431,7 +431,10 @@ class FeedViewModel(app: Application) : AndroidViewModel(app) {
fun markLoadingComplete() = feedSub.markLoadingComplete()
// -- Startup delegates --
fun initRelays() = startup.initRelays()
fun initRelays() {
interfacePrefs.reload(getUserPubkey())
startup.initRelays()
}
fun setTorEnabled(enabled: Boolean) = startup.setTorEnabled(enabled)
fun resetForAccountSwitch() {
startup.resetForAccountSwitch()
@@ -440,6 +443,7 @@ class FeedViewModel(app: Application) : AndroidViewModel(app) {
}
fun reloadForNewAccount() {
safetyPrefs.reload(getUserPubkey())
interfacePrefs.reload(getUserPubkey())
startup.reloadForNewAccount()
groupRepo.reload(getUserPubkey())
}