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

DROID-2398 Multiplayer | Enhancement | Allow picking an image from device as space icon (#1323)

This commit is contained in:
Evgenii Kozlov 2024-06-26 11:09:04 +02:00 committed by Evgenii Kozlov
parent c9138f0272
commit f1ae1856f0
7 changed files with 136 additions and 24 deletions

View file

@ -19,6 +19,7 @@ import com.anytypeio.anytype.core_ui.common.ComposeDialogView
import com.anytypeio.anytype.core_ui.extensions.throttledClick
import com.anytypeio.anytype.core_utils.clipboard.copyPlainTextToClipboard
import com.anytypeio.anytype.core_utils.ext.arg
import com.anytypeio.anytype.core_utils.ext.parseImagePath
import com.anytypeio.anytype.core_utils.ext.shareFile
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
@ -101,7 +102,16 @@ class SpaceSettingsFragment : BaseBottomSheetComposeFragment() {
onRandomGradientClicked = vm::onRandomSpaceGradientClicked,
onManageSharedSpaceClicked = vm::onManageSharedSpaceClicked,
onSharePrivateSpaceClicked = vm::onSharePrivateSpaceClicked,
onAddMoreSpacesClicked = vm::onAddMoreSpacesClicked
onAddMoreSpacesClicked = vm::onAddMoreSpacesClicked,
onSpaceImagePicked = { uri ->
runCatching {
vm.onSpaceImagePicked(
path = uri.parseImagePath(requireContext())
)
}.onFailure {
toast(getString(R.string.error_while_loading_picture))
}
}
)
LaunchedEffect(Unit) { vm.toasts.collect { toast(it) } }
LaunchedEffect(Unit) {

View file

@ -4,8 +4,9 @@ import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Command
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import javax.inject.Inject
class SetDocumentImageIcon(
class SetDocumentImageIcon @Inject constructor(
private val repo: BlockRepository
) : SetImageIcon<Id>() {

View file

@ -60,6 +60,7 @@
<string name="space_name">Space name</string>
<string name="default_space">Entry space</string>
<string name="space_settings_apply_random_gradient">Apply random gradient</string>
<string name="space_settings_apply_upload_image">Upload image</string>
<string name="delete_space">Delete space</string>
<string name="you_can_store">You can store up to %1$s of your files on our encrypted backup node for free. If you reach the limit, files will be stored only locally.</string>
<string name="in_order_to_save">In order to save space on your local device, you can offload all your files to our encrypted backup node. The files will be loaded back when you open them.</string>

View file

@ -9,6 +9,7 @@ import com.anytypeio.anytype.analytics.base.EventsDictionary.screenLeaveSpace
import com.anytypeio.anytype.analytics.base.EventsPropertiesKey
import com.anytypeio.anytype.analytics.base.sendEvent
import com.anytypeio.anytype.analytics.props.Props
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Filepath
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
@ -27,6 +28,9 @@ import com.anytypeio.anytype.core_utils.ui.ViewState
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.icon.SetDocumentImageIcon
import com.anytypeio.anytype.domain.icon.SetImageIcon
import com.anytypeio.anytype.domain.media.UploadFile
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.ActiveSpaceMemberSubscriptionContainer
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
@ -58,7 +62,8 @@ class SpaceSettingsViewModel(
private val userPermissionProvider: UserPermissionProvider,
private val spaceViewContainer: SpaceViewSubscriptionContainer,
private val activeSpaceMemberSubscriptionContainer: ActiveSpaceMemberSubscriptionContainer,
private val getMembership: GetMembershipStatus
private val getMembership: GetMembershipStatus,
private val uploadFile: UploadFile
): BaseViewModel() {
val commands = MutableSharedFlow<Command>()
@ -325,6 +330,46 @@ class SpaceSettingsViewModel(
}
}
fun onSpaceImagePicked(path: String) {
Timber.d("onSpaceImageClicked: $path")
viewModelScope.launch {
uploadFile.async(
params = UploadFile.Params(
path = path,
space = params.space,
type = Block.Content.File.Type.IMAGE
)
).fold(
onSuccess = { file ->
proceedWithSettingSpaceIconImage(file)
},
onFailure = {
Timber.e(it, "Error while uploading image as space icon")
}
)
}
}
private suspend fun proceedWithSettingSpaceIconImage(file: ObjectWrapper.File) {
setSpaceDetails.async(
SetSpaceDetails.Params(
space = params.space,
details = mapOf(
Relations.ICON_OPTION to null,
Relations.ICON_IMAGE to file.id,
Relations.ICON_EMOJI to null
)
)
).fold(
onSuccess = {
Timber.d("Successfully set image as space icon.")
},
onFailure = { e ->
Timber.e(e, "Error while setting image as space icon")
}
)
}
data class SpaceData(
val spaceId: Id?,
val createdDateInMillis: Long?,
@ -369,7 +414,8 @@ class SpaceSettingsViewModel(
private val spaceGradientProvider: SpaceGradientProvider,
private val userPermissionProvider: UserPermissionProvider,
private val activeSpaceMemberSubscriptionContainer: ActiveSpaceMemberSubscriptionContainer,
private val getMembership: GetMembershipStatus
private val getMembership: GetMembershipStatus,
private val uploadFile: UploadFile
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
@ -388,7 +434,8 @@ class SpaceSettingsViewModel(
params = params,
userPermissionProvider = userPermissionProvider,
activeSpaceMemberSubscriptionContainer = activeSpaceMemberSubscriptionContainer,
getMembership = getMembership
getMembership = getMembership,
uploadFile = uploadFile
) as T
}

View file

@ -38,6 +38,7 @@ dependencies {
implementation libs.composeFoundation
implementation libs.composeMaterial
implementation libs.composeToolingPreview
implementation libs.activityCompose
implementation libs.coilCompose

View file

@ -1,12 +1,19 @@
package com.anytypeio.anytype.ui_settings.main
import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Divider
import androidx.compose.material.DropdownMenu
import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
@ -15,6 +22,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
@ -26,6 +34,7 @@ import com.anytypeio.anytype.core_ui.foundation.Dragger
import com.anytypeio.anytype.core_ui.views.BodyRegular
import com.anytypeio.anytype.presentation.spaces.SpaceIconView
import com.anytypeio.anytype.ui_settings.R
import timber.log.Timber
@Composable
fun SpaceHeader(
@ -34,8 +43,20 @@ fun SpaceHeader(
modifier: Modifier = Modifier,
onNameSet: (String) -> Unit,
onRandomGradientClicked: () -> Unit,
isEditEnabled: Boolean
isEditEnabled: Boolean,
onSpaceImagePicked: (Uri) -> Unit
) {
val context = LocalContext.current
val singlePhotoPickerLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickVisualMedia(),
onResult = { uri ->
if (uri != null) {
onSpaceImagePicked(uri)
} else {
Timber.w("Uri was null after picking image")
}
}
)
val isSpaceIconMenuExpanded = remember {
mutableStateOf(false)
}
@ -56,24 +77,50 @@ fun SpaceHeader(
},
gradientCornerRadius = 4.dp
)
DropdownMenu(
expanded = isSpaceIconMenuExpanded.value,
offset = DpOffset(x = 0.dp, y = 6.dp),
onDismissRequest = {
isSpaceIconMenuExpanded.value = false
}
MaterialTheme(
shapes = MaterialTheme.shapes.copy(medium = RoundedCornerShape(16.dp))
) {
DropdownMenuItem(
onClick = {
onRandomGradientClicked()
DropdownMenu(
expanded = isSpaceIconMenuExpanded.value,
offset = DpOffset(x = 0.dp, y = 6.dp),
onDismissRequest = {
isSpaceIconMenuExpanded.value = false
},
}
) {
Text(
text = stringResource(R.string.space_settings_apply_random_gradient),
style = BodyRegular,
color = colorResource(id = R.color.text_primary)
)
DropdownMenuItem(
onClick = {
onRandomGradientClicked()
isSpaceIconMenuExpanded.value = false
},
) {
Text(
text = stringResource(R.string.space_settings_apply_random_gradient),
style = BodyRegular,
color = colorResource(id = R.color.text_primary)
)
}
if (ActivityResultContracts.PickVisualMedia.isPhotoPickerAvailable(context)) {
Divider(
thickness = 0.5.dp,
color = colorResource(id = R.color.shape_primary)
)
DropdownMenuItem(
onClick = {
singlePhotoPickerLauncher.launch(
PickVisualMediaRequest(
ActivityResultContracts.PickVisualMedia.ImageOnly
)
)
isSpaceIconMenuExpanded.value = false
},
) {
Text(
text = stringResource(R.string.space_settings_apply_upload_image),
style = BodyRegular,
color = colorResource(id = R.color.text_primary)
)
}
}
}
}
}

View file

@ -1,5 +1,6 @@
package com.anytypeio.anytype.ui_settings.space
import android.net.Uri
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@ -17,6 +18,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
@ -68,6 +70,7 @@ fun SpaceSettingsScreen(
onSharePrivateSpaceClicked: () -> Unit,
onManageSharedSpaceClicked: () -> Unit,
onAddMoreSpacesClicked: () -> Unit,
onSpaceImagePicked: (Uri) -> Unit
) {
LazyColumn(
modifier = Modifier
@ -95,7 +98,8 @@ fun SpaceSettingsScreen(
ViewState.Init -> false
ViewState.Loading -> false
is ViewState.Success -> state.data.permissions.isOwnerOrEditor()
}
},
onSpaceImagePicked = onSpaceImagePicked
)
}
item { Divider() }
@ -311,7 +315,7 @@ fun SpaceSettingsScreenPreview() {
shareLimitReached = SpaceSettingsViewModel.ShareLimitsState(
shareLimitReached = false,
sharedSpacesLimit = 0
),
)
)
),
onNameSet = {},
@ -325,7 +329,8 @@ fun SpaceSettingsScreenPreview() {
onRandomGradientClicked = {},
onManageSharedSpaceClicked = {},
onSharePrivateSpaceClicked = {},
onAddMoreSpacesClicked = {}
onAddMoreSpacesClicked = {},
onSpaceImagePicked = {}
)
}