mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-2593 Auth | Tech | Debug goroutines stack (#1301)
This commit is contained in:
parent
8d9beec534
commit
d6d871fe57
8 changed files with 215 additions and 49 deletions
|
@ -1,10 +1,13 @@
|
|||
package com.anytypeio.anytype.di.feature.onboarding
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.di.common.ComponentDependencies
|
||||
import com.anytypeio.anytype.presentation.onboarding.OnboardingViewModel
|
||||
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
|
||||
import com.anytypeio.anytype.providers.DefaultUriFileProvider
|
||||
import com.anytypeio.anytype.ui.onboarding.OnboardingFragment
|
||||
import dagger.Binds
|
||||
import dagger.Component
|
||||
|
@ -34,9 +37,16 @@ object OnboardingModule {
|
|||
@Binds
|
||||
@AuthScreenScope
|
||||
fun bindViewModelFactory(factory: OnboardingViewModel.Factory): ViewModelProvider.Factory
|
||||
|
||||
@Binds
|
||||
@PerScreen
|
||||
fun bindUriFileProvider(
|
||||
defaultProvider: DefaultUriFileProvider
|
||||
): UriFileProvider
|
||||
}
|
||||
}
|
||||
|
||||
interface OnboardingDependencies : ComponentDependencies {
|
||||
fun analytics(): Analytics
|
||||
fun context(): Context
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.anytypeio.anytype.di.feature.onboarding.login
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.anytypeio.anytype.CrashReporter
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
|
@ -7,7 +8,10 @@ import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
|||
import com.anytypeio.anytype.di.common.ComponentDependencies
|
||||
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.ConfigStorage
|
||||
import com.anytypeio.anytype.domain.debugging.DebugGoroutines
|
||||
import com.anytypeio.anytype.domain.device.PathProvider
|
||||
import com.anytypeio.anytype.domain.misc.LocaleProvider
|
||||
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
|
||||
|
@ -16,9 +20,12 @@ import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager
|
|||
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
|
||||
import com.anytypeio.anytype.domain.spaces.SpaceDeletedStatusWatcher
|
||||
import com.anytypeio.anytype.presentation.onboarding.login.OnboardingMnemonicLoginViewModel
|
||||
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
|
||||
import com.anytypeio.anytype.providers.DefaultUriFileProvider
|
||||
import dagger.Binds
|
||||
import dagger.Component
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
||||
@Component(
|
||||
dependencies = [OnboardingMnemonicLoginDependencies::class],
|
||||
|
@ -41,8 +48,29 @@ interface OnboardingMnemonicLoginComponent {
|
|||
|
||||
@Module
|
||||
object OnboardingMnemonicLoginModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun bindDebugGoroutines(
|
||||
repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers,
|
||||
context: Context
|
||||
): DebugGoroutines = DebugGoroutines(
|
||||
repo = repo,
|
||||
dispatchers = dispatchers,
|
||||
cacheDir = context.cacheDir.path
|
||||
)
|
||||
|
||||
@Module
|
||||
interface Declarations {
|
||||
|
||||
@Binds
|
||||
@PerScreen
|
||||
fun bindUriFileProvider(
|
||||
defaultProvider: DefaultUriFileProvider
|
||||
): UriFileProvider
|
||||
|
||||
@Binds
|
||||
@PerScreen
|
||||
fun bindViewModelFactory(
|
||||
|
@ -64,4 +92,7 @@ interface OnboardingMnemonicLoginDependencies : ComponentDependencies {
|
|||
fun localeProvider(): LocaleProvider
|
||||
fun awaitAccountStartManager(): AwaitAccountStartManager
|
||||
fun userPermissionProvider() : UserPermissionProvider
|
||||
fun provideAppCoroutineDispatchers(): AppCoroutineDispatchers
|
||||
fun provideBlockRepository(): BlockRepository
|
||||
fun provideContext(): Context
|
||||
}
|
|
@ -71,6 +71,7 @@ import com.anytypeio.anytype.core_ui.MNEMONIC_WORD_COUNT
|
|||
import com.anytypeio.anytype.core_ui.MnemonicPhrasePaletteColors
|
||||
import com.anytypeio.anytype.core_ui.views.BaseAlertDialog
|
||||
import com.anytypeio.anytype.core_utils.ext.argOrNull
|
||||
import com.anytypeio.anytype.core_utils.ext.shareFirstFileFromPath
|
||||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.insets.RootViewDeferringInsetsCallback
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
|
@ -80,6 +81,7 @@ import com.anytypeio.anytype.presentation.onboarding.OnboardingStartViewModel.Si
|
|||
import com.anytypeio.anytype.presentation.onboarding.OnboardingViewModel
|
||||
import com.anytypeio.anytype.presentation.onboarding.login.OnboardingMnemonicLoginViewModel
|
||||
import com.anytypeio.anytype.presentation.onboarding.signup.OnboardingSetProfileNameViewModel
|
||||
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
|
||||
import com.anytypeio.anytype.ui.home.HomeScreenFragment
|
||||
import com.anytypeio.anytype.ui.onboarding.screens.AuthScreenWrapper
|
||||
import com.anytypeio.anytype.ui.onboarding.screens.signin.RecoveryScreenWrapper
|
||||
|
@ -396,12 +398,13 @@ class OnboardingFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
vm.navigation.collect { navigation ->
|
||||
when (navigation) {
|
||||
OnboardingMnemonicLoginViewModel.Navigation.Exit -> {
|
||||
vm.command.collect { command ->
|
||||
Timber.d("Command: $command")
|
||||
when (command) {
|
||||
OnboardingMnemonicLoginViewModel.Command.Exit -> {
|
||||
navController.popBackStack()
|
||||
}
|
||||
OnboardingMnemonicLoginViewModel.Navigation.NavigateToHomeScreen -> {
|
||||
OnboardingMnemonicLoginViewModel.Command.NavigateToHomeScreen -> {
|
||||
runCatching {
|
||||
findNavController().navigate(
|
||||
R.id.action_openHome,
|
||||
|
@ -411,7 +414,7 @@ class OnboardingFragment : Fragment() {
|
|||
Timber.e(it, "Error while trying to open home screen from onboarding")
|
||||
}
|
||||
}
|
||||
OnboardingMnemonicLoginViewModel.Navigation.NavigateToMigrationErrorScreen -> {
|
||||
OnboardingMnemonicLoginViewModel.Command.NavigateToMigrationErrorScreen -> {
|
||||
runCatching {
|
||||
findNavController().navigate(
|
||||
R.id.migrationNeededScreen,
|
||||
|
@ -426,6 +429,18 @@ class OnboardingFragment : Fragment() {
|
|||
Timber.e(it, "Error while trying to open migration screen from onboarding")
|
||||
}
|
||||
}
|
||||
is OnboardingMnemonicLoginViewModel.Command.ShareDebugGoroutines -> {
|
||||
try {
|
||||
this@OnboardingFragment.shareFirstFileFromPath(command.path, command.uriFileProvider)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error while stack goroutines debug").also {
|
||||
toast("Error while stack goroutines debug. Please try again later.")
|
||||
}
|
||||
}
|
||||
}
|
||||
is OnboardingMnemonicLoginViewModel.Command.ShowToast -> {
|
||||
toast(command.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package com.anytypeio.anytype.ui.onboarding.screens.signin
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
|
@ -21,6 +24,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
|
@ -39,6 +43,7 @@ import com.anytypeio.anytype.core_ui.ColorButtonRegular
|
|||
import com.anytypeio.anytype.core_ui.MnemonicPhrasePaletteColors
|
||||
import com.anytypeio.anytype.core_ui.OnBoardingTextPrimaryColor
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonSize
|
||||
import com.anytypeio.anytype.core_ui.views.ConditionLogin
|
||||
import com.anytypeio.anytype.core_ui.views.OnBoardingButtonPrimary
|
||||
|
@ -48,6 +53,7 @@ import com.anytypeio.anytype.core_utils.ext.toast
|
|||
import com.anytypeio.anytype.presentation.onboarding.login.OnboardingMnemonicLoginViewModel
|
||||
import com.anytypeio.anytype.presentation.onboarding.login.OnboardingMnemonicLoginViewModel.SetupState
|
||||
import com.anytypeio.anytype.ui.onboarding.OnboardingMnemonicInput
|
||||
import timber.log.Timber
|
||||
|
||||
@Composable
|
||||
fun RecoveryScreenWrapper(
|
||||
|
@ -60,7 +66,8 @@ fun RecoveryScreenWrapper(
|
|||
onNextClicked = vm::onLoginClicked,
|
||||
onActionDoneClicked = vm::onActionDone,
|
||||
onScanQrClicked = onScanQrClick,
|
||||
isLoading = vm.state.collectAsState().value is SetupState.InProgress
|
||||
isLoading = vm.state.collectAsState().value is SetupState.InProgress,
|
||||
onEnterMyVaultClicked = vm::onEnterMyVaultClicked
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -70,32 +77,42 @@ fun RecoveryScreen(
|
|||
onNextClicked: (Mnemonic) -> Unit,
|
||||
onActionDoneClicked: (Mnemonic) -> Unit,
|
||||
onScanQrClicked: () -> Unit,
|
||||
isLoading: Boolean
|
||||
isLoading: Boolean,
|
||||
onEnterMyVaultClicked: () -> Unit
|
||||
) {
|
||||
val focus = LocalFocusManager.current
|
||||
val context = LocalContext.current
|
||||
val text = remember { mutableStateOf("") }
|
||||
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.padding(top = 12.dp, start = 9.dp)
|
||||
.noRippleClickable {
|
||||
focus.clearFocus()
|
||||
onBackClicked()
|
||||
},
|
||||
painter = painterResource(id = R.drawable.ic_back_onboarding_32),
|
||||
contentDescription = "Back button"
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.noRippleClickable{ onEnterMyVaultClicked() }
|
||||
.align(Alignment.TopCenter)
|
||||
.padding(top = 21.dp)
|
||||
.padding(top = 17.dp, start = 18.dp, end = 18.dp)
|
||||
,
|
||||
text = stringResource(id = R.string.onboarding_enter_my_vault),
|
||||
style = TitleLogin.copy(
|
||||
color = OnBoardingTextPrimaryColor
|
||||
color = colorResource(id = R.color.text_white)
|
||||
)
|
||||
)
|
||||
|
||||
val text = remember {
|
||||
mutableStateOf("")
|
||||
}
|
||||
|
||||
val focus = LocalFocusManager.current
|
||||
val context = LocalContext.current
|
||||
|
||||
val emptyRecoveryPhraseError = stringResource(R.string.onboarding_your_key_can_t_be_empty)
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(top = 71.dp),
|
||||
content = {
|
||||
item {
|
||||
OnboardingMnemonicInput(
|
||||
|
@ -103,7 +120,6 @@ fun RecoveryScreen(
|
|||
.padding(
|
||||
start = 18.dp,
|
||||
end = 18.dp,
|
||||
top = 71.dp,
|
||||
bottom = 18.dp
|
||||
)
|
||||
.height(165.dp)
|
||||
|
@ -182,17 +198,6 @@ fun RecoveryScreen(
|
|||
}
|
||||
}
|
||||
)
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopStart)
|
||||
.padding(top = 16.dp, start = 9.dp)
|
||||
.noRippleClickable {
|
||||
focus.clearFocus()
|
||||
onBackClicked()
|
||||
},
|
||||
painter = painterResource(id = R.drawable.ic_back_onboarding_32),
|
||||
contentDescription = "Back button"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,7 +238,8 @@ object MnemonicPhraseFormatter : VisualTransformation {
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Light Mode")
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO, name = "Dark Mode")
|
||||
@Composable
|
||||
fun RecoveryScreenPreview() {
|
||||
RecoveryScreen(
|
||||
|
@ -241,11 +247,13 @@ fun RecoveryScreenPreview() {
|
|||
onNextClicked = {},
|
||||
onActionDoneClicked = {},
|
||||
onScanQrClicked = {},
|
||||
isLoading = false
|
||||
isLoading = false,
|
||||
onEnterMyVaultClicked = {}
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Light Mode")
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO, name = "Dark Mode")
|
||||
@Composable
|
||||
fun RecoveryScreenLoadingPreview() {
|
||||
RecoveryScreen(
|
||||
|
@ -253,6 +261,7 @@ fun RecoveryScreenLoadingPreview() {
|
|||
onNextClicked = {},
|
||||
onActionDoneClicked = {},
|
||||
onScanQrClicked = {},
|
||||
isLoading = true
|
||||
isLoading = true,
|
||||
onEnterMyVaultClicked = {}
|
||||
)
|
||||
}
|
|
@ -46,8 +46,10 @@ import com.anytypeio.anytype.core_utils.const.FileConstants.REQUEST_MEDIA_CODE
|
|||
import com.anytypeio.anytype.core_utils.const.MimeTypes.MIME_EXTRA_IMAGE_VIDEO
|
||||
import com.anytypeio.anytype.core_utils.const.MimeTypes.MIME_EXTRA_YAML
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
|
||||
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import timber.log.Timber
|
||||
|
@ -370,6 +372,27 @@ fun NavController.safeNavigate(
|
|||
}
|
||||
}
|
||||
|
||||
fun Fragment.shareFirstFileFromPath(path: String, uriFileProvider: UriFileProvider) {
|
||||
try {
|
||||
val dirPath = File(path)
|
||||
if (dirPath.exists() && dirPath.isDirectory) {
|
||||
val files = dirPath.listFiles()
|
||||
val firstFile = files?.firstOrNull { it != null && it.exists() && it.isFile }
|
||||
if (firstFile != null) {
|
||||
val uri = uriFileProvider.getUriForFile(firstFile)
|
||||
shareFile(uri)
|
||||
} else {
|
||||
toast("No valid files to share in the directory.")
|
||||
}
|
||||
} else {
|
||||
toast("Directory does not exist or is not a directory.")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error while sharing file")
|
||||
toast("Could not share file: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
fun Fragment.shareFile(uri: Uri) {
|
||||
try {
|
||||
val shareIntent: Intent = Intent().apply {
|
||||
|
|
|
@ -3,16 +3,39 @@ package com.anytypeio.anytype.domain.debugging
|
|||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.ResultInteractor
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
class DebugGoroutines @Inject constructor(
|
||||
private val cacheDir: String,
|
||||
private val repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
) : ResultInteractor<DebugGoroutines.Params, Unit>(dispatchers.io) {
|
||||
) : ResultInteractor<DebugGoroutines.Params, String>(dispatchers.io) {
|
||||
|
||||
override suspend fun doWork(params: Params) {
|
||||
repo.debugStackGoroutines(params.path)
|
||||
override suspend fun doWork(params: Params): String {
|
||||
val path: String
|
||||
val resultFilePath: String
|
||||
|
||||
if (params.path == null) {
|
||||
// Construct the path using the current time to ensure uniqueness
|
||||
path = "${cacheDir}/debug/goroutines/${System.currentTimeMillis()}/"
|
||||
// Middleware put the log in a subdirectory called logs
|
||||
resultFilePath = "$path/logs/"
|
||||
|
||||
// Create the directories if they do not exist
|
||||
File(path).apply { mkdirs() }
|
||||
} else {
|
||||
path = params.path
|
||||
resultFilePath = path
|
||||
}
|
||||
|
||||
// Perform the debug operation
|
||||
repo.debugStackGoroutines(path)
|
||||
|
||||
// Return the result file path
|
||||
return resultFilePath
|
||||
}
|
||||
|
||||
data class Params(val path: String)
|
||||
// Data class for the parameters, with a default value of null for the path
|
||||
data class Params(val path: String? = null)
|
||||
}
|
|
@ -616,7 +616,7 @@
|
|||
<string name="sign_up">Sign up</string>
|
||||
<string name="type_your_recovery_phrase">or type your Key</string>
|
||||
<string name="login_with_recovery_phrase">Login with your Key</string>
|
||||
<string name="or_scan_qr_code">Scan QR code</string>
|
||||
<string name="or_scan_qr_code">Scan Qr code</string>
|
||||
<string name="choose_pin_code">Choose pin code</string>
|
||||
<string name="congratulations">Congratulations!</string>
|
||||
<string name="time_to_update_title">It\'s time to update</string>
|
||||
|
@ -1102,7 +1102,7 @@
|
|||
<string name="onboarding_soul_creation_description">Only seen by people you share something with. There is no central registry of these names.</string>
|
||||
<string name="onboarding_soul_creation_placeholder">Anytype Identity</string>
|
||||
<string name="onboarding_soul_creation">Creating your Identity…</string>
|
||||
<string name="onboarding_type_your_key">Type your Key</string>
|
||||
<string name="onboarding_type_your_key">Type your recovery phrase</string>
|
||||
<string name="onboarding_login_or">OR</string>
|
||||
<string name="onboarding_entering_void_title">Entering the Void</string>
|
||||
<string name="onboarding_your_key_can_t_be_empty">Your Key can\'t be empty</string>
|
||||
|
|
|
@ -18,7 +18,9 @@ import com.anytypeio.anytype.domain.auth.interactor.RecoverWallet
|
|||
import com.anytypeio.anytype.domain.auth.interactor.SaveMnemonic
|
||||
import com.anytypeio.anytype.domain.auth.interactor.SelectAccount
|
||||
import com.anytypeio.anytype.domain.auth.interactor.StartLoadingAccounts
|
||||
import com.anytypeio.anytype.domain.base.fold
|
||||
import com.anytypeio.anytype.domain.config.ConfigStorage
|
||||
import com.anytypeio.anytype.domain.debugging.DebugGoroutines
|
||||
import com.anytypeio.anytype.domain.device.PathProvider
|
||||
import com.anytypeio.anytype.domain.misc.LocaleProvider
|
||||
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
|
||||
|
@ -28,6 +30,7 @@ import com.anytypeio.anytype.domain.spaces.SpaceDeletedStatusWatcher
|
|||
import com.anytypeio.anytype.presentation.extension.proceedWithAccountEvent
|
||||
import com.anytypeio.anytype.presentation.extension.sendAnalyticsOnboardingLoginEvent
|
||||
import com.anytypeio.anytype.presentation.splash.SplashViewModel
|
||||
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
@ -51,23 +54,34 @@ class OnboardingMnemonicLoginViewModel @Inject constructor(
|
|||
private val crashReporter: CrashReporter,
|
||||
private val configStorage: ConfigStorage,
|
||||
private val localeProvider: LocaleProvider,
|
||||
private val userPermissionProvider: UserPermissionProvider
|
||||
private val userPermissionProvider: UserPermissionProvider,
|
||||
private val debugGoroutines: DebugGoroutines,
|
||||
private val uriFileProvider: UriFileProvider
|
||||
) : ViewModel() {
|
||||
|
||||
private val jobs = mutableListOf<Job>()
|
||||
private var goroutinesJob : Job? = null
|
||||
|
||||
val sideEffects = MutableSharedFlow<SideEffect>()
|
||||
val state = MutableStateFlow<SetupState>(SetupState.Idle)
|
||||
|
||||
val navigation = MutableSharedFlow<Navigation>()
|
||||
val command = MutableSharedFlow<Command>(replay = 0)
|
||||
|
||||
val error by lazy { MutableStateFlow(NO_ERROR) }
|
||||
|
||||
private var debugClickCount = 0
|
||||
private val _fiveClicks = MutableStateFlow(false)
|
||||
|
||||
init {
|
||||
viewModelScope.sendEvent(
|
||||
analytics = analytics,
|
||||
eventName = EventsDictionary.loginScreenShow
|
||||
)
|
||||
viewModelScope.launch {
|
||||
_fiveClicks.collect {
|
||||
if (it) proceedWithGoroutinesDebug()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onLoginClicked(chain: String) {
|
||||
|
@ -177,7 +191,7 @@ class OnboardingMnemonicLoginViewModel @Inject constructor(
|
|||
}
|
||||
Timber.e(e, "Error while account loading")
|
||||
// TODO refact
|
||||
viewModelScope.launch { navigation.emit(Navigation.Exit) }
|
||||
viewModelScope.launch { command.emit(Command.Exit) }
|
||||
},
|
||||
fnR = {
|
||||
Timber.d("Account loading successfully finished")
|
||||
|
@ -248,7 +262,7 @@ class OnboardingMnemonicLoginViewModel @Inject constructor(
|
|||
|
||||
private fun navigateToMigrationErrorScreen() {
|
||||
viewModelScope.launch {
|
||||
navigation.emit(Navigation.NavigateToMigrationErrorScreen)
|
||||
command.emit(Command.NavigateToMigrationErrorScreen)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,7 +275,7 @@ class OnboardingMnemonicLoginViewModel @Inject constructor(
|
|||
|
||||
private fun navigateToDashboard() {
|
||||
viewModelScope.launch {
|
||||
navigation.emit(Navigation.NavigateToHomeScreen)
|
||||
command.emit(Command.NavigateToHomeScreen)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,6 +284,41 @@ class OnboardingMnemonicLoginViewModel @Inject constructor(
|
|||
proceedWithSelectingAccount(id)
|
||||
}
|
||||
|
||||
fun onEnterMyVaultClicked() {
|
||||
Timber.d("onEnterMyVaultClicked")
|
||||
viewModelScope.launch {
|
||||
debugClickCount++
|
||||
if (debugClickCount == 5) {
|
||||
_fiveClicks.emit(true)
|
||||
debugClickCount = 0
|
||||
} else {
|
||||
_fiveClicks.emit(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithGoroutinesDebug() {
|
||||
if (goroutinesJob?.isActive == true) {
|
||||
return
|
||||
}
|
||||
Timber.d("proceedWithGoroutinesDebug")
|
||||
goroutinesJob = viewModelScope.launch {
|
||||
debugGoroutines.async(DebugGoroutines.Params()).fold(
|
||||
onSuccess = { path ->
|
||||
command.emit(Command.ShareDebugGoroutines(path, uriFileProvider))
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Error while collecting goroutines diagnostics")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
goroutinesJob?.cancel()
|
||||
}
|
||||
|
||||
sealed class SideEffect {
|
||||
sealed class Error : SideEffect() {
|
||||
data object InvalidMnemonic : Error()
|
||||
|
@ -285,10 +334,12 @@ class OnboardingMnemonicLoginViewModel @Inject constructor(
|
|||
object Failed: SetupState()
|
||||
}
|
||||
|
||||
sealed class Navigation {
|
||||
object Exit : Navigation()
|
||||
object NavigateToMigrationErrorScreen : Navigation()
|
||||
object NavigateToHomeScreen: Navigation()
|
||||
sealed class Command {
|
||||
data object Exit : Command()
|
||||
data object NavigateToMigrationErrorScreen : Command()
|
||||
data object NavigateToHomeScreen: Command()
|
||||
data class ShowToast(val message: String) : Command()
|
||||
data class ShareDebugGoroutines(val path: String, val uriFileProvider: UriFileProvider) : Command()
|
||||
}
|
||||
|
||||
class Factory @Inject constructor(
|
||||
|
@ -306,7 +357,9 @@ class OnboardingMnemonicLoginViewModel @Inject constructor(
|
|||
private val crashReporter: CrashReporter,
|
||||
private val configStorage: ConfigStorage,
|
||||
private val localeProvider: LocaleProvider,
|
||||
private val userPermissionProvider: UserPermissionProvider
|
||||
private val userPermissionProvider: UserPermissionProvider,
|
||||
private val debugGoroutines: DebugGoroutines,
|
||||
private val uriFileProvider: UriFileProvider
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
|
@ -325,7 +378,9 @@ class OnboardingMnemonicLoginViewModel @Inject constructor(
|
|||
spaceDeletedStatusWatcher = spaceDeletedStatusWatcher,
|
||||
selectAccount = selectAccount,
|
||||
localeProvider = localeProvider,
|
||||
userPermissionProvider = userPermissionProvider
|
||||
userPermissionProvider = userPermissionProvider,
|
||||
debugGoroutines = debugGoroutines,
|
||||
uriFileProvider = uriFileProvider
|
||||
) as T
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue