diff --git a/app/src/main/java/to/bitkit/services/LdkNodeEventBus.kt b/app/src/main/java/to/bitkit/services/LdkNodeEventBus.kt index 3b51d03b2..eb6900848 100644 --- a/app/src/main/java/to/bitkit/services/LdkNodeEventBus.kt +++ b/app/src/main/java/to/bitkit/services/LdkNodeEventBus.kt @@ -8,7 +8,7 @@ import javax.inject.Singleton @Singleton class LdkNodeEventBus @Inject constructor() { - private val _events = MutableSharedFlow(replay = 0, extraBufferCapacity = 1) + private val _events = MutableSharedFlow(extraBufferCapacity = 1) val events = _events.asSharedFlow() suspend fun emit(event: Event) { diff --git a/app/src/main/java/to/bitkit/ui/ContentView.kt b/app/src/main/java/to/bitkit/ui/ContentView.kt index 81ec542c7..b21491b49 100644 --- a/app/src/main/java/to/bitkit/ui/ContentView.kt +++ b/app/src/main/java/to/bitkit/ui/ContentView.kt @@ -159,6 +159,7 @@ fun ContentView( appViewModel.mainScreenEffect.collect { when (it) { is MainScreenEffect.NavigateActivityDetail -> navController.navigate(Routes.ActivityItem(it.activityId)) + else -> Unit } } } diff --git a/app/src/main/java/to/bitkit/ui/MainActivity.kt b/app/src/main/java/to/bitkit/ui/MainActivity.kt index 343ce27f4..1d0e0fe3e 100644 --- a/app/src/main/java/to/bitkit/ui/MainActivity.kt +++ b/app/src/main/java/to/bitkit/ui/MainActivity.kt @@ -6,6 +6,7 @@ import androidx.activity.viewModels import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen @@ -40,6 +41,7 @@ import to.bitkit.viewmodels.ActivityListViewModel import to.bitkit.viewmodels.AppViewModel import to.bitkit.viewmodels.BlocktankViewModel import to.bitkit.viewmodels.CurrencyViewModel +import to.bitkit.viewmodels.MainScreenEffect import to.bitkit.viewmodels.TransferViewModel import to.bitkit.viewmodels.WalletViewModel @@ -210,6 +212,15 @@ class MainActivity : FragmentActivity() { onResetClick = { walletViewModel.wipeStorage() }, ) } + + LaunchedEffect(appViewModel) { + appViewModel.mainScreenEffect.collect { + when (it) { + MainScreenEffect.WipeStorage -> walletViewModel.wipeStorage() + else -> Unit + } + } + } } ToastOverlay( diff --git a/app/src/main/java/to/bitkit/ui/shared/toast/ToastEventBus.kt b/app/src/main/java/to/bitkit/ui/shared/toast/ToastEventBus.kt index c6dc99b49..5613a4265 100644 --- a/app/src/main/java/to/bitkit/ui/shared/toast/ToastEventBus.kt +++ b/app/src/main/java/to/bitkit/ui/shared/toast/ToastEventBus.kt @@ -5,7 +5,7 @@ import kotlinx.coroutines.flow.asSharedFlow import to.bitkit.models.Toast object ToastEventBus { - private val _events = MutableSharedFlow(replay = 0, extraBufferCapacity = 1) + private val _events = MutableSharedFlow(extraBufferCapacity = 1) val events = _events.asSharedFlow() suspend fun send( diff --git a/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt b/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt index e83da17ce..b70c5a589 100644 --- a/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt +++ b/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow @@ -22,8 +23,10 @@ import kotlinx.coroutines.launch import org.lightningdevkit.ldknode.Event import org.lightningdevkit.ldknode.PaymentId import org.lightningdevkit.ldknode.Txid +import to.bitkit.R import to.bitkit.data.SettingsStore import to.bitkit.data.keychain.Keychain +import to.bitkit.di.BgDispatcher import to.bitkit.env.Env import to.bitkit.ext.WatchResult import to.bitkit.ext.removeSpaces @@ -44,6 +47,7 @@ import to.bitkit.ui.components.BottomSheetType import to.bitkit.ui.screens.wallets.send.SendRoute import to.bitkit.ui.shared.toast.ToastEventBus import to.bitkit.utils.Logger +import to.bitkit.utils.ResourceProvider import uniffi.bitkitcore.Activity import uniffi.bitkitcore.ActivityFilter import uniffi.bitkitcore.LightningInvoice @@ -54,12 +58,14 @@ import javax.inject.Inject @HiltViewModel class AppViewModel @Inject constructor( + @BgDispatcher private val bgDispatcher: CoroutineDispatcher, private val keychain: Keychain, private val scannerService: ScannerService, private val lightningService: LightningRepo, private val coreService: CoreService, private val ldkNodeEventBus: LdkNodeEventBus, private val settingsStore: SettingsStore, + private val resourceProvider: ResourceProvider, ) : ViewModel() { var splashVisible by mutableStateOf(true) private set @@ -70,11 +76,11 @@ class AppViewModel @Inject constructor( private val _sendUiState = MutableStateFlow(SendUiState()) val sendUiState = _sendUiState.asStateFlow() - private val _sendEffect = MutableSharedFlow(replay = 0, extraBufferCapacity = 1) + private val _sendEffect = MutableSharedFlow(extraBufferCapacity = 1) val sendEffect = _sendEffect.asSharedFlow() private fun setSendEffect(effect: SendEffect) = viewModelScope.launch { _sendEffect.emit(effect) } - private val _mainScreenEffect = MutableSharedFlow(replay = 0, extraBufferCapacity = 1) + private val _mainScreenEffect = MutableSharedFlow(extraBufferCapacity = 1) val mainScreenEffect = _mainScreenEffect.asSharedFlow() private fun mainScreenEffect(effect: MainScreenEffect) = viewModelScope.launch { _mainScreenEffect.emit(effect) } @@ -820,16 +826,18 @@ class AppViewModel @Inject constructor( return true } - viewModelScope.launch { + viewModelScope.launch(bgDispatcher) { val newAttempts = pinAttemptsRemaining.value - 1 keychain.upsertString(Keychain.Key.PIN_ATTEMPTS_REMAINING.name, newAttempts.toString()) if (newAttempts <= 0) { - // TODO: wipeStorage() & return to onboarding toast( - type = Toast.ToastType.WARNING, - title = "TODO: Wipe App data", + type = Toast.ToastType.SUCCESS, + title = resourceProvider.getString(R.string.security__wiped_title), + description = resourceProvider.getString(R.string.security__wiped_message), ) + delay(250) // small delay for UI feedback + mainScreenEffect(MainScreenEffect.WipeStorage) } } return false @@ -892,6 +900,7 @@ sealed class SendEffect { sealed class MainScreenEffect { data class NavigateActivityDetail(val activityId: String) : MainScreenEffect() + data object WipeStorage : MainScreenEffect() } sealed class SendEvent { diff --git a/app/src/main/java/to/bitkit/viewmodels/ExternalNodeViewModel.kt b/app/src/main/java/to/bitkit/viewmodels/ExternalNodeViewModel.kt index 592d20279..5e1c1afe6 100644 --- a/app/src/main/java/to/bitkit/viewmodels/ExternalNodeViewModel.kt +++ b/app/src/main/java/to/bitkit/viewmodels/ExternalNodeViewModel.kt @@ -33,7 +33,7 @@ class ExternalNodeViewModel @Inject constructor( private val _uiState = MutableStateFlow(UiState()) val uiState = _uiState.asStateFlow() - private val _effects = MutableSharedFlow(replay = 0, extraBufferCapacity = 1) + private val _effects = MutableSharedFlow(extraBufferCapacity = 1) val effects = _effects.asSharedFlow() private fun setEffect(effect: SideEffect) = viewModelScope.launch { _effects.emit(effect) }