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:
parent
c9138f0272
commit
f1ae1856f0
7 changed files with 136 additions and 24 deletions
|
@ -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) {
|
||||
|
|
|
@ -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>() {
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ dependencies {
|
|||
implementation libs.composeFoundation
|
||||
implementation libs.composeMaterial
|
||||
implementation libs.composeToolingPreview
|
||||
implementation libs.activityCompose
|
||||
|
||||
implementation libs.coilCompose
|
||||
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 = {}
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue