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:
parent
699ab04f29
commit
9e46bcdc9f
12 changed files with 116 additions and 38 deletions
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) },
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 -> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
|
@ -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 = {}
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
|
|
|
@ -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>
|
Loading…
Add table
Add a link
Reference in a new issue