From 963603f0f8a50e6d90fecdbe67903de88f1fdf8d Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <54908981+konstantiniiv@users.noreply.github.com> Date: Fri, 20 Dec 2024 12:20:16 +0100 Subject: [PATCH] DROID-3164 Tech | Support debug log sharing (#1943) --- .../anytype/di/feature/AppPreferencesDi.kt | 23 ++++++- .../OnboardingNetworkSetupDialog.kt | 28 ++++++++- .../signin/OnboardingNetworkSetupScreen.kt | 26 +++----- app/src/main/res/xml/provider_paths.xml | 1 + .../anytypeio/anytype/core_models/Command.kt | 3 +- .../core_utils/ext/AndroidExtension.kt | 15 +++++ .../data/auth/repo/AuthCacheDataStore.kt | 4 ++ .../data/auth/repo/AuthDataRepository.kt | 4 ++ .../anytype/data/auth/repo/AuthDataStore.kt | 1 + .../anytype/data/auth/repo/AuthRemote.kt | 1 + .../data/auth/repo/AuthRemoteDataStore.kt | 4 ++ .../domain/auth/interactor/CreateAccount.kt | 1 - .../domain/auth/repo/AuthRepository.kt | 1 + .../domain/debugging/DebugExportLogs.kt | 18 ++++++ localization/src/main/res/values/strings.xml | 1 + .../anytype/middleware/auth/AuthMiddleware.kt | 4 ++ .../middleware/interactor/Middleware.kt | 12 +++- .../middleware/service/MiddlewareService.kt | 3 + .../MiddlewareServiceImplementation.kt | 13 ++++ .../settings/PreferencesViewModel.kt | 63 +++++++++++++++---- 20 files changed, 189 insertions(+), 37 deletions(-) create mode 100644 domain/src/main/java/com/anytypeio/anytype/domain/debugging/DebugExportLogs.kt diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/AppPreferencesDi.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/AppPreferencesDi.kt index 70a17b131b..d1e4c0c2a6 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/AppPreferencesDi.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/AppPreferencesDi.kt @@ -6,12 +6,15 @@ import com.anytypeio.anytype.core_utils.di.scope.PerScreen import com.anytypeio.anytype.di.common.ComponentDependencies import com.anytypeio.anytype.domain.auth.repo.AuthRepository import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers +import com.anytypeio.anytype.domain.debugging.DebugExportLogs +import com.anytypeio.anytype.domain.device.PathProvider import com.anytypeio.anytype.domain.networkmode.GetNetworkMode import com.anytypeio.anytype.domain.networkmode.SetNetworkMode import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate import com.anytypeio.anytype.presentation.settings.PreferencesViewModel import com.anytypeio.anytype.presentation.util.CopyFileToCacheDirectory import com.anytypeio.anytype.presentation.util.NetworkModeCopyFileToCacheDirectory +import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider import com.anytypeio.anytype.ui.onboarding.OnboardingNetworkSetupDialog import com.anytypeio.anytype.ui.settings.system.PreferenceFragment import dagger.Component @@ -44,6 +47,14 @@ object AppPreferencesModule { context: Context ): CopyFileToCacheDirectory = NetworkModeCopyFileToCacheDirectory(context) + @JvmStatic + @Provides + @PerScreen + fun provideLogsExport( + repository: AuthRepository, + dispatchers: AppCoroutineDispatchers + ): DebugExportLogs = DebugExportLogs(repository, dispatchers) + @JvmStatic @Provides @PerScreen @@ -51,12 +62,18 @@ object AppPreferencesModule { copyFileToCacheDirectory: CopyFileToCacheDirectory, getNetworkMode: GetNetworkMode, setNetworkMode: SetNetworkMode, - analytics: Analytics + analytics: Analytics, + debugExportLogs: DebugExportLogs, + pathProvider: PathProvider, + urlFileProvider: UriFileProvider ): PreferencesViewModel.Factory = PreferencesViewModel.Factory( copyFileToCacheDirectory = copyFileToCacheDirectory, getNetworkMode = getNetworkMode, setNetworkMode = setNetworkMode, - analytics = analytics + analytics = analytics, + debugExportLogs = debugExportLogs, + pathProvider = pathProvider, + uriFileProvider = urlFileProvider ) } @@ -66,4 +83,6 @@ interface AppPreferencesDependencies : ComponentDependencies { fun authRepository(): AuthRepository fun analytics(): Analytics fun analyticSpaceHelper(): AnalyticSpaceHelperDelegate + fun pathProvider(): PathProvider + fun provideUriFileProvider(): UriFileProvider } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/onboarding/OnboardingNetworkSetupDialog.kt b/app/src/main/java/com/anytypeio/anytype/ui/onboarding/OnboardingNetworkSetupDialog.kt index f47974a1e3..8cc2e02b02 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/onboarding/OnboardingNetworkSetupDialog.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/onboarding/OnboardingNetworkSetupDialog.kt @@ -15,6 +15,8 @@ import com.anytypeio.anytype.R import com.anytypeio.anytype.core_models.NetworkModeConstants import com.anytypeio.anytype.core_utils.const.FileConstants import com.anytypeio.anytype.core_utils.ext.Mimetype +import com.anytypeio.anytype.core_utils.ext.shareFileFromPath +import com.anytypeio.anytype.core_utils.ext.subscribe import com.anytypeio.anytype.core_utils.ext.toast import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment import com.anytypeio.anytype.di.common.componentManager @@ -23,6 +25,7 @@ import com.anytypeio.anytype.ui.editor.PickerDelegate import com.anytypeio.anytype.ui.onboarding.screens.signin.NetworkSetupScreen import com.anytypeio.anytype.ui.settings.typography import javax.inject.Inject +import timber.log.Timber class OnboardingNetworkSetupDialog : BaseBottomSheetComposeFragment() { @@ -62,12 +65,35 @@ class OnboardingNetworkSetupDialog : BaseBottomSheetComposeFragment() { onAnytypeNetworkClicked = { vm.proceedWithNetworkMode(NetworkModeConstants.NETWORK_MODE_DEFAULT) }, - onUseYamuxToggled = vm::onChangeMultiplexLibrary + onExportLogsClick = vm::onExportLogsClick ) } } } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + subscribe(vm.commands) { command -> + when (command) { + is PreferencesViewModel.Command.ShareDebugLogs -> { + try { + shareFileFromPath( + path = command.path, + uriFileProvider = command.uriFileProvider + ) + } catch (e: Exception) { + Timber.e(e, "Error while share debug logs").also { + toast("Error while share debug logs. Please try again later.") + } + } + } + is PreferencesViewModel.Command.ShowToast -> { + toast(command.message) + } + } + } + } + private fun setup() { pickerDelegate = PickerDelegate.Impl(this) { actions -> when (actions) { diff --git a/app/src/main/java/com/anytypeio/anytype/ui/onboarding/screens/signin/OnboardingNetworkSetupScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/onboarding/screens/signin/OnboardingNetworkSetupScreen.kt index 4cd31fd9ba..b1f73a70e1 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/onboarding/screens/signin/OnboardingNetworkSetupScreen.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/onboarding/screens/signin/OnboardingNetworkSetupScreen.kt @@ -52,7 +52,7 @@ fun DefaultNetworkSetupScreenPreview() { onLocalOnlyClicked = {}, onSelfHostNetworkClicked = {}, onSetSelfHostConfigConfigClicked = {}, - onUseYamuxToggled = {} + onExportLogsClick = {} ) } @@ -69,7 +69,7 @@ fun SelfHostNetworkSetupScreenPreview() { onLocalOnlyClicked = {}, onSelfHostNetworkClicked = {}, onSetSelfHostConfigConfigClicked = {}, - onUseYamuxToggled = {} + onExportLogsClick = {} ) } @@ -86,7 +86,7 @@ fun SelfHostNetworkWithPathSetupScreenPreview() { onLocalOnlyClicked = {}, onSelfHostNetworkClicked = {}, onSetSelfHostConfigConfigClicked = {}, - onUseYamuxToggled = {} + onExportLogsClick = {} ) } @@ -103,7 +103,7 @@ fun LocalNetworkWithPathSetupScreenPreview() { onLocalOnlyClicked = {}, onSelfHostNetworkClicked = {}, onSetSelfHostConfigConfigClicked = {}, - onUseYamuxToggled = {} + onExportLogsClick = {} ) } @@ -114,7 +114,7 @@ fun NetworkSetupScreen( onAnytypeNetworkClicked: () -> Unit, onSelfHostNetworkClicked: () -> Unit, onSetSelfHostConfigConfigClicked: () -> Unit, - onUseYamuxToggled: () -> Unit + onExportLogsClick: () -> Unit ) { Column( modifier = Modifier @@ -148,19 +148,19 @@ fun NetworkSetupScreen( color = NetworkSettingDescriptionColor, textPaddingStart = 0.dp ) - UseYamuxCard(config = config, onUseYamuxToggled = onUseYamuxToggled) + ExportLogs(onExportLogsClick = onExportLogsClick) Spacer(modifier = Modifier.height(24.dp)) } } @Composable -private fun UseYamuxCard(config: NetworkModeConfig, onUseYamuxToggled: () -> Unit) { +private fun ExportLogs(onExportLogsClick: () -> Unit) { Column( modifier = Modifier .clip(RoundedCornerShape(16.dp)) .fillMaxWidth() .background(color = NetworkSettingCardColor) - .noRippleClickable { onUseYamuxToggled() } + .noRippleClickable { onExportLogsClick() } ) { Row( verticalAlignment = Alignment.CenterVertically, @@ -170,19 +170,11 @@ private fun UseYamuxCard(config: NetworkModeConfig, onUseYamuxToggled: () -> Uni ) ) { Text( - text = stringResource(id = R.string.settings_use_yamux), + text = stringResource(id = R.string.settings_share_local_logs), style = BodyCalloutRegular, color = NetworkSettingTitleColor, modifier = Modifier.weight(1.0f) ) - if (config.useReserveMultiplexLib) { - Image( - painter = painterResource(id = R.drawable.ic_network_settings_checked), - contentDescription = "Check icon" - ) - } else { - Spacer(modifier = Modifier.size(24.dp)) - } } } } diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml index 4419d669d4..948ac11c51 100644 --- a/app/src/main/res/xml/provider_paths.xml +++ b/app/src/main/res/xml/provider_paths.xml @@ -1,4 +1,5 @@ + \ No newline at end of file diff --git a/core-models/src/main/java/com/anytypeio/anytype/core_models/Command.kt b/core-models/src/main/java/com/anytypeio/anytype/core_models/Command.kt index 2b5bd485f5..680ea89542 100644 --- a/core-models/src/main/java/com/anytypeio/anytype/core_models/Command.kt +++ b/core-models/src/main/java/com/anytypeio/anytype/core_models/Command.kt @@ -13,8 +13,7 @@ sealed class Command { val avatarPath: String?, val icon: Int, val networkMode: NetworkMode = NetworkMode.DEFAULT, - val networkConfigFilePath: String? = null, - val preferYamuxTransport: Boolean? = null + val networkConfigFilePath: String? = null ) : Command() data class AccountSelect( diff --git a/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/AndroidExtension.kt b/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/AndroidExtension.kt index 5a0d8ae8f5..f8e86a81f5 100644 --- a/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/AndroidExtension.kt +++ b/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/AndroidExtension.kt @@ -386,6 +386,21 @@ fun Fragment.shareFirstFileFromPath(path: String, uriFileProvider: UriFileProvid } } +fun Fragment.shareFileFromPath(path: String, uriFileProvider: UriFileProvider) { + try { + val dirPath = File(path) + if (dirPath.exists()) { + val uri = uriFileProvider.getUriForFile(dirPath) + shareFile(uri) + } else { + toast("File does not exist.") + } + } 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 { diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt index 8c32ad6003..471c53c790 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt @@ -89,4 +89,8 @@ class AuthCacheDataStore(private val cache: AuthCache) : AuthDataStore { override suspend fun setNetworkMode(modeConfig: NetworkModeConfig) { cache.setNetworkMode(modeConfig) } + + override suspend fun debugExportLogs(dir: String): String { + throw UnsupportedOperationException() + } } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt index 4413f568c9..30a41ebe2f 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt @@ -100,4 +100,8 @@ class AuthDataRepository( override suspend fun setNetworkMode(modeConfig: NetworkModeConfig) { factory.cache.setNetworkMode(modeConfig) } + + override suspend fun debugExportLogs(dir: String): String { + return factory.remote.debugExportLogs(dir) + } } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt index 4dfc81f1d1..1b9b077ace 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt @@ -42,4 +42,5 @@ interface AuthDataStore { suspend fun getNetworkMode(): NetworkModeConfig suspend fun setNetworkMode(modeConfig: NetworkModeConfig) + suspend fun debugExportLogs(dir: String): String } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemote.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemote.kt index 73797a1839..9ec8e409bf 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemote.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemote.kt @@ -22,4 +22,5 @@ interface AuthRemote { suspend fun getVersion(): String suspend fun setInitialParams(command: Command.SetInitialParams) + suspend fun debugExportLogs(dir: String): String } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt index 5874dc03d0..6620b8478d 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt @@ -89,4 +89,8 @@ class AuthRemoteDataStore( override suspend fun setNetworkMode(modeConfig: NetworkModeConfig) { throw UnsupportedOperationException() } + + override suspend fun debugExportLogs(dir: String): String { + return authRemote.debugExportLogs(dir) + } } \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/CreateAccount.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/CreateAccount.kt index 5a82376292..c07fcfc1b2 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/CreateAccount.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/CreateAccount.kt @@ -35,7 +35,6 @@ open class CreateAccount @Inject constructor( icon = params.iconGradientValue, networkMode = networkMode.networkMode, networkConfigFilePath = networkMode.storedFilePath, - preferYamuxTransport = networkMode.useReserveMultiplexLib ) val setup = repository.createAccount(command) with(repository) { diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt index a18535619d..a0a40934ed 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt @@ -59,4 +59,5 @@ interface AuthRepository { suspend fun getNetworkMode(): NetworkModeConfig suspend fun setNetworkMode(modeConfig: NetworkModeConfig) + suspend fun debugExportLogs(dir: String): String } \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/debugging/DebugExportLogs.kt b/domain/src/main/java/com/anytypeio/anytype/domain/debugging/DebugExportLogs.kt new file mode 100644 index 0000000000..669320092b --- /dev/null +++ b/domain/src/main/java/com/anytypeio/anytype/domain/debugging/DebugExportLogs.kt @@ -0,0 +1,18 @@ +package com.anytypeio.anytype.domain.debugging + +import com.anytypeio.anytype.domain.auth.repo.AuthRepository +import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers +import com.anytypeio.anytype.domain.base.ResultInteractor +import javax.inject.Inject + +class DebugExportLogs @Inject constructor( + private val repo: AuthRepository, + dispatchers: AppCoroutineDispatchers +) : ResultInteractor(dispatchers.io) { + + override suspend fun doWork(params: Params): String { + return repo.debugExportLogs(params.dir) + } + + data class Params(val dir: String) +} \ No newline at end of file diff --git a/localization/src/main/res/values/strings.xml b/localization/src/main/res/values/strings.xml index 22958be181..163be429e3 100644 --- a/localization/src/main/res/values/strings.xml +++ b/localization/src/main/res/values/strings.xml @@ -1271,6 +1271,7 @@ %1$s days from now Use a reserve multiplex library + Share local logs diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMiddleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMiddleware.kt index cd59a24609..78b5ac2d47 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMiddleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMiddleware.kt @@ -75,4 +75,8 @@ class AuthMiddleware( override suspend fun setInitialParams(command: Command.SetInitialParams) { middleware.metricsSetParameters(command) } + + override suspend fun debugExportLogs(dir: String): String { + return middleware.debugExportLogs(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 65e9e0cf7b..7a57b6fd12 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 @@ -90,8 +90,7 @@ class Middleware @Inject constructor( avatarLocalPath = command.avatarPath, icon = command.icon.toLong(), networkMode = command.networkMode.toMiddlewareModel(), - networkCustomConfigFilePath = command.networkConfigFilePath.orEmpty(), - preferYamuxTransport = command.preferYamuxTransport ?: false + networkCustomConfigFilePath = command.networkConfigFilePath.orEmpty() ) logRequestIfDebug(request) val (response, time) = measureTimedValue { service.accountCreate(request) } @@ -2867,6 +2866,15 @@ class Middleware @Inject constructor( logResponseIfDebug(response, time) } + @Throws(Exception::class) + fun debugExportLogs(dir: String): String { + val request = Rpc.Debug.ExportLog.Request(dir = dir) + logRequestIfDebug(request) + val (response, time) = measureTimedValue { service.debugExportLogs(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 fe9ff68f81..4a1851178d 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 @@ -612,4 +612,7 @@ interface MiddlewareService { @Throws(Exception::class) fun deviceNetworkStateSet(request: Rpc.Device.NetworkState.Set.Request): Rpc.Device.NetworkState.Set.Response + + @Throws(Exception::class) + fun debugExportLogs(request: Rpc.Debug.ExportLog.Request): Rpc.Debug.ExportLog.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 c3078571fc..9ae9436eb2 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 @@ -2463,4 +2463,17 @@ class MiddlewareServiceImplementation @Inject constructor( return response } } + + override fun debugExportLogs(request: Rpc.Debug.ExportLog.Request): Rpc.Debug.ExportLog.Response { + val encoded = Service.debugExportLog( + Rpc.Debug.ExportLog.Request.ADAPTER.encode(request) + ) + val response = Rpc.Debug.ExportLog.Response.ADAPTER.decode(encoded) + val error = response.error + if (error != null && error.code != Rpc.Debug.ExportLog.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/settings/PreferencesViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/PreferencesViewModel.kt index 94c2ac65ac..345d804d05 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/PreferencesViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/PreferencesViewModel.kt @@ -11,7 +11,10 @@ import com.anytypeio.anytype.core_models.NetworkMode import com.anytypeio.anytype.core_models.NetworkModeConfig import com.anytypeio.anytype.core_models.NetworkModeConstants.NETWORK_MODE_CUSTOM import com.anytypeio.anytype.core_models.NetworkModeConstants.NETWORK_MODE_LOCAL +import com.anytypeio.anytype.core_utils.ext.cancel import com.anytypeio.anytype.domain.base.fold +import com.anytypeio.anytype.domain.debugging.DebugExportLogs +import com.anytypeio.anytype.domain.device.PathProvider import com.anytypeio.anytype.domain.networkmode.GetNetworkMode import com.anytypeio.anytype.domain.networkmode.SetNetworkMode import com.anytypeio.anytype.presentation.editor.picker.PickerListener @@ -19,6 +22,9 @@ import com.anytypeio.anytype.presentation.extension.sendAnalyticsSelectNetworkEv import com.anytypeio.anytype.presentation.extension.sendAnalyticsUploadConfigFileEvent import com.anytypeio.anytype.presentation.util.CopyFileToCacheDirectory import com.anytypeio.anytype.presentation.util.CopyFileToCacheStatus +import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch import timber.log.Timber @@ -27,12 +33,18 @@ class PreferencesViewModel( private val copyFileToCache: CopyFileToCacheDirectory, private val getNetworkMode: GetNetworkMode, private val setNetworkMode: SetNetworkMode, - private val analytics: Analytics + private val analytics: Analytics, + private val debugExportLogs: DebugExportLogs, + private val pathProvider: PathProvider, + private val uriFileProvider: UriFileProvider, ) : ViewModel(), PickerListener { val networkModeState = MutableStateFlow(NetworkModeConfig(NetworkMode.DEFAULT, "", "")) val reserveMultiplexSetting = MutableStateFlow(false) + private val jobs = mutableListOf() + val commands = MutableSharedFlow() + fun onStart() { Timber.d("onStart") viewModelScope.launch { @@ -49,6 +61,11 @@ class PreferencesViewModel( } } + override fun onCleared() { + super.onCleared() + jobs.cancel() + } + fun proceedWithNetworkMode(mode: String?) { viewModelScope.launch { val config = when (mode) { @@ -104,19 +121,30 @@ class PreferencesViewModel( } } - fun onChangeMultiplexLibrary() { - val newValue = !networkModeState.value.useReserveMultiplexLib - Timber.d("onChangeMultiplexLibrary: $newValue") - viewModelScope.launch { - val mode = networkModeState.value.copy(useReserveMultiplexLib = newValue) - val params = SetNetworkMode.Params(mode) - setNetworkMode.async(params).fold( - onSuccess = { networkModeState.value = mode }, - onFailure = { Timber.e(it, "Failed to update network mode ") } + fun onExportLogsClick() { + Timber.d("onExportLogsClick: ") + jobs += viewModelScope.launch { + val dir = pathProvider.providePath() + val params = DebugExportLogs.Params(dir = dir) + debugExportLogs.async(params).fold( + onSuccess = { fileName -> + Timber.d("On debug logs success") + sendCommand(Command.ShareDebugLogs(fileName, uriFileProvider)) + }, + onFailure = { + Timber.e(it, "Error while collecting debug logs") + sendCommand(Command.ShowToast("Error while collecting debug logs: ")) + } ) } } + private fun sendCommand(command: Command) { + viewModelScope.launch { + commands.emit(command) + } + } + override fun onStartCopyFileToCacheDir(uri: Uri) { Timber.d("onStartCopyFileToCacheDir: $uri") copyFileToCache.execute( @@ -145,11 +173,19 @@ class PreferencesViewModel( } } + sealed class Command { + data class ShowToast(val message: String) : Command() + data class ShareDebugLogs(val path: String, val uriFileProvider: UriFileProvider) : Command() + } + class Factory( private val copyFileToCacheDirectory: CopyFileToCacheDirectory, private val getNetworkMode: GetNetworkMode, private val setNetworkMode: SetNetworkMode, - private val analytics: Analytics + private val analytics: Analytics, + private val debugExportLogs: DebugExportLogs, + private val pathProvider: PathProvider, + private val uriFileProvider: UriFileProvider, ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create( @@ -158,7 +194,10 @@ class PreferencesViewModel( copyFileToCache = copyFileToCacheDirectory, getNetworkMode = getNetworkMode, setNetworkMode = setNetworkMode, - analytics = analytics + analytics = analytics, + debugExportLogs = debugExportLogs, + pathProvider = pathProvider, + uriFileProvider = uriFileProvider ) as T } } \ No newline at end of file