1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

DROID-1814 Settings | Fix | Redesign and other fixes (#494)

This commit is contained in:
Evgenii Kozlov 2023-11-01 17:44:15 +01:00 committed by GitHub
parent 699ab04f29
commit 9e46bcdc9f
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 116 additions and 38 deletions

View file

@ -5,6 +5,7 @@ import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
import com.anytypeio.anytype.device.BuildProvider
import com.anytypeio.anytype.di.common.ComponentDependencies
import com.anytypeio.anytype.domain.account.DeleteAccount
import com.anytypeio.anytype.domain.auth.interactor.GetAccount
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
@ -100,6 +101,14 @@ object FilesStorageModule {
dispatchers: AppCoroutineDispatchers
): GetAccount = GetAccount(repo = repo, dispatcher = dispatchers)
@JvmStatic
@Provides
@PerScreen
fun provideDeleteAccountUseCase(
repo: AuthRepository,
dispatchers: AppCoroutineDispatchers
): DeleteAccount = DeleteAccount(repo = repo)
@Module
interface Declarations {

View file

@ -16,8 +16,8 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.`object`.SetObjectDetails
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider
import com.anytypeio.anytype.ui.settings.ProfileFragment
import com.anytypeio.anytype.ui_settings.account.ProfileViewModel
import com.anytypeio.anytype.ui.settings.ProfileSettingsFragment
import com.anytypeio.anytype.ui_settings.account.ProfileSettingsViewModel
import dagger.Module
import dagger.Provides
import dagger.Subcomponent
@ -32,7 +32,7 @@ interface ProfileSubComponent {
fun build(): ProfileSubComponent
}
fun inject(fragment: ProfileFragment)
fun inject(fragment: ProfileSettingsFragment)
}
@Module(includes = [ProfileModule.Bindings::class])
@ -50,7 +50,7 @@ object ProfileModule {
urlBuilder: UrlBuilder,
setDocumentImageIcon: SetDocumentImageIcon,
spaceGradientProvider: SpaceGradientProvider
): ProfileViewModel.Factory = ProfileViewModel.Factory(
): ProfileSettingsViewModel.Factory = ProfileSettingsViewModel.Factory(
deleteAccount = deleteAccount,
analytics = analytics,
storelessSubscriptionContainer = storelessSubscriptionContainer,

View file

@ -27,6 +27,7 @@ import com.anytypeio.anytype.core_utils.ui.proceed
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.presentation.settings.FilesStorageViewModel
import com.anytypeio.anytype.presentation.settings.FilesStorageViewModel.Event
import com.anytypeio.anytype.ui.auth.account.DeleteAccountWarning
import com.anytypeio.anytype.ui.dashboard.ClearCacheAlertFragment
import com.anytypeio.anytype.ui_settings.fstorage.LocalStorageScreen
import com.anytypeio.anytype.ui_settings.fstorage.RemoteStorageScreen
@ -63,7 +64,8 @@ class FilesStorageFragment : BaseBottomSheetComposeFragment() {
} else {
LocalStorageScreen(
data = vm.state.collectAsStateWithLifecycle().value,
onOffloadFilesClicked = { throttle { vm.event(Event.OnOffloadFilesClicked) } }
onOffloadFilesClicked = { throttle { vm.event(Event.OnOffloadFilesClicked) } },
onDeleteAccountClicked = { proceedWithAccountDeletion() }
)
}
}
@ -130,6 +132,16 @@ class FilesStorageFragment : BaseBottomSheetComposeFragment() {
)
}
private fun proceedWithAccountDeletion() {
vm.proceedWithAccountDeletion()
val dialog = DeleteAccountWarning()
dialog.onDeletionAccepted = {
dialog.dismiss()
vm.onDeleteAccountClicked()
}
dialog.show(childFragmentManager, null)
}
private fun generateSupportMail(
account: Id,
name: String,

View file

@ -32,20 +32,20 @@ import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.ui.auth.account.DeleteAccountWarning
import com.anytypeio.anytype.ui.profile.KeychainPhraseDialog
import com.anytypeio.anytype.ui_settings.account.ProfileScreen
import com.anytypeio.anytype.ui_settings.account.ProfileViewModel
import com.anytypeio.anytype.ui_settings.account.ProfileSettingsScreen
import com.anytypeio.anytype.ui_settings.account.ProfileSettingsViewModel
import javax.inject.Inject
import timber.log.Timber
class ProfileFragment : BaseBottomSheetComposeFragment() {
class ProfileSettingsFragment : BaseBottomSheetComposeFragment() {
@Inject
lateinit var factory: ProfileViewModel.Factory
lateinit var factory: ProfileSettingsViewModel.Factory
@Inject
lateinit var toggles: FeatureToggles
private val vm by viewModels<ProfileViewModel> { factory }
private val vm by viewModels<ProfileSettingsViewModel> { factory }
private val onKeychainPhraseClicked = {
val bundle =
@ -74,9 +74,8 @@ class ProfileFragment : BaseBottomSheetComposeFragment() {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme(typography = typography) {
ProfileScreen(
ProfileSettingsScreen(
onKeychainPhraseClicked = onKeychainPhraseClicked,
onDeleteAccountClicked = { throttle { proceedWithAccountDeletion() } },
onLogoutClicked = onLogoutClicked,
isLogoutInProgress = vm.isLoggingOut.collectAsState().value,
onNameChange = { vm.onNameChange(it) },

View file

@ -228,7 +228,7 @@
<dialog
android:id="@+id/profileScreen"
android:name="com.anytypeio.anytype.ui.settings.ProfileFragment">
android:name="com.anytypeio.anytype.ui.settings.ProfileSettingsFragment">
</dialog>
<dialog

View file

@ -18,6 +18,7 @@ import com.anytypeio.anytype.core_utils.ext.bytesToHumanReadableSizeLocal
import com.anytypeio.anytype.core_utils.ext.cancel
import com.anytypeio.anytype.core_utils.ext.throttleFirst
import com.anytypeio.anytype.device.BuildProvider
import com.anytypeio.anytype.domain.account.DeleteAccount
import com.anytypeio.anytype.domain.auth.interactor.GetAccount
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.BaseUseCase
@ -31,7 +32,9 @@ import com.anytypeio.anytype.domain.search.PROFILE_SUBSCRIPTION_ID
import com.anytypeio.anytype.domain.workspace.FileSpaceUsage
import com.anytypeio.anytype.domain.workspace.InterceptFileLimitEvents
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.common.BaseViewModel
import com.anytypeio.anytype.presentation.extension.sendGetMoreSpaceEvent
import com.anytypeio.anytype.presentation.extension.sendScreenSettingsDeleteEvent
import com.anytypeio.anytype.presentation.extension.sendSettingsOffloadEvent
import com.anytypeio.anytype.presentation.extension.sendSettingsStorageEvent
import com.anytypeio.anytype.presentation.extension.sendSettingsStorageManageEvent
@ -65,8 +68,9 @@ class FilesStorageViewModel(
private val fileSpaceUsage: FileSpaceUsage,
private val interceptFileLimitEvents: InterceptFileLimitEvents,
private val buildProvider: BuildProvider,
private val getAccount: GetAccount
) : ViewModel() {
private val getAccount: GetAccount,
private val deleteAccount: DeleteAccount
) : BaseViewModel() {
val events = MutableSharedFlow<Event>(replay = 0)
val commands = MutableSharedFlow<Command>(replay = 0)
@ -76,7 +80,6 @@ class FilesStorageViewModel(
private val _state = MutableStateFlow(ScreenState.empty())
val state: StateFlow<ScreenState> = _state
val toasts = MutableSharedFlow<String>(replay = 0)
private val jobs = mutableListOf<Job>()
@ -168,7 +171,7 @@ class FilesStorageViewModel(
is Interactor.Status.Error -> {
isClearFileCacheInProgress.value = false
Timber.e(status.throwable, "Error while clearing file cache")
toasts.emit("Error while clearing the file cache")
sendToast("Error while clearing the file cache")
}
Interactor.Status.Success -> {
viewModelScope.sendEvent(
@ -317,6 +320,32 @@ class FilesStorageViewModel(
}
}
fun proceedWithAccountDeletion() {
viewModelScope.launch {
analytics.sendScreenSettingsDeleteEvent()
}
}
fun onDeleteAccountClicked() {
Timber.d("onDeleteAccountClicked, ")
jobs += viewModelScope.launch {
deleteAccount(BaseUseCase.None).process(
success = {
sendEvent(
analytics = analytics,
eventName = EventsDictionary.deleteAccount
)
Timber.d("Successfully deleted account, status")
},
failure = {
Timber.e(it, "Error while deleting account").also {
sendToast("Error while deleting account")
}
}
)
}
}
sealed class Event {
object OnManageFilesClicked : Event()
object OnOffloadFilesClicked : Event()
@ -340,7 +369,8 @@ class FilesStorageViewModel(
private val fileSpaceUsage: FileSpaceUsage,
private val interceptFileLimitEvents: InterceptFileLimitEvents,
private val buildProvider: BuildProvider,
private val getAccount: GetAccount
private val getAccount: GetAccount,
private val deleteAccount: DeleteAccount
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
@ -356,7 +386,8 @@ class FilesStorageViewModel(
fileSpaceUsage = fileSpaceUsage,
interceptFileLimitEvents = interceptFileLimitEvents,
buildProvider = buildProvider,
getAccount = getAccount
getAccount = getAccount,
deleteAccount = deleteAccount
) as T
}

View file

@ -63,14 +63,13 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
@Composable
fun ProfileScreen(
fun ProfileSettingsScreen(
onKeychainPhraseClicked: () -> Unit,
onDeleteAccountClicked: () -> Unit,
onLogoutClicked: () -> Unit,
isLogoutInProgress: Boolean,
onNameChange: (String) -> Unit,
onProfileIconClick: () -> Unit,
account: ProfileViewModel.AccountProfile,
account: ProfileSettingsViewModel.AccountProfile,
onAppearanceClicked: () -> Unit,
onDataManagementClicked: () -> Unit,
onAboutClicked: () -> Unit
@ -106,6 +105,7 @@ fun ProfileScreen(
text = stringResource(R.string.about),
onClick = onAboutClicked
)
Divider(paddingStart = 60.dp)
Section(stringResource(R.string.access))
Option(
image = R.drawable.ic_keychain_phrase,
@ -113,13 +113,6 @@ fun ProfileScreen(
onClick = onKeychainPhraseClicked
)
Divider(paddingStart = 60.dp)
Section(stringResource(R.string.account))
Action(
name = stringResource(R.string.delete_account),
color = colorResource(R.color.text_primary),
onClick = onDeleteAccountClicked
)
Divider()
ActionWithProgressBar(
name = stringResource(R.string.log_out),
color = colorResource(R.color.palette_dark_red),
@ -252,12 +245,12 @@ fun ActionWithProgressBar(
@Composable
private fun Header(
modifier: Modifier = Modifier,
account: ProfileViewModel.AccountProfile,
account: ProfileSettingsViewModel.AccountProfile,
onProfileIconClick: () -> Unit,
onNameSet: (String) -> Unit
) {
when (account) {
is ProfileViewModel.AccountProfile.Data -> {
is ProfileSettingsViewModel.AccountProfile.Data -> {
Box(modifier = modifier.padding(vertical = 6.dp)) {
Dragger()
}
@ -273,7 +266,7 @@ private fun Header(
}
ProfileNameBlock(name = account.name, onNameSet = onNameSet)
}
is ProfileViewModel.AccountProfile.Idle -> {}
is ProfileSettingsViewModel.AccountProfile.Idle -> {}
}
}

View file

@ -32,7 +32,7 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import timber.log.Timber
class ProfileViewModel(
class ProfileSettingsViewModel(
private val analytics: Analytics,
private val deleteAccount: DeleteAccount,
private val storelessSubscriptionContainer: StorelessSubscriptionContainer,
@ -168,7 +168,7 @@ class ProfileViewModel(
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ProfileViewModel(
return ProfileSettingsViewModel(
deleteAccount = deleteAccount,
analytics = analytics,
storelessSubscriptionContainer = storelessSubscriptionContainer,

View file

@ -36,6 +36,7 @@ import com.anytypeio.anytype.core_ui.views.BodyCalloutMedium
import com.anytypeio.anytype.core_ui.views.BodyCalloutRegular
import com.anytypeio.anytype.core_ui.views.ButtonSecondary
import com.anytypeio.anytype.core_ui.views.ButtonSize
import com.anytypeio.anytype.core_ui.views.ButtonWarning
import com.anytypeio.anytype.core_ui.views.PreviewTitle2Medium
import com.anytypeio.anytype.core_ui.views.Relations3
import com.anytypeio.anytype.core_ui.views.Title1
@ -48,7 +49,8 @@ import com.anytypeio.anytype.ui_settings.main.SpaceImageBlock
@Composable
fun LocalStorageScreen(
data: ScreenState,
onOffloadFilesClicked: () -> Unit
onOffloadFilesClicked: () -> Unit,
onDeleteAccountClicked: () -> Unit
) {
Card(
modifier = Modifier.fillMaxSize(),
@ -68,7 +70,13 @@ fun LocalStorageScreen(
) {
Dragger()
}
Header(stringResource(id = R.string.local_storage))
Header(stringResource(id = R.string.data_management))
Spacer(modifier = Modifier.height(24.dp))
Text(
text = stringResource(id = R.string.local_storage),
style = Title1,
color = colorResource(id = R.color.text_primary)
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = stringResource(id = R.string.in_order_to_save),
@ -127,6 +135,28 @@ fun LocalStorageScreen(
contentPadding = PaddingValues(12.dp, 7.dp, 12.dp, 7.dp)
}
)
Spacer(modifier = Modifier.height(24.dp))
Text(
text = stringResource(id = R.string.danger_zone),
style = Title1,
color = colorResource(id = R.color.text_primary)
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = stringResource(id = R.string.deleted_account_danger_zone_msg),
style = BodyCalloutRegular,
color = colorResource(id = R.color.text_primary),
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(12.dp))
ButtonWarning(
text = stringResource(id = R.string.delete_account),
onClick = onDeleteAccountClicked,
size = ButtonSize.SmallSecondary.apply {
contentPadding = PaddingValues(12.dp, 7.dp, 12.dp, 7.dp)
}
)
Spacer(modifier = Modifier.height(24.dp))
}
}
}
@ -304,7 +334,8 @@ fun PreviewRemoteStorageScreen() {
fun PreviewLocalStorageScreen() {
LocalStorageScreen(
data = mockData,
onOffloadFilesClicked = {}
onOffloadFilesClicked = {},
onDeleteAccountClicked = {}
)
}

View file

@ -40,6 +40,7 @@ import com.anytypeio.anytype.presentation.settings.MainSettingsViewModel
import com.anytypeio.anytype.presentation.spaces.SpaceIconView
import com.anytypeio.anytype.ui_settings.R
@Deprecated("To be deleted")
@Composable
fun MainSettingScreen(
workspace: MainSettingsViewModel.WorkspaceAndAccount,

View file

@ -105,7 +105,7 @@ fun SpaceNameBlock(
@Composable
fun SpaceNameBlock() {
Text(
text = stringResource(id = R.string.personal_space),
text = stringResource(id = R.string.space_settings),
style = Title1,
color = colorResource(id = R.color.text_primary)
)

View file

@ -69,4 +69,6 @@
<string name="account_name">Account name</string>
<string name="space_settings">Space settings</string>
<string name="data_management">Data management</string>
<string name="deleted_account_danger_zone_msg">Once you request your account to be deleted, you have 30 days to cancel this request. After 30 days, your encrypted account data is permanently removed from the backup node, you won\'t be able to sign into Anytype on new devices.</string>
<string name="danger_zone">Danger zone</string>
</resources>