diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/onboarding/login/OnboardingMnemonicLoginDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/onboarding/login/OnboardingMnemonicLoginDI.kt index 1257560c4e..ed7715b2d1 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/onboarding/login/OnboardingMnemonicLoginDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/onboarding/login/OnboardingMnemonicLoginDI.kt @@ -12,6 +12,7 @@ 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.config.UserSettingsRepository +import com.anytypeio.anytype.domain.debugging.DebugAccountSelectTrace import com.anytypeio.anytype.domain.debugging.DebugGoroutines import com.anytypeio.anytype.domain.device.PathProvider import com.anytypeio.anytype.domain.misc.LocaleProvider @@ -97,4 +98,5 @@ interface OnboardingMnemonicLoginDependencies : ComponentDependencies { fun userSettings(): UserSettingsRepository fun spaceManager(): SpaceManager fun globalSubscriptionManager(): GlobalSubscriptionManager + fun debugAccountSelectTrace(): DebugAccountSelectTrace } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/SubscriptionsModule.kt b/app/src/main/java/com/anytypeio/anytype/di/main/SubscriptionsModule.kt index 769ce9d488..a6198fd78b 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/main/SubscriptionsModule.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/main/SubscriptionsModule.kt @@ -8,6 +8,7 @@ import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.config.ConfigStorage +import com.anytypeio.anytype.domain.debugging.DebugAccountSelectTrace import com.anytypeio.anytype.domain.debugging.Logger import com.anytypeio.anytype.domain.event.interactor.SpaceSyncAndP2PStatusProvider import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer @@ -116,7 +117,7 @@ object SubscriptionsModule { configStorage: ConfigStorage, container: StorelessSubscriptionContainer, logger: Logger - ) : SpaceDeletedStatusWatcher = SpaceDeletedStatusWatcher( + ): SpaceDeletedStatusWatcher = SpaceDeletedStatusWatcher( spaceManager = spaceManager, dispatchers = dispatchers, configStorage = configStorage, @@ -135,7 +136,7 @@ object SubscriptionsModule { repo: AuthRepository, logger: Logger, spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer - ) : UserPermissionProvider = DefaultUserPermissionProvider( + ): UserPermissionProvider = DefaultUserPermissionProvider( dispatchers = dispatchers, scope = scope, container = container, @@ -154,7 +155,7 @@ object SubscriptionsModule { awaitAccountStartManager: AwaitAccountStartManager, logger: Logger, configStorage: ConfigStorage - ) : SpaceViewSubscriptionContainer = SpaceViewSubscriptionContainer.Default( + ): SpaceViewSubscriptionContainer = SpaceViewSubscriptionContainer.Default( dispatchers = dispatchers, scope = scope, container = container, @@ -173,7 +174,7 @@ object SubscriptionsModule { awaitAccountStartManager: AwaitAccountStartManager, configStorage: ConfigStorage, logger: Logger - ) : ProfileSubscriptionManager = ProfileSubscriptionManager.Default( + ): ProfileSubscriptionManager = ProfileSubscriptionManager.Default( dispatchers = dispatchers, scope = scope, container = container, @@ -192,7 +193,7 @@ object SubscriptionsModule { spaceManager: SpaceManager, awaitAccountStartManager: AwaitAccountStartManager, logger: Logger - ) : ActiveSpaceMemberSubscriptionContainer = ActiveSpaceMemberSubscriptionContainer.Default( + ): ActiveSpaceMemberSubscriptionContainer = ActiveSpaceMemberSubscriptionContainer.Default( dispatchers = dispatchers, scope = scope, container = container, @@ -221,7 +222,7 @@ object SubscriptionsModule { permissions: UserPermissionProvider, isSpaceDeleted: SpaceDeletedStatusWatcher, profileSubscriptionManager: ProfileSubscriptionManager - ) : GlobalSubscriptionManager = GlobalSubscriptionManager.Default( + ): GlobalSubscriptionManager = GlobalSubscriptionManager.Default( types = types, relations = relations, permissions = permissions, @@ -243,4 +244,16 @@ object SubscriptionsModule { repo: BlockRepository, dispatchers: AppCoroutineDispatchers ): GetObjectTypes = GetObjectTypes(repo, dispatchers) + + @JvmStatic + @Provides + @Singleton + fun provideDebugAccountSelectTrace( + repo: BlockRepository, + dispatchers: AppCoroutineDispatchers + ): DebugAccountSelectTrace = + DebugAccountSelectTrace( + repo = repo, + dispatchers = dispatchers + ) } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/onboarding/screens/signin/OnboardingRecoveryPhraseLoginScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/onboarding/screens/signin/OnboardingRecoveryPhraseLoginScreen.kt index 18c0146174..41709c39b3 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/onboarding/screens/signin/OnboardingRecoveryPhraseLoginScreen.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/onboarding/screens/signin/OnboardingRecoveryPhraseLoginScreen.kt @@ -3,11 +3,13 @@ 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.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardActions @@ -37,6 +39,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.withStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.anytypeio.anytype.BuildConfig import com.anytypeio.anytype.R import com.anytypeio.anytype.core_ui.ColorButtonRegular import com.anytypeio.anytype.core_ui.MnemonicPhrasePaletteColors @@ -51,6 +54,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 kotlin.Unit @Composable fun RecoveryScreenWrapper( @@ -64,7 +68,10 @@ fun RecoveryScreenWrapper( onActionDoneClicked = vm::onActionDone, onScanQrClicked = onScanQrClick, isLoading = vm.state.collectAsState().value is SetupState.InProgress, - onEnterMyVaultClicked = vm::onEnterMyVaultClicked + onEnterMyVaultClicked = vm::onEnterMyVaultClicked, + onDebugAccountTraceClicked = { + vm.onAccountThraceButtonClicked() + } ) } @@ -75,7 +82,8 @@ fun RecoveryScreen( onActionDoneClicked: (Mnemonic) -> Unit, onScanQrClicked: () -> Unit, isLoading: Boolean, - onEnterMyVaultClicked: () -> Unit + onEnterMyVaultClicked: () -> Unit, + onDebugAccountTraceClicked: () -> Unit ) { val focus = LocalFocusManager.current val context = LocalContext.current @@ -96,7 +104,7 @@ fun RecoveryScreen( ) Text( modifier = Modifier - .noRippleClickable{ onEnterMyVaultClicked() } + .noRippleClickable { onEnterMyVaultClicked() } .align(Alignment.TopCenter) .padding(top = 17.dp, start = 18.dp, end = 18.dp) , @@ -105,6 +113,19 @@ fun RecoveryScreen( color = colorResource(id = R.color.text_white) ) ) + if (BuildConfig.DEBUG) { + Image( + modifier = Modifier + .wrapContentSize() + .padding(top = 16.dp, end = 16.dp) + .align(Alignment.TopEnd) + .clickable { + onDebugAccountTraceClicked() + }, + painter = painterResource(R.drawable.ic_vault_settings), + contentDescription = "Debug account select command" + ) + } val emptyRecoveryPhraseError = stringResource(R.string.onboarding_your_key_can_t_be_empty) @@ -247,7 +268,8 @@ fun RecoveryScreenPreview() { onActionDoneClicked = {}, onScanQrClicked = {}, isLoading = false, - onEnterMyVaultClicked = {} + onEnterMyVaultClicked = {}, + onDebugAccountTraceClicked = {} ) } @@ -261,6 +283,7 @@ fun RecoveryScreenLoadingPreview() { onActionDoneClicked = {}, onScanQrClicked = {}, isLoading = true, - onEnterMyVaultClicked = {} + onEnterMyVaultClicked = {}, + onDebugAccountTraceClicked = {} ) } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt index 143419edf2..f6d5a3ca15 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt @@ -1080,4 +1080,8 @@ class BlockDataRepository( override suspend fun unsubscribeChat(chat: Id) { return remote.unsubscribeChat(chat) } + + override suspend fun debugAccountSelectTrace(dir: String): String { + return remote.debugAccountSelectTrace(dir) + } } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt index 0627d50b82..235a9da480 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt @@ -457,4 +457,6 @@ interface BlockRemote { suspend fun unsubscribeChat(chat: Id) //endregion + + suspend fun debugAccountSelectTrace(dir: String): String } \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt b/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt index f889c7d50f..a589fc93b3 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt @@ -500,4 +500,6 @@ interface BlockRepository { suspend fun unsubscribeChat(chat: Id) //endregion + + suspend fun debugAccountSelectTrace(dir: String): String } \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/debugging/DebugAccountSelectTrace.kt b/domain/src/main/java/com/anytypeio/anytype/domain/debugging/DebugAccountSelectTrace.kt new file mode 100644 index 0000000000..21e3eab381 --- /dev/null +++ b/domain/src/main/java/com/anytypeio/anytype/domain/debugging/DebugAccountSelectTrace.kt @@ -0,0 +1,18 @@ +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 javax.inject.Inject + +class DebugAccountSelectTrace @Inject constructor( + private val repo: BlockRepository, + dispatchers: AppCoroutineDispatchers +) : ResultInteractor(dispatchers.io) { + + override suspend fun doWork(params: Params): String { + return repo.debugAccountSelectTrace(params.dir) + } + + data class Params(val dir: String) +} \ No newline at end of file diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt index 4d1091cfe1..e3b8275a1c 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt @@ -1057,4 +1057,8 @@ class BlockMiddleware( override suspend fun dataViewSetActiveView(command: Command.DataViewSetActiveView): Payload { return middleware.dataViewSetActiveView(command) } + + override suspend fun debugAccountSelectTrace(dir: String): String { + return middleware.debugAccountSelectTrace(dir) + } } \ No newline at end of file diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt index ccff56332b..1f3226adac 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt @@ -2806,6 +2806,15 @@ class Middleware @Inject constructor( logResponseIfDebug(response, time) } + @Throws(Exception::class) + fun debugAccountSelectTrace(dir: String): String { + val request = Rpc.Debug.AccountSelectTrace.Request(dir = dir) + logRequestIfDebug(request) + val (response, time) = measureTimedValue { service.debugAccountSelectTrace(request) } + logResponseIfDebug(response, time) + return response.path + } + private fun logRequestIfDebug(request: Any) { if (BuildConfig.DEBUG) { logger.logRequest(request).also { diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt index 7a6f3c723e..bd9f7f6b56 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt @@ -599,4 +599,7 @@ interface MiddlewareService { fun chatUnsubscribe(request: Rpc.Chat.Unsubscribe.Request): Rpc.Chat.Unsubscribe.Response //endregion + + @Throws(Exception::class) + fun debugAccountSelectTrace(request: Rpc.Debug.AccountSelectTrace.Request): Rpc.Debug.AccountSelectTrace.Response } \ No newline at end of file diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt index 381210d466..102dfcd4e0 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt @@ -2403,4 +2403,17 @@ class MiddlewareServiceImplementation @Inject constructor( return response } } + + override fun debugAccountSelectTrace(request: Rpc.Debug.AccountSelectTrace.Request): Rpc.Debug.AccountSelectTrace.Response { + val encoded = Service.debugAccountSelectTrace( + Rpc.Debug.AccountSelectTrace.Request.ADAPTER.encode(request) + ) + val response = Rpc.Debug.AccountSelectTrace.Response.ADAPTER.decode(encoded) + val error = response.error + if (error != null && error.code != Rpc.Debug.AccountSelectTrace.Response.Error.Code.NULL) { + throw Exception(error.description) + } else { + return response + } + } } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/onboarding/login/OnboardingMnemonicLoginViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/onboarding/login/OnboardingMnemonicLoginViewModel.kt index 2229cb9f3c..0074a545f2 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/onboarding/login/OnboardingMnemonicLoginViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/onboarding/login/OnboardingMnemonicLoginViewModel.kt @@ -22,6 +22,7 @@ import com.anytypeio.anytype.domain.auth.interactor.StartLoadingAccounts import com.anytypeio.anytype.domain.base.Interactor import com.anytypeio.anytype.domain.base.fold import com.anytypeio.anytype.domain.config.ConfigStorage +import com.anytypeio.anytype.domain.debugging.DebugAccountSelectTrace import com.anytypeio.anytype.domain.debugging.DebugGoroutines import com.anytypeio.anytype.domain.device.PathProvider import com.anytypeio.anytype.domain.misc.LocaleProvider @@ -53,7 +54,8 @@ class OnboardingMnemonicLoginViewModel @Inject constructor( private val debugGoroutines: DebugGoroutines, private val uriFileProvider: UriFileProvider, private val logout: Logout, - private val globalSubscriptionManager: GlobalSubscriptionManager + private val globalSubscriptionManager: GlobalSubscriptionManager, + private val debugAccountSelectTrace: DebugAccountSelectTrace ) : ViewModel() { private val jobs = mutableListOf() @@ -339,6 +341,26 @@ class OnboardingMnemonicLoginViewModel @Inject constructor( } } + fun onAccountThraceButtonClicked() { + jobs += viewModelScope.launch { + val path = pathProvider.providePath() + val params = DebugAccountSelectTrace.Params( + dir = path + ) + debugAccountSelectTrace.async(params).fold( + onSuccess = { + Timber.d("On account trace success") + command.emit(Command.ShowToast("On account trace success")) + command.emit(Command.ShareDebugGoroutines(path, uriFileProvider)) + }, + onFailure = { + Timber.e(it, "Error while collecting account trace") + command.emit(Command.ShowToast("Error while collecting account trace: ${it.message}")) + } + ) + } + } + override fun onCleared() { super.onCleared() goroutinesJob?.cancel() @@ -384,7 +406,8 @@ class OnboardingMnemonicLoginViewModel @Inject constructor( private val debugGoroutines: DebugGoroutines, private val uriFileProvider: UriFileProvider, private val logout: Logout, - private val globalSubscriptionManager: GlobalSubscriptionManager + private val globalSubscriptionManager: GlobalSubscriptionManager, + private val debugAccountSelectTrace: DebugAccountSelectTrace ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { @@ -403,7 +426,8 @@ class OnboardingMnemonicLoginViewModel @Inject constructor( debugGoroutines = debugGoroutines, uriFileProvider = uriFileProvider, logout = logout, - globalSubscriptionManager = globalSubscriptionManager + globalSubscriptionManager = globalSubscriptionManager, + debugAccountSelectTrace = debugAccountSelectTrace ) as T } }