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

DROID-3375 New settings | Enhancement | Settings as fullscreen fragment + Navigation to remote storage + Delete space UX + other misc. fixes (#2161)

This commit is contained in:
Evgenii Kozlov 2025-03-14 16:44:39 +01:00 committed by GitHub
parent 0475183585
commit 29c43b0cfc
Signed by: github
GPG key ID: B5690EEEBB952194
8 changed files with 114 additions and 92 deletions

View file

@ -6,21 +6,20 @@ import android.view.View
import android.view.ViewGroup
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.res.colorResource
import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels
import androidx.fragment.compose.content
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.fragment.findNavController
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.core_ui.common.ComposeDialogView
import com.anytypeio.anytype.core_utils.ext.arg
import com.anytypeio.anytype.core_utils.ext.shareFile
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
import com.anytypeio.anytype.core_utils.ui.BaseComposeFragment
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.presentation.spaces.SpaceSettingsViewModel
import com.anytypeio.anytype.presentation.spaces.SpaceSettingsViewModel.Command
@ -29,6 +28,7 @@ import com.anytypeio.anytype.ui.multiplayer.LeaveSpaceWarning
import com.anytypeio.anytype.ui.multiplayer.ShareSpaceFragment
import com.anytypeio.anytype.ui.objects.types.pickers.AppDefaultObjectTypeFragment
import com.anytypeio.anytype.ui.objects.types.pickers.ObjectTypeSelectionListener
import com.anytypeio.anytype.ui.settings.SpacesStorageFragment
import com.anytypeio.anytype.ui.settings.typography
import com.anytypeio.anytype.ui.spaces.DeleteSpaceWarning
import com.anytypeio.anytype.ui_settings.space.new_settings.SpaceSettingsContainer
@ -36,8 +36,7 @@ import java.io.File
import javax.inject.Inject
import timber.log.Timber
// TODO convert to Fragment.
class SpaceSettingsFragment : BaseBottomSheetComposeFragment(), ObjectTypeSelectionListener {
class SpaceSettingsFragment : BaseComposeFragment(), ObjectTypeSelectionListener {
private val space get() = arg<Id>(ARG_SPACE_ID_KEY)
@ -51,31 +50,26 @@ class SpaceSettingsFragment : BaseBottomSheetComposeFragment(), ObjectTypeSelect
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
) = ComposeDialogView(
context = requireContext(), dialog = requireDialog()
).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme(
typography = typography,
colors = MaterialTheme.colors.copy(
surface = colorResource(id = R.color.context_menu_background)
)
) {
SpaceSettingsContainer(
uiState = vm.uiState.collectAsStateWithLifecycle().value,
uiEvent = vm::onUiEvent
)
LaunchedEffect(Unit) { vm.toasts.collect { toast(it) } }
LaunchedEffect(Unit) {
vm.isDismissed.collect { isDismissed ->
if (isDismissed) dismiss()
}
}
LaunchedEffect(Unit) {
observeCommands()
) = content {
MaterialTheme(
typography = typography,
colors = MaterialTheme.colors.copy(
surface = colorResource(id = R.color.context_menu_background)
)
) {
SpaceSettingsContainer(
uiState = vm.uiState.collectAsStateWithLifecycle().value,
uiEvent = vm::onUiEvent
)
LaunchedEffect(Unit) { vm.toasts.collect { toast(it) } }
LaunchedEffect(Unit) {
vm.isDismissed.collect { isDismissed ->
if (isDismissed) findNavController().popBackStack()
}
}
LaunchedEffect(Unit) {
observeCommands()
}
}
}
@ -170,6 +164,16 @@ class SpaceSettingsFragment : BaseBottomSheetComposeFragment(), ObjectTypeSelect
Timber.e(it, "Error while opening set-default-object-type screen")
}
}
is Command.ManageRemoteStorage -> {
runCatching {
findNavController().navigate(
resId = R.id.spacesStorageScreen,
args = SpacesStorageFragment.args(space = space)
)
}.onFailure {
Timber.e(it, "Failed to execute nav command: $command")
}
}
}
}
}
@ -180,8 +184,6 @@ class SpaceSettingsFragment : BaseBottomSheetComposeFragment(), ObjectTypeSelect
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
expand()
skipCollapsed()
}
override fun injectDependencies() {
@ -193,6 +195,10 @@ class SpaceSettingsFragment : BaseBottomSheetComposeFragment(), ObjectTypeSelect
componentManager().spaceSettingsComponent.release()
}
override fun onApplyWindowRootInsets(view: View) {
// Do nothing. Compose code will handle insets.
}
companion object {
const val ARG_SPACE_ID_KEY = "arg.space-settings.space-id"
fun args(space: SpaceId) = bundleOf(ARG_SPACE_ID_KEY to space.id)

View file

@ -307,7 +307,7 @@
android:name="com.anytypeio.anytype.ui.vault.IntroduceVaultFragment"
android:label="IntroduceVaultScreen"/>
<dialog
<fragment
android:id="@+id/spaceSettingsScreen"
android:name="com.anytypeio.anytype.ui.settings.space.SpaceSettingsFragment"
android:label="SpaceSettingsScreen"/>

View file

@ -84,7 +84,8 @@ fun NewSpaceIcon(
}
},
text = stringResource(R.string.space_settings_icon_title),
style = Caption1Medium
style = Caption1Medium,
color = colorResource(R.color.text_secondary)
)
MaterialTheme(
shapes = MaterialTheme.shapes.copy(medium = RoundedCornerShape(10.dp))

View file

@ -235,6 +235,16 @@ fun SpaceInfoItem(
)
}
@Composable
fun RemoteStorageItem(
modifier: Modifier = Modifier
) {
BaseButton(
modifier = modifier,
title = stringResource(id = R.string.remote_storage),
)
}
@Composable
fun DeleteSpaceItem(
modifier: Modifier = Modifier

View file

@ -5,7 +5,6 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.border
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.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
@ -135,6 +134,7 @@ fun NewSpaceSettingsScreen(
)
}
}
is UiSpaceSettingsItem.Name -> {
item {
NewSpaceNameInputField(
@ -149,8 +149,7 @@ fun NewSpaceSettingsScreen(
.animateItem()
.noRippleClickable {
showEditTitle = true
}
,
},
name = item.name,
isEditEnabled = false
)
@ -171,8 +170,7 @@ fun NewSpaceSettingsScreen(
.animateItem()
.noRippleClickable {
showEditDescription = true
}
,
},
isEditEnabled = false,
description = initialDescription
)
@ -192,6 +190,7 @@ fun NewSpaceSettingsScreen(
is UiSpaceSettingsItem.Chat -> {
// TODO
}
is UiSpaceSettingsItem.DefaultObjectType -> {
item {
DefaultTypeItem(
@ -199,8 +198,7 @@ fun NewSpaceSettingsScreen(
.fillMaxWidth()
.animateItem()
.clip(RoundedCornerShape(16.dp))
.clickable { uiEvent(UiEvent.OnDefaultObjectTypeClicked(item.id)) }
,
.clickable { uiEvent(UiEvent.OnDefaultObjectTypeClicked(item.id)) },
name = item.name,
icon = item.icon
)
@ -213,6 +211,8 @@ fun NewSpaceSettingsScreen(
modifier = Modifier
.fillMaxWidth()
.animateItem()
.clip(RoundedCornerShape(16.dp))
.clickable { uiEvent(UiEvent.OnDeleteSpaceClicked) },
)
}
}
@ -224,8 +224,7 @@ fun NewSpaceSettingsScreen(
.fillMaxWidth()
.animateItem()
.clip(RoundedCornerShape(16.dp))
.clickable { uiEvent(UiEvent.OnSpaceMembersClicked) }
,
.clickable { uiEvent(UiEvent.OnSpaceMembersClicked) },
item = item
)
}
@ -244,6 +243,7 @@ fun NewSpaceSettingsScreen(
)
}
}
UiSpaceSettingsItem.Fields -> {
item {
FieldsItem(
@ -257,9 +257,19 @@ fun NewSpaceSettingsScreen(
)
}
}
is UiSpaceSettingsItem.RemoteStorage -> {
// TODO
item {
RemoteStorageItem(
modifier = Modifier
.fillMaxWidth()
.animateItem()
.clip(RoundedCornerShape(16.dp))
.clickable { uiEvent(UiEvent.OnRemoteStorageClick) }
)
}
}
is UiSpaceSettingsItem.Section -> {
item {
SpaceSettingsSection(
@ -284,7 +294,6 @@ fun NewSpaceSettingsScreen(
)
}
}
is UiSpaceSettingsItem.Wallpapers -> {
item {
WallpaperItem(
@ -293,9 +302,8 @@ fun NewSpaceSettingsScreen(
.animateItem()
.clip(RoundedCornerShape(16.dp))
.clickable {
uiEvent(UiEvent.OnWallpaperClicked)
}
,
uiEvent(UiEvent.OnSelectWallpaperClicked)
},
item = item
)
}
@ -390,7 +398,11 @@ private fun EditNameField(
modifier = Modifier.fillMaxWidth(),
containerColor = colorResource(id = R.color.background_secondary),
topBar = {
Box(modifier = Modifier.fillMaxWidth().height(48.dp)) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(48.dp)
) {
Text(
modifier = Modifier
.align(Alignment.CenterEnd)
@ -433,8 +445,7 @@ private fun EditNameField(
width = 2.dp,
color = colorResource(id = R.color.palette_system_amber_50)
)
.padding(vertical = 12.dp, horizontal = 16.dp)
,
.padding(vertical = 12.dp, horizontal = 16.dp),
name = fieldInput,
onNameSet = { newName ->
fieldInput = newName
@ -458,7 +469,11 @@ private fun EditDescriptionField(
modifier = Modifier.fillMaxWidth(),
containerColor = colorResource(id = R.color.background_secondary),
topBar = {
Box(modifier = Modifier.fillMaxWidth().height(48.dp)) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(48.dp)
) {
Text(
modifier = Modifier
.align(Alignment.CenterEnd)
@ -501,8 +516,7 @@ private fun EditDescriptionField(
width = 2.dp,
color = colorResource(id = R.color.palette_system_amber_50)
)
.padding(vertical = 12.dp, horizontal = 16.dp)
,
.padding(vertical = 12.dp, horizontal = 16.dp),
description = fieldInput,
isEditEnabled = true,
onDescriptionSet = {

View file

@ -11,12 +11,8 @@ import com.anytypeio.anytype.analytics.base.sendEvent
import com.anytypeio.anytype.analytics.event.EventAnalytics
import com.anytypeio.anytype.analytics.props.Props
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Block.Content.DataView.Filter
import com.anytypeio.anytype.core_models.DVFilterCondition
import com.anytypeio.anytype.core_models.Filepath
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectTypeUniqueKeys
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Relations
@ -28,7 +24,6 @@ import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.core_models.primitives.TypeId
import com.anytypeio.anytype.core_models.primitives.TypeKey
import com.anytypeio.anytype.domain.base.fold
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.debugging.DebugSpaceShareDownloader
import com.anytypeio.anytype.domain.launch.GetDefaultObjectType
import com.anytypeio.anytype.domain.launch.SetDefaultObjectType
@ -42,18 +37,15 @@ import com.anytypeio.anytype.domain.multiplayer.sharedSpaceCount
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
import com.anytypeio.anytype.domain.payments.GetMembershipStatus
import com.anytypeio.anytype.domain.search.ProfileSubscriptionManager
import com.anytypeio.anytype.domain.search.SearchObjects
import com.anytypeio.anytype.domain.spaces.DeleteSpace
import com.anytypeio.anytype.domain.spaces.SetSpaceDetails
import com.anytypeio.anytype.domain.wallpaper.ObserveWallpaper
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.common.BaseViewModel
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.presentation.settings.PersonalizationSettingsViewModel
import com.anytypeio.anytype.presentation.spaces.UiSpaceSettingsItem.Spacer
import javax.inject.Inject
import kotlin.collections.map
import kotlin.collections.sortedBy
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
@ -212,6 +204,8 @@ class SpaceSettingsViewModel(
defaultObjectTypeSettingItem,
Spacer(height = 8),
UiSpaceSettingsItem.Wallpapers(current = wallpaper),
UiSpaceSettingsItem.Section.DataManagement,
UiSpaceSettingsItem.RemoteStorage,
UiSpaceSettingsItem.Section.Misc,
UiSpaceSettingsItem.SpaceInfo,
Spacer(height = 8),
@ -237,10 +231,16 @@ class SpaceSettingsViewModel(
isDismissed.value = true
}
UiEvent.OnDeleteSpaceClicked -> {
sendToast("Coming soon")
viewModelScope.launch {
commands.emit(
Command.ShowDeleteSpaceWarning
)
}
}
UiEvent.OnFileStorageClick -> {
sendToast("Coming soon")
UiEvent.OnRemoteStorageClick -> {
viewModelScope.launch {
commands.emit(Command.ManageRemoteStorage)
}
}
UiEvent.OnInviteClicked -> {
sendToast("Coming soon")
@ -275,13 +275,10 @@ class SpaceSettingsViewModel(
)
}
}
UiEvent.OnSpaceIdClicked -> {
sendToast("Coming soon")
}
is UiEvent.OnSpaceImagePicked -> {
proceedWithSettingSpaceImage(uiEvent.uri)
}
is UiEvent.OnWallpaperClicked -> {
is UiEvent.OnSelectWallpaperClicked -> {
viewModelScope.launch {
commands.emit(Command.OpenWallpaperPicker)
}
@ -380,27 +377,21 @@ class SpaceSettingsViewModel(
}
private fun proceedWithSpaceDeletion() {
// val state = spaceViewState.value as? SpaceData.Success ?: return
// val space = state.spaceId
// if (space != null) {
// viewModelScope.launch {
// deleteSpace.async(params = SpaceId(space)).fold(
// onSuccess = {
// analytics.sendEvent(
// eventName = EventsDictionary.deleteSpace,
// props = Props(mapOf(EventsPropertiesKey.type to "Private"))
// )
// spaceManager.clear()
// commands.emit(Command.ExitToVault)
// },
// onFailure = {
// Timber.e(it, "Error while deleting space")
// }
// )
// }
// } else {
// sendToast("Space not found. Please, try again later")
// }
viewModelScope.launch {
deleteSpace.async(params = vmParams.space).fold(
onSuccess = {
analytics.sendEvent(
eventName = EventsDictionary.deleteSpace,
props = Props(mapOf(EventsPropertiesKey.type to "Private"))
)
spaceManager.clear()
commands.emit(Command.ExitToVault)
},
onFailure = {
Timber.e(it, "Error while deleting space")
}
)
}
}
private fun proceedWithSpaceDebug() {
@ -634,6 +625,7 @@ class SpaceSettingsViewModel(
data object NavigateToMembership : Command()
data object NavigateToMembershipUpdate : Command()
data object OpenWallpaperPicker : Command()
data object ManageRemoteStorage : Command()
}
class Factory @Inject constructor(

View file

@ -8,17 +8,16 @@ sealed class UiEvent {
data class OnSaveDescriptionClicked(val description: String) : UiEvent()
data class OnSaveTitleClicked(val title: String) : UiEvent()
data class OnSpaceImagePicked(val uri: String) : UiEvent()
data object OnSelectWallpaperClicked : UiEvent()
data object OnSpaceMembersClicked : UiEvent()
data class OnDefaultObjectTypeClicked(val currentDefaultObjectTypeId: Id?) : UiEvent()
data object OnDeleteSpaceClicked : UiEvent()
data object OnFileStorageClick : UiEvent()
data object OnRemoteStorageClick : UiEvent()
data object OnPersonalizationClicked : UiEvent()
data object OnSpaceIdClicked : UiEvent()
data object OnInviteClicked : UiEvent()
data object OnQrCodeClicked : UiEvent()
data object OnWallpaperClicked : UiEvent()
sealed class IconMenu : UiEvent() {
data object OnRemoveIconClicked : IconMenu()

View file

@ -49,7 +49,7 @@ sealed class UiSpaceSettingsItem {
data object Fields : UiSpaceSettingsItem()
data class DefaultObjectType(val id: Id?, val name: String, val icon: ObjectIcon) : UiSpaceSettingsItem()
data class Wallpapers(val current: Wallpaper?) : UiSpaceSettingsItem()
data class RemoteStorage(val size: Int) : UiSpaceSettingsItem()
data object RemoteStorage : UiSpaceSettingsItem()
data object SpaceInfo : UiSpaceSettingsItem()
data object DeleteSpace : UiSpaceSettingsItem()
}