From 2d115aa64b0b8659444eadd4f6b558d191306151 Mon Sep 17 00:00:00 2001 From: Evgenii Kozlov Date: Thu, 27 Feb 2025 13:38:02 +0100 Subject: [PATCH] DROID-3407 App | Tech | New debug menu + allow exporting work directory (#2122) --- .../anytype/di/common/ComponentManager.kt | 11 ++- .../anytype/di/feature/settings/DebugDI.kt | 49 ++++++++++ .../anytype/di/main/MainComponent.kt | 9 +- .../anytype/ui/settings/DebugFragment.kt | 93 +++++++++++++++++++ .../anytype/ui/settings/DebugScreen.kt | 78 ++++++++++++++++ .../ui/settings/ProfileSettingsFragment.kt | 10 +- app/src/main/res/navigation/graph.xml | 6 ++ .../core_models/settings/VaultSettings.kt | 3 - .../anytypeio/anytype/core_utils/tools/IO.kt | 21 +++++ .../ui_settings/account/ProfileScreen.kt | 39 ++++++-- .../account/ProfileSettingsViewModel.kt | 15 +++ .../repo/DefaultUserSettingsCache.kt | 5 +- persistence/src/main/proto/preferences.proto | 1 + .../persistence/UserSettingsCacheTest.kt | 4 - .../presentation/settings/DebugViewModel.kt | 55 +++++++++++ 15 files changed, 376 insertions(+), 23 deletions(-) create mode 100644 app/src/main/java/com/anytypeio/anytype/di/feature/settings/DebugDI.kt create mode 100644 app/src/main/java/com/anytypeio/anytype/ui/settings/DebugFragment.kt create mode 100644 app/src/main/java/com/anytypeio/anytype/ui/settings/DebugScreen.kt create mode 100644 core-utils/src/main/java/com/anytypeio/anytype/core_utils/tools/IO.kt create mode 100644 presentation/src/main/java/com/anytypeio/anytype/presentation/settings/DebugViewModel.kt diff --git a/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt b/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt index 4ea9d1dcd8..2cc7528514 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt @@ -49,9 +49,9 @@ import com.anytypeio.anytype.di.feature.ViewerFilterModule import com.anytypeio.anytype.di.feature.ViewerSortModule import com.anytypeio.anytype.di.feature.auth.DaggerDeletedAccountComponent import com.anytypeio.anytype.di.feature.chats.DaggerChatComponent -import com.anytypeio.anytype.di.feature.cover.UnsplashModule import com.anytypeio.anytype.di.feature.chats.DaggerChatReactionComponent import com.anytypeio.anytype.di.feature.chats.DaggerSelectChatReactionComponent +import com.anytypeio.anytype.di.feature.cover.UnsplashModule import com.anytypeio.anytype.di.feature.gallery.DaggerGalleryInstallationComponent import com.anytypeio.anytype.di.feature.home.DaggerHomeScreenComponent import com.anytypeio.anytype.di.feature.membership.DaggerMembershipComponent @@ -82,6 +82,7 @@ import com.anytypeio.anytype.di.feature.sets.PickConditionModule import com.anytypeio.anytype.di.feature.sets.SelectFilterRelationModule import com.anytypeio.anytype.di.feature.settings.DaggerAboutAppComponent import com.anytypeio.anytype.di.feature.settings.DaggerAppearanceComponent +import com.anytypeio.anytype.di.feature.settings.DaggerDebugComponent import com.anytypeio.anytype.di.feature.settings.DaggerFilesStorageComponent import com.anytypeio.anytype.di.feature.settings.DaggerSpacesStorageComponent import com.anytypeio.anytype.di.feature.settings.LogoutWarningModule @@ -102,10 +103,10 @@ import com.anytypeio.anytype.di.feature.widgets.DaggerSelectWidgetSourceComponen import com.anytypeio.anytype.di.feature.widgets.DaggerSelectWidgetTypeComponent import com.anytypeio.anytype.di.main.MainComponent import com.anytypeio.anytype.feature_allcontent.presentation.AllContentViewModel -import com.anytypeio.anytype.feature_date.viewmodel.DateObjectVmParams import com.anytypeio.anytype.feature_chats.presentation.ChatReactionViewModel import com.anytypeio.anytype.feature_chats.presentation.ChatViewModel import com.anytypeio.anytype.feature_chats.presentation.SelectChatReactionViewModel +import com.anytypeio.anytype.feature_date.viewmodel.DateObjectVmParams import com.anytypeio.anytype.gallery_experience.viewmodel.GalleryInstallationViewModel import com.anytypeio.anytype.presentation.editor.EditorViewModel import com.anytypeio.anytype.presentation.history.VersionHistoryViewModel @@ -148,6 +149,12 @@ class ComponentManager( .build() } + val debugComponent = Component { + DaggerDebugComponent + .factory() + .create(findComponentDependencies()) + } + val splashLoginComponent = Component { DaggerSplashComponent .factory() diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/settings/DebugDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/settings/DebugDI.kt new file mode 100644 index 0000000000..720f511042 --- /dev/null +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/settings/DebugDI.kt @@ -0,0 +1,49 @@ +package com.anytypeio.anytype.di.feature.settings + +import androidx.lifecycle.ViewModelProvider +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.device.PathProvider +import com.anytypeio.anytype.presentation.settings.DebugViewModel +import com.anytypeio.anytype.ui.settings.DebugFragment +import dagger.Binds +import dagger.Component +import dagger.Module + +@Component( + dependencies = [DebugDependencies::class], + modules = [ + DebugModule::class, + DebugModule.Declarations::class + ] +) +@PerScreen +interface DebugComponent { + + @Component.Factory + interface Factory { + fun create(dependencies: DebugDependencies): DebugComponent + } + + fun inject(fragment: DebugFragment) +} + +@Module +object DebugModule { + @Module + interface Declarations { + @PerScreen + @Binds + fun bindViewModelFactory( + factory: DebugViewModel.Factory + ): ViewModelProvider.Factory + } +} + +interface DebugDependencies : ComponentDependencies { + fun path(): PathProvider + fun auth(): AuthRepository + fun dispatchers(): AppCoroutineDispatchers +} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt b/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt index 6a30bb8046..8306646e00 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt @@ -43,6 +43,7 @@ import com.anytypeio.anytype.di.feature.relations.RelationEditDependencies import com.anytypeio.anytype.di.feature.search.GlobalSearchDependencies import com.anytypeio.anytype.di.feature.settings.AboutAppDependencies import com.anytypeio.anytype.di.feature.settings.AppearanceDependencies +import com.anytypeio.anytype.di.feature.settings.DebugDependencies import com.anytypeio.anytype.di.feature.settings.FilesStorageDependencies import com.anytypeio.anytype.di.feature.settings.LogoutWarningSubComponent import com.anytypeio.anytype.di.feature.settings.ProfileSubComponent @@ -139,7 +140,8 @@ interface MainComponent : DateObjectDependencies, SelectChatReactionDependencies, ChatReactionDependencies, - ParticipantComponentDependencies + ParticipantComponentDependencies, + DebugDependencies { fun inject(app: AndroidApplication) @@ -400,4 +402,9 @@ abstract class ComponentDependenciesModule { @IntoMap @ComponentDependenciesKey(ParticipantComponentDependencies::class) abstract fun provideParticipantComponentDependencies(component: MainComponent): ComponentDependencies + + @Binds + @IntoMap + @ComponentDependenciesKey(DebugDependencies::class) + abstract fun provideDebugDependencies(component: MainComponent): ComponentDependencies } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/settings/DebugFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/settings/DebugFragment.kt new file mode 100644 index 0000000000..3c0ef402b5 --- /dev/null +++ b/app/src/main/java/com/anytypeio/anytype/ui/settings/DebugFragment.kt @@ -0,0 +1,93 @@ +package com.anytypeio.anytype.ui.settings + +import android.net.Uri +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.runtime.LaunchedEffect +import androidx.fragment.app.viewModels +import androidx.fragment.compose.content +import com.anytypeio.anytype.core_utils.tools.ZIP_MIME_TYPE +import com.anytypeio.anytype.core_utils.tools.zipDirectory +import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment +import com.anytypeio.anytype.di.common.componentManager +import com.anytypeio.anytype.presentation.settings.DebugViewModel +import java.io.File +import java.io.FileInputStream +import java.io.IOException +import javax.inject.Inject +import kotlin.getValue + +class DebugFragment : BaseBottomSheetComposeFragment() { + + private val createFileLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument(ZIP_MIME_TYPE)) { uri -> + uri?.let { saveZipToUri(it) } + } + + @Inject + lateinit var factory: DebugViewModel.Factory + + private val vm by viewModels { factory } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View = content { + DebugScreen( + onExportAllClicked = vm::onExportWorkingDirectory + ) + LaunchedEffect(Unit) { + vm.commands.collect { cmd -> + when(cmd) { + is DebugViewModel.Command.ExportWorkingDirectory -> { + proceedWithZippingAndSharingWorkDirectory( + folderName = cmd.folderName, + exportFileName = cmd.exportFileName + ) + } + } + } + } + } + + private fun proceedWithZippingAndSharingWorkDirectory( + folderName: String, + exportFileName: String + ) { + val folder = File( + requireContext().filesDir, + folderName + ) + val zipped = File( + requireContext().cacheDir, + DebugViewModel.EXPORT_WORK_DIRECTORY_TEMP_FOLDER + ) + zipDirectory( + sourceDir = folder, + zipFile = zipped + ) + createFileLauncher.launch(exportFileName) + } + + private fun saveZipToUri(uri: Uri) { + try { + requireContext().contentResolver.openOutputStream(uri)?.use { outputStream -> + val zipFile = File(requireContext().cacheDir, DebugViewModel.EXPORT_WORK_DIRECTORY_TEMP_FOLDER) + FileInputStream(zipFile).use { it.copyTo(outputStream) } + } + } catch (e: IOException) { + e.printStackTrace() + } + } + + override fun injectDependencies() { + componentManager().debugComponent.get().inject(this) + } + + override fun releaseDependencies() { + componentManager().debugComponent.release() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/settings/DebugScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/settings/DebugScreen.kt new file mode 100644 index 0000000000..4379ad8963 --- /dev/null +++ b/app/src/main/java/com/anytypeio/anytype/ui/settings/DebugScreen.kt @@ -0,0 +1,78 @@ +package com.anytypeio.anytype.ui.settings + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +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.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.anytypeio.anytype.core_ui.common.DefaultPreviews +import com.anytypeio.anytype.core_ui.foundation.Dragger +import com.anytypeio.anytype.core_ui.foundation.Header + +import com.anytypeio.anytype.R +import com.anytypeio.anytype.core_ui.foundation.Divider +import com.anytypeio.anytype.core_ui.views.BodyRegular + +@Composable +fun DebugScreen( + onExportAllClicked: () -> Unit +) { + Column( + modifier = Modifier.fillMaxSize() + ) { + Dragger( + modifier = Modifier + .align(Alignment.CenterHorizontally) + .padding(vertical = 6.dp) + ) + Header( + text = stringResource(R.string.debug) + ) + + Spacer(modifier = Modifier.height(10.dp)) + + ActionItem( + title = "Export work directory", + onClick = onExportAllClicked + ) + + Divider() + + } +} + +@Composable +private fun ActionItem( + title: String, + onClick: () -> Unit +) { + Text( + text = title, + style = BodyRegular, + color = colorResource(R.color.text_primary), + modifier = Modifier + .fillMaxWidth() + .padding(20.dp) + .clickable { + onClick() + } + ) +} + +@DefaultPreviews +@Composable +fun DebugScreenPreview() { + DebugScreen( + onExportAllClicked = {} + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/settings/ProfileSettingsFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/settings/ProfileSettingsFragment.kt index 99867b116c..c6aff8ba4b 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/settings/ProfileSettingsFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/settings/ProfileSettingsFragment.kt @@ -5,7 +5,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia import androidx.compose.material.MaterialTheme import androidx.compose.runtime.collectAsState @@ -121,7 +120,14 @@ class ProfileSettingsFragment : BaseBottomSheetComposeFragment() { } } ), - clearProfileImage = { vm.onClearProfileImage() } + clearProfileImage = { vm.onClearProfileImage() }, + onDebugClicked = { + runCatching { + findNavController().navigate(R.id.debugScreen) + } + }, + isDebugEnabled = vm.isDebugEnabled.collectAsStateWithLifecycle().value, + onHeaderTitleClicked = vm::onHeaderTitleClicked ) } } diff --git a/app/src/main/res/navigation/graph.xml b/app/src/main/res/navigation/graph.xml index 1dec7c401f..060abc2806 100644 --- a/app/src/main/res/navigation/graph.xml +++ b/app/src/main/res/navigation/graph.xml @@ -450,6 +450,12 @@ android:name="com.anytypeio.anytype.ui.settings.DebugSettingsFragment" android:label="DebugSettingsFragment" tools:layout="@layout/fragment_debug_settings" /> + + + = emptyList(), val isRelativeDates: Boolean, val dateFormat: String ) { companion object { fun default() : VaultSettings = VaultSettings( - showIntroduceVault = false, orderOfSpaces = emptyList(), isRelativeDates = DEFAULT_RELATIVE_DATES, dateFormat = FALLBACK_DATE_PATTERN diff --git a/core-utils/src/main/java/com/anytypeio/anytype/core_utils/tools/IO.kt b/core-utils/src/main/java/com/anytypeio/anytype/core_utils/tools/IO.kt new file mode 100644 index 0000000000..ab11649336 --- /dev/null +++ b/core-utils/src/main/java/com/anytypeio/anytype/core_utils/tools/IO.kt @@ -0,0 +1,21 @@ +package com.anytypeio.anytype.core_utils.tools + +import java.io.File +import java.io.FileOutputStream +import java.util.zip.ZipEntry +import java.util.zip.ZipOutputStream + +fun zipDirectory(sourceDir: File, zipFile: File) { + ZipOutputStream(FileOutputStream(zipFile)).use { zipOut -> + sourceDir.walkTopDown().forEach { file -> + if (file.isFile) { + val entryName = sourceDir.toURI().relativize(file.toURI()).path + zipOut.putNextEntry(ZipEntry(entryName)) + file.inputStream().use { it.copyTo(zipOut) } + zipOut.closeEntry() + } + } + } +} + +const val ZIP_MIME_TYPE = "application/zip" \ No newline at end of file diff --git a/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileScreen.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileScreen.kt index 7b7973c63c..af96e61ce8 100644 --- a/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileScreen.kt +++ b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileScreen.kt @@ -74,6 +74,7 @@ fun ProfileSettingsScreen( onKeychainPhraseClicked: () -> Unit, onLogoutClicked: () -> Unit, isLogoutInProgress: Boolean, + isDebugEnabled: Boolean, onNameChange: (String) -> Unit, onProfileIconClick: () -> Unit, account: AccountProfile, @@ -84,7 +85,9 @@ fun ProfileSettingsScreen( onMembershipClicked: () -> Unit, membershipStatus: MembershipStatus?, showMembership: ShowMembership?, - clearProfileImage: () -> Unit + clearProfileImage: () -> Unit, + onDebugClicked: () -> Unit, + onHeaderTitleClicked: () -> Unit ) { LazyColumn( modifier = Modifier @@ -97,7 +100,8 @@ fun ProfileSettingsScreen( account = account, onNameSet = onNameChange, onProfileIconClick = onProfileIconClick, - clearProfileImage = clearProfileImage + clearProfileImage = clearProfileImage, + onTitleClicked = onHeaderTitleClicked ) } item { @@ -163,6 +167,18 @@ fun ProfileSettingsScreen( onClick = onAboutClicked ) } + if (isDebugEnabled) { + item { + Divider(paddingStart = 60.dp) + } + item { + Option( + image = R.drawable.ic_debug, + text = stringResource(R.string.debug), + onClick = onDebugClicked + ) + } + } item { Divider(paddingStart = 60.dp) } @@ -277,7 +293,8 @@ private fun Header( account: AccountProfile, onProfileIconClick: () -> Unit, onNameSet: (String) -> Unit, - clearProfileImage: () -> Unit + clearProfileImage: () -> Unit, + onTitleClicked: () -> Unit ) { when (account) { is AccountProfile.Data -> { @@ -285,7 +302,7 @@ private fun Header( Dragger() } Box(modifier = modifier.padding(top = 12.dp, bottom = 28.dp)) { - ProfileTitleBlock() + ProfileTitleBlock(onTitleClicked) } Box(modifier = modifier.padding(bottom = 16.dp)) { ProfileImageBlock( @@ -389,11 +406,16 @@ fun ProfileNameBlock( } @Composable -fun ProfileTitleBlock() { +fun ProfileTitleBlock( + onClick: () -> Unit +) { Text( text = stringResource(R.string.profile), style = Title1, - color = colorResource(id = R.color.text_primary) + color = colorResource(id = R.color.text_primary), + modifier = Modifier.noRippleClickable { + onClick() + } ) } @@ -519,7 +541,10 @@ private fun ProfileSettingPreview() { onMembershipClicked = {}, membershipStatus = null, showMembership = ShowMembership(true), - clearProfileImage = {} + clearProfileImage = {}, + onDebugClicked = {}, + isDebugEnabled = true, + onHeaderTitleClicked = {} ) } diff --git a/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileSettingsViewModel.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileSettingsViewModel.kt index 05daf9efff..d51ec91143 100644 --- a/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileSettingsViewModel.kt +++ b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileSettingsViewModel.kt @@ -48,11 +48,15 @@ class ProfileSettingsViewModel( private val jobs = mutableListOf() + private var headerTitleClickCount = 0 + val isLoggingOut = MutableStateFlow(false) val debugSyncReportUri = MutableStateFlow(null) val membershipStatusState = MutableStateFlow(null) val showMembershipState = MutableStateFlow(null) + val isDebugEnabled = MutableStateFlow(false) + val profileData = profileContainer.observe().map { obj -> AccountProfile.Data( name = obj.name.orEmpty(), @@ -166,6 +170,13 @@ class ProfileSettingsViewModel( } } + fun onHeaderTitleClicked() { + headerTitleClickCount = headerTitleClickCount + 1 + if (headerTitleClickCount >= ENABLE_DEBUG_MENU_CLICK_COUNT && isDebugEnabled.value == false) { + isDebugEnabled.value = true + } + } + class Factory( private val analytics: Analytics, private val container: StorelessSubscriptionContainer, @@ -194,6 +205,10 @@ class ProfileSettingsViewModel( ) as T } } + + companion object { + const val ENABLE_DEBUG_MENU_CLICK_COUNT = 5 + } } private const val STOP_SUBSCRIPTION_TIMEOUT = 1_000L diff --git a/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultUserSettingsCache.kt b/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultUserSettingsCache.kt index 1c46e3a8bd..20b671b18e 100644 --- a/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultUserSettingsCache.kt +++ b/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultUserSettingsCache.kt @@ -417,9 +417,8 @@ class DefaultUserSettingsCache( ) VaultSettings( orderOfSpaces = curr.orderOfSpaces, - showIntroduceVault = curr.showIntroduceVault, isRelativeDates = curr.isRelativeDates, - dateFormat = curr.dateFormat ?: appDefaultDateFormatProvider.provide() + dateFormat = curr.dateFormat ?: appDefaultDateFormatProvider.provide(), ) } .first() @@ -435,7 +434,6 @@ class DefaultUserSettingsCache( ) VaultSettings( orderOfSpaces = curr.orderOfSpaces, - showIntroduceVault = curr.showIntroduceVault, isRelativeDates = curr.isRelativeDates, dateFormat = curr.dateFormat ?: appDefaultDateFormatProvider.provide() ) @@ -464,7 +462,6 @@ class DefaultUserSettingsCache( preferences = existingPreferences.preferences + mapOf( account.id to VaultPreference( orderOfSpaces = settings.orderOfSpaces, - showIntroduceVault = settings.showIntroduceVault ) ) ) diff --git a/persistence/src/main/proto/preferences.proto b/persistence/src/main/proto/preferences.proto index 7e5b3e8e6f..8c2136f349 100644 --- a/persistence/src/main/proto/preferences.proto +++ b/persistence/src/main/proto/preferences.proto @@ -15,6 +15,7 @@ message VaultPreferences { message VaultPreference { repeated string orderOfSpaces = 1; + // deprecated bool showIntroduceVault = 2; bool isRelativeDates = 3; optional string dateFormat = 4; diff --git a/persistence/src/test/java/com/anytypeio/anytype/persistence/UserSettingsCacheTest.kt b/persistence/src/test/java/com/anytypeio/anytype/persistence/UserSettingsCacheTest.kt index 82c7772d27..9a122ecb52 100644 --- a/persistence/src/test/java/com/anytypeio/anytype/persistence/UserSettingsCacheTest.kt +++ b/persistence/src/test/java/com/anytypeio/anytype/persistence/UserSettingsCacheTest.kt @@ -362,7 +362,6 @@ class UserSettingsCacheTest { val vaultSettings = cache.getVaultSettings(account = account) val expected = VaultSettings( - showIntroduceVault = DEFAULT_SHOW_INTRODUCE_VAULT, dateFormat = dateFormat, isRelativeDates = DEFAULT_RELATIVE_DATES ) @@ -399,7 +398,6 @@ class UserSettingsCacheTest { val vaultSettings = cache.getVaultSettings(account = account) val expected = VaultSettings( - showIntroduceVault = DEFAULT_SHOW_INTRODUCE_VAULT, dateFormat = updatedDateFormat, isRelativeDates = DEFAULT_RELATIVE_DATES ) @@ -435,7 +433,6 @@ class UserSettingsCacheTest { val vaultSettings = cache.getVaultSettings(account = account) val expected = VaultSettings( - showIntroduceVault = DEFAULT_SHOW_INTRODUCE_VAULT, dateFormat = dateFormat, isRelativeDates = false ) @@ -477,7 +474,6 @@ class UserSettingsCacheTest { val vaultSettings = cache.getVaultSettings(account = account) val expected = VaultSettings( - showIntroduceVault = DEFAULT_SHOW_INTRODUCE_VAULT, dateFormat = updatedDateFormat, isRelativeDates = false ) diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/DebugViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/DebugViewModel.kt new file mode 100644 index 0000000000..2a76390468 --- /dev/null +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/DebugViewModel.kt @@ -0,0 +1,55 @@ +package com.anytypeio.anytype.presentation.settings + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import com.anytypeio.anytype.domain.auth.interactor.GetAccount +import com.anytypeio.anytype.domain.base.onSuccess +import com.anytypeio.anytype.presentation.common.BaseViewModel +import javax.inject.Inject +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.launch + +class DebugViewModel @Inject constructor( + private val getAccount: GetAccount, +) : BaseViewModel() { + + val commands = MutableSharedFlow(replay = 0) + + fun onExportWorkingDirectory() { + viewModelScope.launch { + getAccount + .async(Unit) + .onSuccess { account -> + commands.emit( + Command.ExportWorkingDirectory( + folderName = account.id, + exportFileName = "anytype-${account.id}.zip" + ) + ) + } + } + } + + class Factory @Inject constructor( + private val getAccount: GetAccount + ) : ViewModelProvider.Factory { + @Suppress("UNCHECKED_CAST") + override fun create(modelClass: Class): T { + return DebugViewModel( + getAccount = getAccount + ) as T + } + } + + sealed class Command { + data class ExportWorkingDirectory( + val folderName: String, + val exportFileName: String + ): Command() + } + + companion object { + const val EXPORT_WORK_DIRECTORY_TEMP_FOLDER = "anytype-work-directory.zip" + } +} \ No newline at end of file