diff --git a/app/src/main/java/com/anytypeio/anytype/ui/dashboard/WallpaperSelectFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/dashboard/WallpaperSelectFragment.kt index 7446be2e3b..46fddaaf81 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/dashboard/WallpaperSelectFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/dashboard/WallpaperSelectFragment.kt @@ -74,6 +74,10 @@ class WallpaperSelectFragment : BaseBottomSheetFragment if (isDismissed) dismiss() } } + + skipCollapsed() + expand() + } override fun injectDependencies() { diff --git a/app/src/main/java/com/anytypeio/anytype/ui/multiplayer/ShareQrCodeScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/multiplayer/ShareQrCodeScreen.kt index 007313ca0f..08883c9566 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/multiplayer/ShareQrCodeScreen.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/multiplayer/ShareQrCodeScreen.kt @@ -1,6 +1,8 @@ package com.anytypeio.anytype.ui.multiplayer import androidx.compose.foundation.Image +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.fillMaxWidth @@ -11,18 +13,21 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.anytypeio.anytype.R +import com.anytypeio.anytype.core_ui.common.DefaultPreviews import com.anytypeio.anytype.core_ui.foundation.Dragger -import com.anytypeio.anytype.core_ui.views.BodyCalloutRegular -import com.anytypeio.anytype.core_ui.views.HeadlineHeading +import com.anytypeio.anytype.core_ui.foundation.Header +import com.anytypeio.anytype.core_ui.views.BodyRegular +import com.anytypeio.anytype.core_utils.clipboard.copyPlainTextToClipboard import com.lightspark.composeqr.QrCodeView -@Preview +@DefaultPreviews @Composable fun ShareQrCodeScreenPreview() { ShareQrCodeScreen(link ="https://github.com/anyproto/anytype-kotlin") @@ -30,23 +35,15 @@ fun ShareQrCodeScreenPreview() { @Composable fun ShareQrCodeScreen(link: String) { + val context = LocalContext.current + Column( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 20.dp), + modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { Dragger(Modifier.padding(vertical = 6.dp)) - Text( - text = stringResource(id = R.string.multiplayer_share_space), - style = HeadlineHeading, - color = colorResource(id = R.color.text_primary) - ) - Spacer(modifier = Modifier.height(10.dp)) - Text( - text = stringResource(R.string.multiplayer_how_to_share_space_qr_code), - color = colorResource(id = R.color.text_primary), - style = BodyCalloutRegular + Header( + text = stringResource(id = R.string.space_settings_qrcode) ) Spacer(modifier = Modifier.height(20.dp)) QrCodeView( @@ -59,5 +56,36 @@ fun ShareQrCodeScreen(link: String) { ) } Spacer(modifier = Modifier.height(20.dp)) + Box( + modifier = Modifier + .fillMaxWidth() + .height(48.dp) + .clickable { + context.copyPlainTextToClipboard( + plainText = link, + label = "Space invite link", + successToast = context.getString(R.string.space_invite_link_copied) + ) + } + .padding(horizontal = 20.dp) + ) { + Image( + modifier = Modifier.align(Alignment.CenterStart), + painter = painterResource(R.drawable.ic_copy_24), + contentDescription = "Copy icon" + ) + Text( + modifier = Modifier + .padding(start = 36.dp) + .fillMaxWidth() + .align(Alignment.CenterStart) + , + text = link, + color = colorResource(R.color.text_primary), + style = BodyRegular, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/settings/space/SpaceSettingsFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/settings/space/SpaceSettingsFragment.kt index 22158004b0..11e88ed8d6 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/settings/space/SpaceSettingsFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/settings/space/SpaceSettingsFragment.kt @@ -26,6 +26,7 @@ import com.anytypeio.anytype.presentation.spaces.SpaceSettingsViewModel import com.anytypeio.anytype.presentation.spaces.SpaceSettingsViewModel.Command import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider import com.anytypeio.anytype.ui.multiplayer.LeaveSpaceWarning +import com.anytypeio.anytype.ui.multiplayer.ShareQrCodeSpaceInviteFragment 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 @@ -189,6 +190,16 @@ class SpaceSettingsFragment : BaseComposeFragment(), ObjectTypeSelectionListener Timber.w(it, "Error while opening bin from widgets") } } + is Command.ShowInviteLinkQrCode -> { + runCatching { + findNavController().navigate( + R.id.shareSpaceInviteQrCodeScreen, + ShareQrCodeSpaceInviteFragment.args(link = command.link) + ) + }.onFailure { + Timber.w(it, "Error while showing invite QR code from space settings") + } + } } } } diff --git a/core-ui/src/main/res/drawable/ic_more_32.xml b/core-ui/src/main/res/drawable/ic_more_32.xml new file mode 100644 index 0000000000..78e284bc52 --- /dev/null +++ b/core-ui/src/main/res/drawable/ic_more_32.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/core-ui/src/main/res/drawable/ic_space_settings_invite_members.xml b/core-ui/src/main/res/drawable/ic_space_settings_invite_members.xml new file mode 100644 index 0000000000..9bc9814bb6 --- /dev/null +++ b/core-ui/src/main/res/drawable/ic_space_settings_invite_members.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/Icon.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/Icon.kt index 7ffed430a4..7a6f378b7e 100644 --- a/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/Icon.kt +++ b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/Icon.kt @@ -75,18 +75,20 @@ fun NewSpaceIcon( } } ) - Text( - modifier = Modifier - .padding(top = 8.dp) - .noRippleThrottledClickable { - if (isEditEnabled) { - isSpaceIconMenuExpanded.value = !isSpaceIconMenuExpanded.value - } - }, - text = stringResource(R.string.space_settings_icon_title), - style = Caption1Medium, - color = colorResource(R.color.text_secondary) - ) + if (isEditEnabled) { + Text( + modifier = Modifier + .padding(top = 8.dp) + .noRippleThrottledClickable { + if (isEditEnabled) { + isSpaceIconMenuExpanded.value = !isSpaceIconMenuExpanded.value + } + }, + text = stringResource(R.string.space_settings_icon_title), + style = Caption1Medium, + color = colorResource(R.color.text_secondary) + ) + } MaterialTheme( shapes = MaterialTheme.shapes.copy(medium = RoundedCornerShape(10.dp)) ) { diff --git a/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/Items.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/Items.kt index 96b29a9a36..0dcd6172d7 100644 --- a/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/Items.kt +++ b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/Items.kt @@ -30,6 +30,8 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor @@ -37,9 +39,11 @@ import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -62,6 +66,7 @@ import com.anytypeio.anytype.presentation.spaces.UiEvent import com.anytypeio.anytype.presentation.spaces.UiSpaceSettingsItem import com.anytypeio.anytype.ui_settings.R import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.dropWhile @@ -243,6 +248,7 @@ fun RemoteStorageItem( BaseButton( modifier = modifier, title = stringResource(id = R.string.remote_storage), + icon = R.drawable.ic_remote_storage_24 ) } @@ -444,12 +450,23 @@ fun NewSettingsTextField( placeholderText: String, isEditEnabled: Boolean ) { + + val focusRequester = remember { FocusRequester() } + + val textFieldValue = TextFieldValue( + text = value, + selection = TextRange(value.length) + ) BasicTextField( - value = value, + value = textFieldValue, modifier = Modifier .padding(top = 4.dp) - .fillMaxWidth(), - onValueChange = onValueChange, + .fillMaxWidth() + .focusRequester(focusRequester) + , + onValueChange = { update -> + onValueChange(update.text) + }, enabled = isEditEnabled, readOnly = !isEditEnabled, textStyle = textStyle, @@ -495,6 +512,12 @@ fun NewSettingsTextField( ) } ) + + LaunchedEffect(Unit) { + // Focusing with delay, awaiting the expansion of the bottom sheet + delay(300) + focusRequester.requestFocus() + } } @Composable diff --git a/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/NewSettings.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/NewSettings.kt index 46aec30155..aab7fa649b 100644 --- a/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/NewSettings.kt +++ b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/NewSettings.kt @@ -22,6 +22,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -34,6 +35,7 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.anytypeio.anytype.core_ui.foundation.Dragger import com.anytypeio.anytype.core_ui.foundation.noRippleClickable @@ -229,7 +231,21 @@ fun NewSpaceSettingsScreen( ) } } - + is UiSpaceSettingsItem.InviteMembers -> { + item { + BaseButton( + modifier = Modifier + .fillMaxWidth() + .animateItem() + .clip(RoundedCornerShape(16.dp)) + .clickable { + uiEvent(UiEvent.OnInviteClicked) + }, + title = stringResource(id = R.string.space_settings_invite_members), + icon = R.drawable.ic_space_settings_invite_members + ) + } + } UiSpaceSettingsItem.ObjectTypes -> { item { ObjectTypesItem( @@ -335,6 +351,8 @@ fun NewSpaceSettingsScreen( if (showEditDescription) { ModalBottomSheet( + sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), + modifier = Modifier.padding(top = 48.dp), containerColor = colorResource(R.color.background_secondary), onDismissRequest = { showEditDescription = false @@ -357,6 +375,8 @@ fun NewSpaceSettingsScreen( } if (showEditTitle) { ModalBottomSheet( + sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), + modifier = Modifier.padding(top = 48.dp), containerColor = colorResource(R.color.background_secondary), onDismissRequest = { showEditTitle = false diff --git a/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/ViewerSpaceSettings.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/ViewerSpaceSettings.kt new file mode 100644 index 0000000000..dabac9d009 --- /dev/null +++ b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/new_settings/ViewerSpaceSettings.kt @@ -0,0 +1,202 @@ +package com.anytypeio.anytype.ui_settings.space.new_settings + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +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.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.unit.dp +import com.anytypeio.anytype.core_models.SystemColor +import com.anytypeio.anytype.core_models.primitives.SpaceId +import com.anytypeio.anytype.core_ui.common.DefaultPreviews +import com.anytypeio.anytype.core_ui.foundation.Dragger +import com.anytypeio.anytype.core_ui.views.BodyCalloutRegular +import com.anytypeio.anytype.core_ui.views.HeadlineHeading +import com.anytypeio.anytype.presentation.spaces.SpaceIconView +import com.anytypeio.anytype.presentation.spaces.SpaceTechInfo +import com.anytypeio.anytype.presentation.spaces.UiEvent +import com.anytypeio.anytype.ui_settings.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ViewerSpaceSettings( + title: String, + description: String, + icon: SpaceIconView, + info: SpaceTechInfo, + uiEvent: (UiEvent) -> Unit, +) { + + val isTheeDotsMenuExpanded = remember { mutableStateOf(true) } + var showTechInfo by remember { mutableStateOf(false) } + + Column( + modifier = Modifier.fillMaxWidth() + ) { + Dragger( + modifier = Modifier + .align(Alignment.CenterHorizontally) + .padding(vertical = 6.dp) + ) + Box( + modifier = Modifier + .height(48.dp) + .width(56.dp) + .align(Alignment.End) + .clickable { + isTheeDotsMenuExpanded.value = true + } + ) { + Image( + modifier = Modifier.align(Alignment.Center), + painter = painterResource(R.drawable.ic_more_32), + contentDescription = "Three dots button" + ) + } + NewSpaceIcon( + modifier = Modifier.fillMaxWidth(), + icon = icon, + isEditEnabled = false, + uiEvent = uiEvent + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = title.ifEmpty { stringResource(R.string.untitled) }, + style = HeadlineHeading, + color = colorResource(R.color.text_primary), + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center + ) + if (description.isNotEmpty()) { + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = description, + modifier = Modifier.padding(horizontal = 16.dp).fillMaxWidth(), + style = BodyCalloutRegular, + color = colorResource(R.color.text_primary), + ) + } + Spacer(modifier = Modifier.height(12.dp)) + MultiplayerButtons( + modifier = Modifier + .padding(horizontal = 16.dp), + uiEvent = uiEvent + ) + Spacer(modifier = Modifier.height(24.dp)) + } + + MaterialTheme( + shapes = MaterialTheme.shapes.copy(medium = RoundedCornerShape(10.dp)) + ) { + DropdownMenu( + modifier = Modifier + .background( + shape = RoundedCornerShape(10.dp), + color = colorResource(id = R.color.background_secondary) + ), + expanded = isTheeDotsMenuExpanded.value, + offset = DpOffset(x = 0.dp, y = 6.dp), + onDismissRequest = { + isTheeDotsMenuExpanded.value = false + } + ) { + DropdownMenuItem( + onClick = { + uiEvent(UiEvent.IconMenu.OnRemoveIconClicked) + isTheeDotsMenuExpanded.value = false + }, + ) { + Text( + text = stringResource(R.string.tech_info), + style = BodyCalloutRegular, + color = colorResource(id = R.color.text_primary) + ) + } + DropdownMenuItem( + onClick = { + isTheeDotsMenuExpanded.value = false + uiEvent(UiEvent.OnLeaveSpaceClicked) + }, + ) { + Text( + text = stringResource(R.string.multiplayer_leave_space), + style = BodyCalloutRegular, + color = colorResource(id = R.color.palette_system_red) + ) + } + } + } + + if (showTechInfo) { + ModalBottomSheet( + containerColor = colorResource(R.color.background_secondary), + onDismissRequest = { showTechInfo = false }, + dragHandle = null, + content = { SpaceInfoScreen(spaceTechInfo = info) } + ) + } +} + +@DefaultPreviews +@Composable +fun ViewerSpaceSettingsWithDescriptionPreview() { + ViewerSpaceSettings( + title = "Susan Sontag", + description = stringResource(R.string.default_text_placeholder), + uiEvent = {}, + icon = SpaceIconView.Placeholder( + name = "Susan", + color = SystemColor.SKY + ), + info = SpaceTechInfo( + spaceId = SpaceId("space-id"), + createdBy = "Thomas", + creationDateInMillis = null, + networkId = "random network id" + ) + ) +} + +@DefaultPreviews +@Composable +fun ViewerSpaceSettingsWithoutDescriptionPreview() { + ViewerSpaceSettings( + title = "Susan Sontag", + description = "", + uiEvent = {}, + icon = SpaceIconView.Placeholder( + name = "Susan", + color = SystemColor.SKY + ), + info = SpaceTechInfo( + spaceId = SpaceId("space-id"), + createdBy = "Thomas", + creationDateInMillis = null, + networkId = "random network id" + ) + ) +} \ 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 a9a10d7d52..02c0f806f8 100644 --- a/localization/src/main/res/values/strings.xml +++ b/localization/src/main/res/values/strings.xml @@ -1957,6 +1957,7 @@ Please provide specific details of your needs here. Data Management Misc Invite + Invite members QR Code Members Object Types @@ -2003,5 +2004,6 @@ Please provide specific details of your needs here. Change icon Remove Search..." + Space invite link copied! \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceSettingsViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceSettingsViewModel.kt index 9466be7b83..acedfefae9 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceSettingsViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceSettingsViewModel.kt @@ -19,11 +19,15 @@ import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.SpaceType import com.anytypeio.anytype.core_models.ext.EMPTY_STRING_VALUE import com.anytypeio.anytype.core_models.multiplayer.ParticipantStatus +import com.anytypeio.anytype.core_models.multiplayer.SpaceAccessType +import com.anytypeio.anytype.core_models.multiplayer.SpaceInviteView import com.anytypeio.anytype.core_models.multiplayer.SpaceMemberPermissions 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.base.onFailure +import com.anytypeio.anytype.domain.base.onSuccess import com.anytypeio.anytype.domain.debugging.DebugSpaceShareDownloader import com.anytypeio.anytype.domain.launch.GetDefaultObjectType import com.anytypeio.anytype.domain.launch.SetDefaultObjectType @@ -31,6 +35,7 @@ import com.anytypeio.anytype.domain.media.UploadFile import com.anytypeio.anytype.domain.misc.AppActionManager import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.multiplayer.ActiveSpaceMemberSubscriptionContainer +import com.anytypeio.anytype.domain.multiplayer.GetSpaceInviteLink import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.multiplayer.sharedSpaceCount @@ -73,7 +78,8 @@ class SpaceSettingsViewModel( private val setDefaultObjectType: SetDefaultObjectType, private val observeWallpaper: ObserveWallpaper, private val storeOfObjectTypes: StoreOfObjectTypes, - private val appActionManager: AppActionManager + private val appActionManager: AppActionManager, + private val getSpaceInviteLink: GetSpaceInviteLink ): BaseViewModel() { val commands = MutableSharedFlow() @@ -117,6 +123,7 @@ class SpaceSettingsViewModel( } viewModelScope.launch { + val defaultObjectTypeResponse = getDefaultObjectType .async(params = vmParams.space) .getOrNull() @@ -174,46 +181,70 @@ class SpaceSettingsViewModel( networkId = spaceManager.getConfig(vmParams.space)?.network.orEmpty() ) - UiSpaceSettingsState.SpaceSettings( - spaceTechInfo = spaceTechInfo, - items = listOf( + // TODO In the next PR : show different settings for viewer + + val items = buildList { + add( UiSpaceSettingsItem.Icon( icon = spaceView.spaceIcon( builder = urlBuilder, spaceGradientProvider = gradientProvider ) - ), - Spacer(height = 16), + ) + ) + add(Spacer(height = 24)) + add( UiSpaceSettingsItem.Name( name = spaceView.name.orEmpty() - ), - Spacer(height = 12), + ) + ) + add( + Spacer(height = 8), + ) + add( UiSpaceSettingsItem.Description( description = spaceView.description.orEmpty() - ), - Spacer(height = 12), - UiSpaceSettingsItem.Multiplayer, - Spacer(height = 8), - UiSpaceSettingsItem.Section.Collaboration, - UiSpaceSettingsItem.Members(count = spaceMemberCount), - UiSpaceSettingsItem.Section.ContentModel, - UiSpaceSettingsItem.ObjectTypes, - Spacer(height = 8), - UiSpaceSettingsItem.Fields, - UiSpaceSettingsItem.Section.Preferences, - defaultObjectTypeSettingItem, - Spacer(height = 8), - UiSpaceSettingsItem.Wallpapers(current = wallpaper), - UiSpaceSettingsItem.Section.DataManagement, - UiSpaceSettingsItem.RemoteStorage, - Spacer(height = 8), - UiSpaceSettingsItem.Bin, - UiSpaceSettingsItem.Section.Misc, - UiSpaceSettingsItem.SpaceInfo, - Spacer(height = 8), - UiSpaceSettingsItem.DeleteSpace, - Spacer(height = 32) - ), + ) + ) + + if (spaceView.spaceAccessType == SpaceAccessType.SHARED) { + add(Spacer(height = 8)) + add(UiSpaceSettingsItem.Multiplayer) + } + + add(UiSpaceSettingsItem.Section.Collaboration) + + if (spaceView.spaceAccessType == SpaceAccessType.SHARED) { + add(UiSpaceSettingsItem.Members(count = spaceMemberCount)) + } else { + add(UiSpaceSettingsItem.InviteMembers) + } + + add(UiSpaceSettingsItem.Section.ContentModel) + add(UiSpaceSettingsItem.ObjectTypes) + add(Spacer(height = 8)) + add(UiSpaceSettingsItem.Fields) + + add(UiSpaceSettingsItem.Section.Preferences) + add(defaultObjectTypeSettingItem) + add(Spacer(height = 8)) + add(UiSpaceSettingsItem.Wallpapers(current = wallpaper)) + + add(UiSpaceSettingsItem.Section.DataManagement) + add(UiSpaceSettingsItem.RemoteStorage) + add(Spacer(height = 8)) + add(UiSpaceSettingsItem.Bin) + + add(UiSpaceSettingsItem.Section.Misc) + add(UiSpaceSettingsItem.SpaceInfo) + add(Spacer(height = 8)) + add(UiSpaceSettingsItem.DeleteSpace) + add(Spacer(height = 32)) + } + + UiSpaceSettingsState.SpaceSettings( + spaceTechInfo = spaceTechInfo, + items = items, isEditEnabled = permission?.isOwnerOrEditor() == true ) @@ -233,11 +264,10 @@ class SpaceSettingsViewModel( isDismissed.value = true } UiEvent.OnDeleteSpaceClicked -> { - viewModelScope.launch { - commands.emit( - Command.ShowDeleteSpaceWarning - ) - } + viewModelScope.launch { commands.emit(Command.ShowDeleteSpaceWarning) } + } + UiEvent.OnLeaveSpaceClicked -> { + viewModelScope.launch { commands.emit(Command.ShowLeaveSpaceWarning) } } UiEvent.OnRemoteStorageClick -> { viewModelScope.launch { @@ -250,13 +280,30 @@ class SpaceSettingsViewModel( } } UiEvent.OnInviteClicked -> { - sendToast("Coming soon") + viewModelScope.launch { + commands.emit( + Command.ManageSharedSpace(vmParams.space) + ) + } } UiEvent.OnPersonalizationClicked -> { sendToast("Coming soon") } UiEvent.OnQrCodeClicked -> { - sendToast("Coming soon") + viewModelScope.launch { + getSpaceInviteLink + .async(vmParams.space) + .onFailure { + commands.emit( + Command.ManageSharedSpace(vmParams.space) + ) + } + .onSuccess { link -> + commands.emit( + Command.ShowInviteLinkQrCode(link.scheme) + ) + } + } } is UiEvent.OnSaveDescriptionClicked -> { viewModelScope.launch { @@ -401,26 +448,22 @@ class SpaceSettingsViewModel( } } - private fun proceedWithSpaceDebug() { - viewModelScope.launch { - debugSpaceShareDownloader - .stream(Unit) - .collect { result -> - result.fold( - onLoading = { sendToast(SPACE_DEBUG_MSG) }, - onSuccess = { path -> commands.emit(Command.ShareSpaceDebug(path)) } - ) - } - } - } + // What is below is candidate to legacy. Might be deleted soon. - fun onManageSharedSpaceClicked() { - viewModelScope.launch { - commands.emit( - Command.ManageSharedSpace(vmParams.space) - ) - } - } + // TODO add debug functionality + +// private fun proceedWithSpaceDebug() { +// viewModelScope.launch { +// debugSpaceShareDownloader +// .stream(Unit) +// .collect { result -> +// result.fold( +// onLoading = { sendToast(SPACE_DEBUG_MSG) }, +// onSuccess = { path -> commands.emit(Command.ShareSpaceDebug(path)) } +// ) +// } +// } +// } // fun onSharePrivateSpaceClicked() { // viewModelScope.launch { @@ -459,9 +502,9 @@ class SpaceSettingsViewModel( // } // } - private fun resolveIsSpaceDeletable(spaceView: ObjectWrapper.SpaceView) : Boolean { - return spaceView.spaceAccessType != null - } +// private fun resolveIsSpaceDeletable(spaceView: ObjectWrapper.SpaceView) : Boolean { +// return spaceView.spaceAccessType != null +// } // fun onAddMoreSpacesClicked() { // viewModelScope.launch { @@ -624,6 +667,7 @@ class SpaceSettingsViewModel( data class ShareSpaceDebug(val filepath: Filepath) : Command() data class SharePrivateSpace(val space: SpaceId) : Command() data class ManageSharedSpace(val space: SpaceId) : Command() + data class ShowInviteLinkQrCode(val link: String) : Command() data class ManageBin(val space: SpaceId) : Command() data class SelectDefaultObjectType(val space: SpaceId, val excludedTypeIds: List) : Command() data object ExitToVault : Command() @@ -656,7 +700,8 @@ class SpaceSettingsViewModel( private val setDefaultObjectType: SetDefaultObjectType, private val observeWallpaper: ObserveWallpaper, private val appActionManager: AppActionManager, - private val storeOfObjectTypes: StoreOfObjectTypes + private val storeOfObjectTypes: StoreOfObjectTypes, + private val getSpaceInviteLink: GetSpaceInviteLink ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create( @@ -681,7 +726,8 @@ class SpaceSettingsViewModel( setDefaultObjectType = setDefaultObjectType, observeWallpaper = observeWallpaper, appActionManager = appActionManager, - storeOfObjectTypes = storeOfObjectTypes + storeOfObjectTypes = storeOfObjectTypes, + getSpaceInviteLink = getSpaceInviteLink ) as T } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/UiEvent.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/UiEvent.kt index 90f5264908..c269315ae9 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/UiEvent.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/UiEvent.kt @@ -14,6 +14,7 @@ sealed class UiEvent { data class OnDefaultObjectTypeClicked(val currentDefaultObjectTypeId: Id?) : UiEvent() data object OnDeleteSpaceClicked : UiEvent() + data object OnLeaveSpaceClicked : UiEvent() data object OnRemoteStorageClick : UiEvent() data object OnBinClick : UiEvent() data object OnPersonalizationClicked : UiEvent() diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/UiState.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/UiState.kt index b24ebbe7f4..5da8f3de9f 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/UiState.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/UiState.kt @@ -44,6 +44,7 @@ sealed class UiSpaceSettingsItem { data class Description(val description: String) : UiSpaceSettingsItem() data object Multiplayer : UiSpaceSettingsItem() data class Members(val count: Int) : UiSpaceSettingsItem() + data object InviteMembers : UiSpaceSettingsItem() data class Chat(val isOn: Boolean) : UiSpaceSettingsItem() data object ObjectTypes : UiSpaceSettingsItem() data object Fields : UiSpaceSettingsItem()