mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-3367 Primitives | Object type icons, part 1 (#2156)
This commit is contained in:
parent
f952730bfa
commit
fc0386b4ef
46 changed files with 837 additions and 561 deletions
|
@ -6,6 +6,7 @@ import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes
|
|||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.UserSettingsRepository
|
||||
import com.anytypeio.anytype.domain.launch.GetDefaultObjectType
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.spaces.AddObjectTypeToSpace
|
||||
import com.anytypeio.anytype.domain.workspace.SpaceManager
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectTypeChangeViewModelFactory
|
||||
|
@ -44,14 +45,16 @@ object ObjectTypeChangeModule {
|
|||
addObjectTypeToSpace: AddObjectTypeToSpace,
|
||||
dispatchers: AppCoroutineDispatchers,
|
||||
spaceManager: SpaceManager,
|
||||
getDefaultObjectType: GetDefaultObjectType
|
||||
getDefaultObjectType: GetDefaultObjectType,
|
||||
urlBuilder: UrlBuilder
|
||||
): ObjectTypeChangeViewModelFactory {
|
||||
return ObjectTypeChangeViewModelFactory(
|
||||
getObjectTypes = getObjectTypes,
|
||||
addObjectTypeToSpace = addObjectTypeToSpace,
|
||||
dispatchers = dispatchers,
|
||||
spaceManager = spaceManager,
|
||||
getDefaultObjectType = getDefaultObjectType
|
||||
getDefaultObjectType = getDefaultObjectType,
|
||||
urlBuilder = urlBuilder
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
|||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.ConfigStorage
|
||||
import com.anytypeio.anytype.domain.config.UserSettingsRepository
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.workspace.SpaceManager
|
||||
import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
|
||||
import com.anytypeio.anytype.presentation.objects.SelectObjectTypeViewModel
|
||||
|
@ -54,4 +55,5 @@ interface SelectObjectTypeDependencies : ComponentDependencies {
|
|||
fun analyticSpaceHelper(): AnalyticSpaceHelperDelegate
|
||||
fun userSettingsRepository(): UserSettingsRepository
|
||||
fun provideSpaceManger(): SpaceManager
|
||||
fun provideUrlBuilder(): UrlBuilder
|
||||
}
|
|
@ -51,7 +51,6 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.DpOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil.compose.rememberAsyncImagePainter
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_ui.extensions.throttledClick
|
||||
import com.anytypeio.anytype.core_ui.foundation.AlertConfig
|
||||
|
@ -62,8 +61,10 @@ import com.anytypeio.anytype.core_ui.foundation.Toolbar
|
|||
import com.anytypeio.anytype.core_ui.views.BodyRegular
|
||||
import com.anytypeio.anytype.core_ui.views.Caption1Medium
|
||||
import com.anytypeio.anytype.core_ui.views.Title2
|
||||
import com.anytypeio.anytype.core_ui.widgets.ListWidgetObjectIcon
|
||||
import com.anytypeio.anytype.core_ui.widgets.SearchField
|
||||
import com.anytypeio.anytype.emojifier.Emojifier
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.SelectTypeView
|
||||
import com.anytypeio.anytype.presentation.objects.SelectTypeViewState
|
||||
|
||||
|
@ -204,7 +205,7 @@ private fun FlowRowContent(
|
|||
Box {
|
||||
ObjectTypeItem(
|
||||
name = view.name,
|
||||
emoji = view.icon,
|
||||
icon = view.icon,
|
||||
onItemClicked = throttledClick(
|
||||
onClick = { onTypeClicked(view) }
|
||||
),
|
||||
|
@ -434,7 +435,7 @@ private fun LazyColumnContent(
|
|||
) {
|
||||
ObjectTypeItem(
|
||||
name = view.name,
|
||||
emoji = view.icon,
|
||||
icon = view.icon,
|
||||
onItemClicked = throttledClick(
|
||||
onClick = {
|
||||
onTypeClicked(view)
|
||||
|
@ -459,7 +460,7 @@ private fun LazyColumnContent(
|
|||
fun ObjectTypeItem(
|
||||
modifier: Modifier,
|
||||
name: String,
|
||||
emoji: String,
|
||||
icon: ObjectIcon,
|
||||
isSelected: Boolean,
|
||||
onItemClicked: () -> Unit,
|
||||
onItemLongClicked: () -> Unit
|
||||
|
@ -491,17 +492,11 @@ fun ObjectTypeItem(
|
|||
Spacer(
|
||||
modifier = Modifier.width(14.dp)
|
||||
)
|
||||
val uri = Emojifier.safeUri(emoji)
|
||||
if (uri.isNotEmpty()) {
|
||||
Image(
|
||||
painter = rememberAsyncImagePainter(
|
||||
Emojifier.safeUri(emoji)
|
||||
),
|
||||
contentDescription = "Icon from URI",
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
}
|
||||
ListWidgetObjectIcon(
|
||||
icon = icon,
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = name,
|
||||
style = Title2,
|
||||
|
|
|
@ -4,9 +4,11 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
|
@ -29,7 +31,10 @@ import com.anytypeio.anytype.di.common.componentManager
|
|||
import com.anytypeio.anytype.feature_object_type.fields.ui.FieldsMainScreen
|
||||
import com.anytypeio.anytype.feature_object_type.ui.ObjectTypeCommand
|
||||
import com.anytypeio.anytype.feature_object_type.ui.ObjectTypeVmParams
|
||||
import com.anytypeio.anytype.feature_object_type.ui.TypeEvent
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiErrorState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiIconsPickerState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.icons.ChangeIconScreen
|
||||
import com.anytypeio.anytype.feature_object_type.viewmodel.ObjectTypeVMFactory
|
||||
import com.anytypeio.anytype.feature_object_type.viewmodel.ObjectTypeViewModel
|
||||
import com.anytypeio.anytype.ui.editor.EditorModalFragment
|
||||
|
@ -52,17 +57,6 @@ class ObjectTypeFragment : BaseComposeFragment() {
|
|||
private val space get() = argString(ARG_SPACE)
|
||||
private val objectId get() = argString(ARG_OBJECT_ID)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setFragmentResultListener(REQUEST_KEY_PICK_EMOJI) { _, bundle ->
|
||||
val res = requireNotNull(bundle.getString(RESULT_EMOJI_UNICODE))
|
||||
vm.updateIcon(res)
|
||||
}
|
||||
setFragmentResultListener(REQUEST_KEY_REMOVE_EMOJI) { _, _ ->
|
||||
vm.removeIcon()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
@ -70,6 +64,7 @@ class ObjectTypeFragment : BaseComposeFragment() {
|
|||
) = content {
|
||||
MaterialTheme {
|
||||
ObjectTypeScreen()
|
||||
IconsPickerScreen()
|
||||
ErrorScreen()
|
||||
}
|
||||
}
|
||||
|
@ -86,13 +81,6 @@ class ObjectTypeFragment : BaseComposeFragment() {
|
|||
Timber.e(e, "Error while exiting back from object type screen")
|
||||
}
|
||||
}
|
||||
ObjectTypeCommand.OpenEmojiPicker -> {
|
||||
runCatching {
|
||||
findNavController().navigate(R.id.openEmojiPicker)
|
||||
}.onFailure {
|
||||
Timber.w("Error while opening emoji picker")
|
||||
}
|
||||
}
|
||||
|
||||
is ObjectTypeCommand.OpenTemplate -> {
|
||||
findNavController().navigate(
|
||||
|
@ -205,6 +193,30 @@ class ObjectTypeFragment : BaseComposeFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun IconsPickerScreen() {
|
||||
val uiState = vm.uiIconsPickerScreen.collectAsStateWithLifecycle().value
|
||||
if (uiState is UiIconsPickerState.Visible) {
|
||||
ChangeIconScreen(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onDismissRequest = {
|
||||
vm.onTypeEvent(TypeEvent.OnIconPickerDismiss)
|
||||
},
|
||||
onIconClicked = { name, color ->
|
||||
vm.onTypeEvent(
|
||||
TypeEvent.OnIconPickerItemClick(
|
||||
iconName = name,
|
||||
color = color
|
||||
)
|
||||
)
|
||||
},
|
||||
onRemoveIconClicked = {
|
||||
vm.onTypeEvent(TypeEvent.OnIconPickerRemovedClick)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun injectDependencies() {
|
||||
val params = ObjectTypeVmParams(
|
||||
spaceId = SpaceId(space),
|
||||
|
|
|
@ -30,6 +30,7 @@ sealed class ObjectWrapper {
|
|||
val iconEmoji: String? by default
|
||||
val iconImage: String? = getSingleValue(Relations.ICON_IMAGE)
|
||||
val iconOption: Double? by default
|
||||
val iconName: String? by default
|
||||
|
||||
val coverId: String? = getSingleValue(Relations.COVER_ID)
|
||||
|
||||
|
@ -200,6 +201,9 @@ sealed class ObjectWrapper {
|
|||
else -> emptyList()
|
||||
}
|
||||
|
||||
val iconName: String? by default
|
||||
val iconOption: Double? by default
|
||||
|
||||
val allRecommendedRelations: List<Id>
|
||||
get() = recommendedRelations + recommendedFeaturedRelations + recommendedHiddenRelations + recommendedFileRelations
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ object Relations {
|
|||
const val NAME = "name"
|
||||
const val ICON_EMOJI = "iconEmoji"
|
||||
const val ICON_OPTION = "iconOption"
|
||||
const val ICON_NAME = "iconName"
|
||||
const val ICON_IMAGE = "iconImage"
|
||||
const val RELATION_FORMAT = "relationFormat"
|
||||
const val IS_ARCHIVED = "isArchived"
|
||||
|
|
|
@ -14,6 +14,7 @@ import com.anytypeio.anytype.core_models.RelativeDate
|
|||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_utils.const.MimeTypes
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectLayoutView
|
||||
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIconColor
|
||||
import com.anytypeio.anytype.presentation.sets.model.ColumnView
|
||||
|
||||
fun Context.drawable(
|
||||
|
@ -309,4 +310,18 @@ fun RelativeDate.getPrettyName(
|
|||
is RelativeDate.Tomorrow -> resources.getString(R.string.tomorrow)
|
||||
is RelativeDate.Yesterday -> resources.getString(R.string.yesterday)
|
||||
RelativeDate.Empty -> ""
|
||||
}
|
||||
|
||||
@ColorRes
|
||||
fun CustomIconColor.colorRes() = when (this) {
|
||||
CustomIconColor.Gray -> R.color.glyph_active
|
||||
CustomIconColor.Yellow -> R.color.palette_system_yellow
|
||||
CustomIconColor.Amber -> R.color.palette_system_amber_100
|
||||
CustomIconColor.Red -> R.color.palette_system_red
|
||||
CustomIconColor.Pink -> R.color.palette_system_pink
|
||||
CustomIconColor.Purple -> R.color.palette_system_purple
|
||||
CustomIconColor.Blue -> R.color.palette_system_blue
|
||||
CustomIconColor.Sky -> R.color.palette_system_sky
|
||||
CustomIconColor.Teal -> R.color.palette_system_teal
|
||||
CustomIconColor.Green -> R.color.palette_system_green
|
||||
}
|
|
@ -12,11 +12,7 @@ class ObjectTypeMenuHolder(
|
|||
|
||||
fun bind(item: SlashItem.ObjectType) = with(binding) {
|
||||
val objectType = item.objectTypeView
|
||||
ivIcon.setIcon(
|
||||
emoji = objectType.emoji,
|
||||
image = null,
|
||||
name = objectType.name
|
||||
)
|
||||
ivIcon.setIcon(objectType.icon)
|
||||
tvTitle.text = objectType.name
|
||||
if (objectType.description.isNullOrBlank()) {
|
||||
tvSubtitle.gone()
|
||||
|
|
|
@ -21,9 +21,7 @@ class ObjectTypeHolder(
|
|||
icSelected.gone()
|
||||
}
|
||||
ivIcon.setIcon(
|
||||
emoji = item.emoji,
|
||||
image = null,
|
||||
name = item.name
|
||||
icon = item.icon
|
||||
)
|
||||
tvTitle.text = item.name
|
||||
if (item.description.isNullOrBlank()) {
|
||||
|
@ -40,11 +38,7 @@ class ObjectTypeHorizontalHolder(
|
|||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: ObjectTypeView) = with(binding) {
|
||||
icon.setIcon(
|
||||
emoji = item.emoji,
|
||||
image = null,
|
||||
name = item.name
|
||||
)
|
||||
icon.setIcon(item.icon)
|
||||
name.text = item.name
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import com.anytypeio.anytype.core_ui.R
|
|||
import com.anytypeio.anytype.core_ui.extensions.getMimeIcon
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
|
||||
import com.anytypeio.anytype.core_ui.widgets.objectIcon.AvatarIconView
|
||||
import com.anytypeio.anytype.core_ui.widgets.objectIcon.CustomIconView
|
||||
import com.anytypeio.anytype.core_ui.widgets.objectIcon.DeletedIconView
|
||||
import com.anytypeio.anytype.core_ui.widgets.objectIcon.EmojiIconView
|
||||
import com.anytypeio.anytype.core_ui.widgets.objectIcon.EmptyIconView
|
||||
|
@ -83,6 +84,13 @@ fun ListWidgetObjectIcon(
|
|||
)
|
||||
}
|
||||
ObjectIcon.None -> {}
|
||||
is ObjectIcon.ObjectType -> {
|
||||
CustomIconView(
|
||||
icon = icon,
|
||||
modifier = modifier,
|
||||
iconSize = iconSize
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.anytypeio.anytype.core_ui.widgets
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
|
@ -13,6 +14,7 @@ import com.anytypeio.anytype.core_models.Url
|
|||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.WidgetObjectIconBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.color
|
||||
import com.anytypeio.anytype.core_ui.extensions.colorRes
|
||||
import com.anytypeio.anytype.core_ui.extensions.drawable
|
||||
import com.anytypeio.anytype.core_ui.extensions.getMimeIcon
|
||||
import com.anytypeio.anytype.core_ui.extensions.setCircularShape
|
||||
|
@ -32,6 +34,7 @@ class ObjectIconWidget @JvmOverloads constructor(
|
|||
|
||||
companion object {
|
||||
const val DEFAULT_SIZE = 28
|
||||
const val DRAWABLE_DIR = "drawable"
|
||||
}
|
||||
|
||||
val binding = WidgetObjectIconBinding.inflate(
|
||||
|
@ -149,23 +152,10 @@ class ObjectIconWidget @JvmOverloads constructor(
|
|||
ObjectIcon.Deleted -> setDeletedIcon()
|
||||
is ObjectIcon.Checkbox -> setCheckbox(icon.isChecked)
|
||||
is ObjectIcon.Empty -> icon.setEmptyIcon()
|
||||
is ObjectIcon.ObjectType -> setCustomIcon(icon)
|
||||
}
|
||||
}
|
||||
|
||||
fun setIcon(
|
||||
emoji: String?,
|
||||
image: Url?,
|
||||
name: String
|
||||
) {
|
||||
if (emoji.isNullOrBlank() && image.isNullOrBlank()) {
|
||||
setProfileInitials(name)
|
||||
} else {
|
||||
setEmoji(emoji)
|
||||
setCircularImage(image)
|
||||
}
|
||||
//todo Add checkbox logic
|
||||
}
|
||||
|
||||
fun setNonExistentIcon() {
|
||||
binding.ivImage.setImageResource(R.drawable.ic_non_existent_object)
|
||||
}
|
||||
|
@ -360,6 +350,32 @@ class ObjectIconWidget @JvmOverloads constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun setCustomIcon(icon: ObjectIcon.ObjectType) {
|
||||
val resId = context.resources.getIdentifier(icon.icon.drawableResId, DRAWABLE_DIR, context.packageName)
|
||||
with(binding) {
|
||||
ivCheckbox.invisible()
|
||||
initialContainer.invisible()
|
||||
ivImage.invisible()
|
||||
ivBookmark.setImageDrawable(null)
|
||||
ivBookmark.gone()
|
||||
emojiContainer.visible()
|
||||
}
|
||||
try {
|
||||
if (resId != 0) {
|
||||
val tint = context.getColor(icon.icon.color.colorRes())
|
||||
binding.tvEmojiFallback.gone()
|
||||
binding.ivEmoji.setImageResource(resId)
|
||||
binding.ivEmoji.imageTintList = ColorStateList.valueOf(tint)
|
||||
} else {
|
||||
binding.ivEmoji.setImageDrawable(null)
|
||||
binding.tvEmojiFallback.gone()
|
||||
binding.tvEmojiFallback.visible()
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Timber.w(e, "Error while setting object type icon for")
|
||||
}
|
||||
}
|
||||
|
||||
private fun ObjectIcon.Empty.setEmptyIcon() {
|
||||
val (drawable, containerBackground) = when (this) {
|
||||
ObjectIcon.Empty.Bookmark -> R.drawable.ic_empty_state_link to true
|
||||
|
|
|
@ -8,6 +8,8 @@ import com.anytypeio.anytype.core_models.primitives.TypeId
|
|||
import com.anytypeio.anytype.core_models.primitives.TypeKey
|
||||
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
|
||||
import com.anytypeio.anytype.presentation.editor.cover.CoverColor
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIcon
|
||||
import com.anytypeio.anytype.presentation.templates.TemplateObjectTypeView
|
||||
import com.anytypeio.anytype.presentation.templates.TemplateView
|
||||
import com.anytypeio.anytype.presentation.templates.TemplateView.Companion.DEFAULT_TEMPLATE_ID_BLANK
|
||||
|
@ -50,6 +52,11 @@ fun TypeTemplatesWidgetPreview() {
|
|||
TemplateObjectTypeView.Item(
|
||||
type = ObjectWrapper.Type(
|
||||
map = mapOf(Relations.ID to "123", Relations.NAME to "Page"),
|
||||
),
|
||||
icon = ObjectIcon.ObjectType(
|
||||
icon = CustomIcon(
|
||||
rawValue = "batteryCharging"
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
|
|
@ -953,44 +953,26 @@ fun ObjectTypesList(
|
|||
},
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
val typeIcon = item.type.iconEmoji
|
||||
val (rowPaddingStart, textPaddingStart) = if (typeIcon != null) {
|
||||
14.dp to 8.dp
|
||||
} else {
|
||||
16.dp to 0.dp
|
||||
}
|
||||
val (rowPaddingStart, textPaddingStart) = 14.dp to 8.dp
|
||||
Row(
|
||||
modifier = Modifier.padding(
|
||||
start = rowPaddingStart,
|
||||
start = 14.dp,
|
||||
end = 16.dp
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (typeIcon != null) {
|
||||
Box(
|
||||
modifier = Modifier.wrapContentSize()
|
||||
) {
|
||||
Image(
|
||||
painter = rememberAsyncImagePainter(
|
||||
Emojifier.safeUri(
|
||||
typeIcon
|
||||
)
|
||||
),
|
||||
contentDescription = "Type's icon",
|
||||
modifier = Modifier
|
||||
.size(18.dp)
|
||||
.align(Alignment.Center),
|
||||
alignment = Alignment.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
ListWidgetObjectIcon(
|
||||
modifier = Modifier.size(20.dp),
|
||||
icon = item.icon
|
||||
)
|
||||
Text(
|
||||
text = item.type.name.orEmpty(),
|
||||
style = BodyCalloutMedium.copy(
|
||||
color = colorResource(id = R.color.text_primary)
|
||||
),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.padding(start = textPaddingStart)
|
||||
.padding(start = 8.dp)
|
||||
.widthIn(max = 100.dp),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package com.anytypeio.anytype.core_ui.widgets.objectIcon
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
|
||||
import com.anytypeio.anytype.core_ui.extensions.colorRes
|
||||
import com.anytypeio.anytype.core_ui.widgets.objectIcon.custom_icons.CustomIcons
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIcon
|
||||
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIconColor
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
|
||||
@Composable
|
||||
fun CustomIconView(
|
||||
modifier: Modifier = Modifier,
|
||||
icon: ObjectIcon.ObjectType,
|
||||
iconSize: Dp
|
||||
) {
|
||||
val tint = colorResource(id = icon.icon.color.colorRes())
|
||||
|
||||
val imageVector = CustomIcons.getImageVector(icon.icon)
|
||||
|
||||
Box(modifier = modifier) {
|
||||
if (imageVector != null) {
|
||||
Image(
|
||||
modifier = Modifier.size(iconSize),
|
||||
imageVector = imageVector,
|
||||
contentDescription = "Object Type icon",
|
||||
colorFilter = ColorFilter.tint(tint),
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
modifier = Modifier.size(iconSize),
|
||||
painter = painterResource(id = R.drawable.ic_empty_state_page),
|
||||
contentDescription = "Object Type icon",
|
||||
colorFilter = ColorFilter.tint(tint),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@DefaultPreviews
|
||||
fun CustomIconViewPreview() {
|
||||
CustomIconView(
|
||||
icon = ObjectIcon.ObjectType(
|
||||
icon = CustomIcon(
|
||||
rawValue = "batteryCharging",
|
||||
color = CustomIconColor.Yellow
|
||||
),
|
||||
),
|
||||
modifier = Modifier,
|
||||
iconSize = 18.dp
|
||||
)
|
||||
}
|
|
@ -1,405 +1,20 @@
|
|||
package com.anytypeio.anytype.core_ui.widgets.objectIcon.custom_icons
|
||||
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIcon
|
||||
|
||||
object CustomIcons {
|
||||
|
||||
fun getIconByName(name: String): ImageVector? = iconsMap[name]
|
||||
fun getImageVector(icon: CustomIcon): ImageVector? {
|
||||
return iconsMap[icon.rawValue]
|
||||
}
|
||||
|
||||
fun getImageVector(name: String): ImageVector? {
|
||||
return iconsMap[name]
|
||||
}
|
||||
|
||||
// Маппинг, который связывает строковое название с соответствующей иконкой.
|
||||
// Например, если у нас raw-имя иконки "walk" соответствует CustomIcons.CiWalk.
|
||||
val iconsMap: Map<String, ImageVector> by lazy {
|
||||
mapOf(
|
||||
"accessibility" to CiAccessibility,
|
||||
"addCircle" to CiAddCircle,
|
||||
"airplane" to CiAirplane,
|
||||
"alarm" to CiAlarm,
|
||||
"albums" to CiAlbums,
|
||||
"alertCircle" to CiAlertCircle,
|
||||
"americanFootball" to CiAmericanFootball,
|
||||
"analytics" to CiAnalytics,
|
||||
"aperture" to CiAperture,
|
||||
"apps" to CiApps,
|
||||
"archive" to CiArchive,
|
||||
"arrowBackCircle" to CiArrowBackCircle,
|
||||
"arrowDownCircle" to CiArrowDownCircle,
|
||||
"arrowForwardCircle" to CiArrowForwardCircle,
|
||||
"arrowRedo" to CiArrowRedo,
|
||||
"arrowRedoCircle" to CiArrowRedoCircle,
|
||||
"arrowUndo" to CiArrowUndo,
|
||||
"arrowUndoCircle" to CiArrowUndoCircle,
|
||||
"arrowUpCircle" to CiArrowUpCircle,
|
||||
"atCircle" to CiAtCircle,
|
||||
"attach" to CiAttach,
|
||||
"backspace" to CiBackspace,
|
||||
"bag" to CiBag,
|
||||
"bagAdd" to CiBagAdd,
|
||||
"bagCheck" to CiBagCheck,
|
||||
"bagHandle" to CiBagHandle,
|
||||
"bagRemove" to CiBagRemove,
|
||||
"balloon" to CiBalloon,
|
||||
"ban" to CiBan,
|
||||
"bandage" to CiBandage,
|
||||
"barChart" to CiBarChart,
|
||||
"barbell" to CiBarbell,
|
||||
"barcode" to CiBarcode,
|
||||
"baseball" to CiBaseball,
|
||||
"basket" to CiBasket,
|
||||
"basketball" to CiBasketball,
|
||||
"batteryCharging" to CiBatteryCharging,
|
||||
"batteryDead" to CiBatteryDead,
|
||||
"batteryFull" to CiBatteryFull,
|
||||
"batteryHalf" to CiBatteryHalf,
|
||||
"beaker" to CiBeaker,
|
||||
"bed" to CiBed,
|
||||
"beer" to CiBeer,
|
||||
"bicycle" to CiBicycle,
|
||||
"binoculars" to CiBinoculars,
|
||||
"bluetooth" to CiBluetooth,
|
||||
"boat" to CiBoat,
|
||||
"body" to CiBody,
|
||||
"bonfire" to CiBonfire,
|
||||
"book" to CiBook,
|
||||
"bookmark" to CiBookmark,
|
||||
"bookmarks" to CiBookmarks,
|
||||
"bowlingBall" to CiBowlingBall,
|
||||
"briefcase" to CiBriefcase,
|
||||
"browsers" to CiBrowsers,
|
||||
"brush" to CiBrush,
|
||||
"bug" to CiBug,
|
||||
"build" to CiBuild,
|
||||
"bulb" to CiBulb,
|
||||
"bus" to CiBus,
|
||||
"business" to CiBusiness,
|
||||
"cafe" to CiCafe,
|
||||
"calculator" to CiCalculator,
|
||||
"calendar" to CiCalendar,
|
||||
"calendarClear" to CiCalendarClear,
|
||||
"calendarNumber" to CiCalendarNumber,
|
||||
"call" to CiCall,
|
||||
"camera" to CiCamera,
|
||||
"cameraReverse" to CiCameraReverse,
|
||||
"car" to CiCar,
|
||||
"carSport" to CiCarSport,
|
||||
"card" to CiCard,
|
||||
"caretBack" to CiCaretBack,
|
||||
"caretBackCircle" to CiCaretBackCircle,
|
||||
"caretDown" to CiCaretDown,
|
||||
"caretDownCircle" to CiCaretDownCircle,
|
||||
"caretForward" to CiCaretForward,
|
||||
"caretForwardCircle" to CiCaretForwardCircle,
|
||||
"caretUp" to CiCaretUp,
|
||||
"caretUpCircle" to CiCaretUpCircle,
|
||||
"cart" to CiCart,
|
||||
"cash" to CiCash,
|
||||
"cellular" to CiCellular,
|
||||
"chatbox" to CiChatbox,
|
||||
"chatboxEllipses" to CiChatboxEllipses,
|
||||
"chatbubble" to CiChatbubble,
|
||||
"chatbubbleEllipses" to CiChatbubbleEllipses,
|
||||
"chatbubbles" to CiChatbubbles,
|
||||
"checkbox" to CiCheckbox,
|
||||
"checkmarkCircle" to CiCheckmarkCircle,
|
||||
"checkmarkDoneCircle" to CiCheckmarkDoneCircle,
|
||||
"chevronBackCircle" to CiChevronBackCircle,
|
||||
"chevronDownCircle" to CiChevronDownCircle,
|
||||
"chevronForwardCircle" to CiChevronForwardCircle,
|
||||
"chevronUpCircle" to CiChevronUpCircle,
|
||||
"clipboard" to CiClipboard,
|
||||
"closeCircle" to CiCloseCircle,
|
||||
"cloud" to CiCloud,
|
||||
"cloudCircle" to CiCloudCircle,
|
||||
"cloudDone" to CiCloudDone,
|
||||
"cloudDownload" to CiCloudDownload,
|
||||
"cloudOffline" to CiCloudOffline,
|
||||
"cloudUpload" to CiCloudUpload,
|
||||
"cloudy" to CiCloudy,
|
||||
"cloudyNight" to CiCloudyNight,
|
||||
"code" to CiCode,
|
||||
"codeSlash" to CiCodeSlash,
|
||||
"cog" to CiCog,
|
||||
"colorFill" to CiColorFill,
|
||||
"colorFilter" to CiColorFilter,
|
||||
"colorPalette" to CiColorPalette,
|
||||
"colorWand" to CiColorWand,
|
||||
"compass" to CiCompass,
|
||||
"construct" to CiConstruct,
|
||||
"contract" to CiContract,
|
||||
"contrast" to CiContrast,
|
||||
"copy" to CiCopy,
|
||||
"create" to CiCreate,
|
||||
"crop" to CiCrop,
|
||||
"cube" to CiCube,
|
||||
"cut" to CiCut,
|
||||
"desktop" to CiDesktop,
|
||||
"diamond" to CiDiamond,
|
||||
"dice" to CiDice,
|
||||
"disc" to CiDisc,
|
||||
"document" to CiDocument,
|
||||
"documentAttach" to CiDocumentAttach,
|
||||
"documentLock" to CiDocumentLock,
|
||||
"documentText" to CiDocumentText,
|
||||
"documents" to CiDocuments,
|
||||
"download" to CiDownload,
|
||||
"duplicate" to CiDuplicate,
|
||||
"ear" to CiEar,
|
||||
"earth" to CiEarth,
|
||||
"easel" to CiEasel,
|
||||
"egg" to CiEgg,
|
||||
"ellipse" to CiEllipse,
|
||||
"ellipsisHorizontalCircle" to CiEllipsisHorizontalCircle,
|
||||
"ellipsisVerticalCircle" to CiEllipsisVerticalCircle,
|
||||
"enter" to CiEnter,
|
||||
"exit" to CiExit,
|
||||
"expand" to CiExpand,
|
||||
"extensionPuzzle" to CiExtensionPuzzle,
|
||||
"eye" to CiEye,
|
||||
"eyeOff" to CiEyeOff,
|
||||
"eyedrop" to CiEyedrop,
|
||||
"fastFood" to CiFastFood,
|
||||
"female" to CiFemale,
|
||||
"fileTray" to CiFileTray,
|
||||
"fileTrayFull" to CiFileTrayFull,
|
||||
"fileTrayStacked" to CiFileTrayStacked,
|
||||
"film" to CiFilm,
|
||||
"filterCircle" to CiFilterCircle,
|
||||
"fingerPrint" to CiFingerPrint,
|
||||
"fish" to CiFish,
|
||||
"fitness" to CiFitness,
|
||||
"flag" to CiFlag,
|
||||
"flame" to CiFlame,
|
||||
"flash" to CiFlash,
|
||||
"flashOff" to CiFlashOff,
|
||||
"flashlight" to CiFlashlight,
|
||||
"flask" to CiFlask,
|
||||
"flower" to CiFlower,
|
||||
"folder" to CiFolder,
|
||||
"folderOpen" to CiFolderOpen,
|
||||
"football" to CiFootball,
|
||||
"footsteps" to CiFootsteps,
|
||||
"funnel" to CiFunnel,
|
||||
"gameController" to CiGameController,
|
||||
"gift" to CiGift,
|
||||
"gitBranch" to CiGitBranch,
|
||||
"gitCommit" to CiGitCommit,
|
||||
"gitCompare" to CiGitCompare,
|
||||
"gitMerge" to CiGitMerge,
|
||||
"gitNetwork" to CiGitNetwork,
|
||||
"gitPullRequest" to CiGitPullRequest,
|
||||
"glasses" to CiGlasses,
|
||||
"globe" to CiGlobe,
|
||||
"golf" to CiGolf,
|
||||
"grid" to CiGrid,
|
||||
"hammer" to CiHammer,
|
||||
"handLeft" to CiHandLeft,
|
||||
"handRight" to CiHandRight,
|
||||
"happy" to CiHappy,
|
||||
"hardwareChip" to CiHardwareChip,
|
||||
"headset" to CiHeadset,
|
||||
"heart" to CiHeart,
|
||||
"heartCircle" to CiHeartCircle,
|
||||
"heartDislike" to CiHeartDislike,
|
||||
"heartDislikeCircle" to CiHeartDislikeCircle,
|
||||
"heartHalf" to CiHeartHalf,
|
||||
"helpBuoy" to CiHelpBuoy,
|
||||
"helpCircle" to CiHelpCircle,
|
||||
"home" to CiHome,
|
||||
"hourglass" to CiHourglass,
|
||||
"iceCream" to CiIceCream,
|
||||
"idCard" to CiIdCard,
|
||||
"image" to CiImage,
|
||||
"images" to CiImages,
|
||||
"infinite" to CiInfinite,
|
||||
"informationCircle" to CiInformationCircle,
|
||||
"invertMode" to CiInvertMode,
|
||||
"journal" to CiJournal,
|
||||
"key" to CiKey,
|
||||
"keypad" to CiKeypad,
|
||||
"language" to CiLanguage,
|
||||
"laptop" to CiLaptop,
|
||||
"layers" to CiLayers,
|
||||
"leaf" to CiLeaf,
|
||||
"library" to CiLibrary,
|
||||
"link" to CiLink,
|
||||
"list" to CiList,
|
||||
"listCircle" to CiListCircle,
|
||||
"locate" to CiLocate,
|
||||
"location" to CiLocation,
|
||||
"lockClosed" to CiLockClosed,
|
||||
"lockOpen" to CiLockOpen,
|
||||
"logIn" to CiLogIn,
|
||||
"logOut" to CiLogOut,
|
||||
"logoAlipay" to CiLogoAlipay,
|
||||
"logoAmazon" to CiLogoAmazon,
|
||||
"logoAmplify" to CiLogoAmplify,
|
||||
"logoAndroid" to CiLogoAndroid,
|
||||
"magnet" to CiMagnet,
|
||||
"mail" to CiMail,
|
||||
"mailOpen" to CiMailOpen,
|
||||
"mailUnread" to CiMailUnread,
|
||||
"male" to CiMale,
|
||||
"maleFemale" to CiMaleFemale,
|
||||
"man" to CiMan,
|
||||
"map" to CiMap,
|
||||
"medal" to CiMedal,
|
||||
"medical" to CiMedical,
|
||||
"medkit" to CiMedkit,
|
||||
"megaphone" to CiMegaphone,
|
||||
"menu" to CiMenu,
|
||||
"mic" to CiMic,
|
||||
"micCircle" to CiMicCircle,
|
||||
"micOff" to CiMicOff,
|
||||
"micOffCircle" to CiMicOffCircle,
|
||||
"moon" to CiMoon,
|
||||
"move" to CiMove,
|
||||
"musicalNote" to CiMusicalNote,
|
||||
"musicalNotes" to CiMusicalNotes,
|
||||
"navigate" to CiNavigate,
|
||||
"navigateCircle" to CiNavigateCircle,
|
||||
"newspaper" to CiNewspaper,
|
||||
"notifications" to CiNotifications,
|
||||
"notificationsCircle" to CiNotificationsCircle,
|
||||
"notificationsOff" to CiNotificationsOff,
|
||||
"notificationsOffCircle" to CiNotificationsOffCircle,
|
||||
"nuclear" to CiNuclear,
|
||||
"nutrition" to CiNutrition,
|
||||
"options" to CiOptions,
|
||||
"paperPlane" to CiPaperPlane,
|
||||
"partlySunny" to CiPartlySunny,
|
||||
"pause" to CiPause,
|
||||
"pauseCircle" to CiPauseCircle,
|
||||
"paw" to CiPaw,
|
||||
"pencil" to CiPencil,
|
||||
"people" to CiPeople,
|
||||
"peopleCircle" to CiPeopleCircle,
|
||||
"person" to CiPerson,
|
||||
"personAdd" to CiPersonAdd,
|
||||
"personCircle" to CiPersonCircle,
|
||||
"personRemove" to CiPersonRemove,
|
||||
"phoneLandscape" to CiPhoneLandscape,
|
||||
"phonePortrait" to CiPhonePortrait,
|
||||
"pieChart" to CiPieChart,
|
||||
"pin" to CiPin,
|
||||
"pint" to CiPint,
|
||||
"pizza" to CiPizza,
|
||||
"planet" to CiPlanet,
|
||||
"play" to CiPlay,
|
||||
"playBack" to CiPlayBack,
|
||||
"playBackCircle" to CiPlayBackCircle,
|
||||
"playCircle" to CiPlayCircle,
|
||||
"playForward" to CiPlayForward,
|
||||
"playForwardCircle" to CiPlayForwardCircle,
|
||||
"playSkipBack" to CiPlaySkipBack,
|
||||
"playSkipBackCircle" to CiPlaySkipBackCircle,
|
||||
"playSkipForward" to CiPlaySkipForward,
|
||||
"playSkipForwardCircle" to CiPlaySkipForwardCircle,
|
||||
"podium" to CiPodium,
|
||||
"power" to CiPower,
|
||||
"pricetag" to CiPricetag,
|
||||
"pricetags" to CiPricetags,
|
||||
"print" to CiPrint,
|
||||
"prism" to CiPrism,
|
||||
"pulse" to CiPulse,
|
||||
"push" to CiPush,
|
||||
"qrCode" to CiQrCode,
|
||||
"radio" to CiRadio,
|
||||
"radioButtonOff" to CiRadioButtonOff,
|
||||
"radioButtonOn" to CiRadioButtonOn,
|
||||
"rainy" to CiRainy,
|
||||
"reader" to CiReader,
|
||||
"receipt" to CiReceipt,
|
||||
"recording" to CiRecording,
|
||||
"refresh" to CiRefresh,
|
||||
"refreshCircle" to CiRefreshCircle,
|
||||
"reload" to CiReload,
|
||||
"reloadCircle" to CiReloadCircle,
|
||||
"removeCircle" to CiRemoveCircle,
|
||||
"repeat" to CiRepeat,
|
||||
"resize" to CiResize,
|
||||
"restaurant" to CiRestaurant,
|
||||
"ribbon" to CiRibbon,
|
||||
"rocket" to CiRocket,
|
||||
"rose" to CiRose,
|
||||
"sad" to CiSad,
|
||||
"save" to CiSave,
|
||||
"scale" to CiScale,
|
||||
"scan" to CiScan,
|
||||
"scanCircle" to CiScanCircle,
|
||||
"school" to CiSchool,
|
||||
"search" to CiSearch,
|
||||
"searchCircle" to CiSearchCircle,
|
||||
"send" to CiSend,
|
||||
"server" to CiServer,
|
||||
"settings" to CiSettings,
|
||||
"shapes" to CiShapes,
|
||||
"share" to CiShare,
|
||||
"shareSocial" to CiShareSocial,
|
||||
"shield" to CiShield,
|
||||
"shieldCheckmark" to CiShieldCheckmark,
|
||||
"shieldHalf" to CiShieldHalf,
|
||||
"shirt" to CiShirt,
|
||||
"shuffle" to CiShuffle,
|
||||
"skull" to CiSkull,
|
||||
"snow" to CiSnow,
|
||||
"sparkles" to CiSparkles,
|
||||
"speedometer" to CiSpeedometer,
|
||||
"square" to CiSquare,
|
||||
"star" to CiStar,
|
||||
"starHalf" to CiStarHalf,
|
||||
"statsChart" to CiStatsChart,
|
||||
"stop" to CiStop,
|
||||
"stopCircle" to CiStopCircle,
|
||||
"stopwatch" to CiStopwatch,
|
||||
"storefront" to CiStorefront,
|
||||
"subway" to CiSubway,
|
||||
"sunny" to CiSunny,
|
||||
"swapHorizontal" to CiSwapHorizontal,
|
||||
"swapVertical" to CiSwapVertical,
|
||||
"sync" to CiSync,
|
||||
"syncCircle" to CiSyncCircle,
|
||||
"tabletLandscape" to CiTabletLandscape,
|
||||
"tabletPortrait" to CiTabletPortrait,
|
||||
"telescope" to CiTelescope,
|
||||
"tennisball" to CiTennisball,
|
||||
"terminal" to CiTerminal,
|
||||
"text" to CiText,
|
||||
"thermometer" to CiThermometer,
|
||||
"thumbsDown" to CiThumbsDown,
|
||||
"thumbsUp" to CiThumbsUp,
|
||||
"thunderstorm" to CiThunderstorm,
|
||||
"ticket" to CiTicket,
|
||||
"time" to CiTime,
|
||||
"timer" to CiTimer,
|
||||
"today" to CiToday,
|
||||
"toggle" to CiToggle,
|
||||
"trailSign" to CiTrailSign,
|
||||
"train" to CiTrain,
|
||||
"transgender" to CiTransgender,
|
||||
"trash" to CiTrash,
|
||||
"trashBin" to CiTrashBin,
|
||||
"trendingDown" to CiTrendingDown,
|
||||
"trendingUp" to CiTrendingUp,
|
||||
"triangle" to CiTriangle,
|
||||
"trophy" to CiTrophy,
|
||||
"tv" to CiTv,
|
||||
"umbrella" to CiUmbrella,
|
||||
"unlink" to CiUnlink,
|
||||
"videocam" to CiVideocam,
|
||||
"videocamOff" to CiVideocamOff,
|
||||
"volumeHigh" to CiVolumeHigh,
|
||||
"volumeLow" to CiVolumeLow,
|
||||
"volumeMedium" to CiVolumeMedium,
|
||||
"volumeMute" to CiVolumeMute,
|
||||
"volumeOff" to CiVolumeOff,
|
||||
"walk" to CiWalk,
|
||||
"wallet" to CiWallet,
|
||||
"warning" to CiWarning,
|
||||
"watch" to CiWatch,
|
||||
"water" to CiWater,
|
||||
"wifi" to CiWifi,
|
||||
"wine" to CiWine,
|
||||
"woman" to CiWoman
|
||||
)
|
||||
mapOf()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,14 +30,14 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil.compose.rememberAsyncImagePainter
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
||||
import com.anytypeio.anytype.core_ui.views.BodyRegular
|
||||
import com.anytypeio.anytype.core_ui.views.Caption1Medium
|
||||
import com.anytypeio.anytype.emojifier.Emojifier
|
||||
import com.anytypeio.anytype.core_ui.widgets.ListWidgetObjectIcon
|
||||
import com.anytypeio.anytype.presentation.editor.EditorViewModel
|
||||
import com.anytypeio.anytype.presentation.editor.EditorViewModel.TypesWidgetItem
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectTypeView
|
||||
|
||||
|
||||
|
@ -50,11 +50,11 @@ fun MyChooseTypeHorizontalWidget() {
|
|||
TypesWidgetItem.Search,
|
||||
TypesWidgetItem.Type(
|
||||
item = ObjectTypeView(
|
||||
emoji = "👍",
|
||||
name = "Like",
|
||||
id = "12312",
|
||||
description = null,
|
||||
key = "dd"
|
||||
key = "dd",
|
||||
icon = ObjectIcon.None
|
||||
)
|
||||
)
|
||||
),
|
||||
|
@ -72,11 +72,11 @@ fun MyChooseTypeHorizontalWidgetCollapsed() {
|
|||
TypesWidgetItem.Search,
|
||||
TypesWidgetItem.Type(
|
||||
item = ObjectTypeView(
|
||||
emoji = "👍",
|
||||
name = "Like",
|
||||
id = "12312",
|
||||
description = null,
|
||||
key = "dd"
|
||||
key = "dd",
|
||||
icon = ObjectIcon.None
|
||||
)
|
||||
)
|
||||
),
|
||||
|
@ -158,15 +158,11 @@ fun ChooseTypeHorizontalWidgetExpanded(
|
|||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
val uri = Emojifier.safeUri(item.item.emoji.orEmpty())
|
||||
if (uri.isNotEmpty()) {
|
||||
Image(
|
||||
painter = rememberAsyncImagePainter(uri),
|
||||
contentDescription = "Icon from URI",
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
}
|
||||
ListWidgetObjectIcon(
|
||||
modifier = Modifier.size(16.dp),
|
||||
icon = item.item.icon
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = item.item.name,
|
||||
style = Caption1Medium,
|
||||
|
|
|
@ -108,6 +108,8 @@ class ObjectTypesSubscriptionManager (
|
|||
Relations.LAYOUT,
|
||||
Relations.DESCRIPTION,
|
||||
Relations.ICON_EMOJI,
|
||||
Relations.ICON_NAME,
|
||||
Relations.ICON_OPTION,
|
||||
Relations.SOURCE_OBJECT,
|
||||
Relations.IS_READ_ONLY,
|
||||
Relations.RECOMMENDED_LAYOUT,
|
||||
|
|
|
@ -58,6 +58,7 @@ interface ProfileSubscriptionManager : GlobalSubscription {
|
|||
Relations.ID,
|
||||
Relations.NAME,
|
||||
Relations.ICON_EMOJI,
|
||||
Relations.ICON_NAME,
|
||||
Relations.ICON_IMAGE,
|
||||
Relations.ICON_OPTION,
|
||||
Relations.SHARED_SPACES_LIMIT
|
||||
|
|
|
@ -74,6 +74,7 @@ class GetTemplates(
|
|||
Relations.NAME,
|
||||
Relations.LAYOUT,
|
||||
Relations.ICON_EMOJI,
|
||||
Relations.ICON_NAME,
|
||||
Relations.ICON_IMAGE,
|
||||
Relations.ICON_OPTION,
|
||||
Relations.COVER_ID,
|
||||
|
|
|
@ -214,14 +214,14 @@ fun ObjectWrapper.Basic.toAllContentItem(
|
|||
)
|
||||
}
|
||||
|
||||
fun List<ObjectWrapper.Basic>.toUiContentTypes(
|
||||
fun List<ObjectWrapper.Type>.toUiContentTypes(
|
||||
urlBuilder: UrlBuilder,
|
||||
isOwnerOrEditor: Boolean
|
||||
): List<UiContentItem.Type> {
|
||||
return map { it.toAllContentType(urlBuilder, isOwnerOrEditor) }
|
||||
}
|
||||
|
||||
fun ObjectWrapper.Basic.toAllContentType(
|
||||
fun ObjectWrapper.Type.toAllContentType(
|
||||
urlBuilder: UrlBuilder,
|
||||
isOwnerOrEditor: Boolean
|
||||
): UiContentItem.Type {
|
||||
|
|
|
@ -316,10 +316,12 @@ class AllContentViewModel(
|
|||
val isOwnerOrEditor = permission.value?.isOwnerOrEditor() == true
|
||||
return when (activeTab) {
|
||||
AllContentTab.TYPES -> {
|
||||
val items = objectWrappers.toUiContentTypes(
|
||||
urlBuilder = urlBuilder,
|
||||
isOwnerOrEditor = isOwnerOrEditor
|
||||
)
|
||||
val items = objectWrappers
|
||||
.map { ObjectWrapper.Type(it.map) }
|
||||
.toUiContentTypes(
|
||||
urlBuilder = urlBuilder,
|
||||
isOwnerOrEditor = isOwnerOrEditor
|
||||
)
|
||||
buildList {
|
||||
if (isOwnerOrEditor) add(UiContentItem.NewType)
|
||||
addAll(items)
|
||||
|
@ -346,11 +348,19 @@ class AllContentViewModel(
|
|||
}
|
||||
val result = when (activeSort) {
|
||||
is ObjectsListSort.ByDateCreated -> {
|
||||
groupItemsByDate(items = items, isSortByDateCreated = true, activeSort = activeSort)
|
||||
groupItemsByDate(
|
||||
items = items,
|
||||
isSortByDateCreated = true,
|
||||
activeSort = activeSort
|
||||
)
|
||||
}
|
||||
|
||||
is ObjectsListSort.ByDateUpdated -> {
|
||||
groupItemsByDate(items = items, isSortByDateCreated = false, activeSort = activeSort)
|
||||
groupItemsByDate(
|
||||
items = items,
|
||||
isSortByDateCreated = false,
|
||||
activeSort = activeSort
|
||||
)
|
||||
}
|
||||
|
||||
is ObjectsListSort.ByName -> {
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.anytypeio.anytype.feature_object_type.ui
|
|||
|
||||
import com.anytypeio.anytype.core_models.ObjectType.Layout
|
||||
import com.anytypeio.anytype.core_models.multiplayer.SpaceSyncAndP2PStatusState
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIconColor
|
||||
import com.anytypeio.anytype.presentation.templates.TemplateView
|
||||
|
||||
sealed class TypeEvent {
|
||||
|
@ -42,4 +44,10 @@ sealed class TypeEvent {
|
|||
data object OnLayoutButtonClick : TypeEvent()
|
||||
data object OnFieldsButtonClick : TypeEvent()
|
||||
data object OnTemplatesButtonClick : TypeEvent()
|
||||
|
||||
//region Icon picker
|
||||
data class OnIconPickerItemClick(val iconName: String, val color: CustomIconColor?) : TypeEvent()
|
||||
data object OnIconPickerRemovedClick : TypeEvent()
|
||||
data object OnIconPickerDismiss : TypeEvent()
|
||||
//endregion
|
||||
}
|
|
@ -29,8 +29,6 @@ sealed class ObjectTypeCommand {
|
|||
val spaceId: Id
|
||||
) : ObjectTypeCommand()
|
||||
|
||||
data object OpenEmojiPicker : ObjectTypeCommand()
|
||||
|
||||
data object OpenFieldsScreen : ObjectTypeCommand()
|
||||
|
||||
data class OpenEditTypePropertiesScreen(val typeId: Id, val space: Id) : ObjectTypeCommand()
|
||||
|
@ -230,4 +228,12 @@ sealed class UiSyncStatusBadgeState {
|
|||
data object Hidden : UiSyncStatusBadgeState()
|
||||
data class Visible(val status: SpaceSyncAndP2PStatusState) : UiSyncStatusBadgeState()
|
||||
}
|
||||
//endregion
|
||||
//endregion
|
||||
|
||||
//region Type icon screen
|
||||
sealed class UiIconsPickerState {
|
||||
data object Hidden : UiIconsPickerState()
|
||||
data object Visible : UiIconsPickerState()
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
|
|
@ -0,0 +1,307 @@
|
|||
package com.anytypeio.anytype.feature_object_type.ui.icons
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
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
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
|
||||
import com.anytypeio.anytype.core_ui.common.ReorderHapticFeedback
|
||||
import com.anytypeio.anytype.core_ui.common.ReorderHapticFeedbackType
|
||||
import com.anytypeio.anytype.core_ui.common.rememberReorderHapticFeedback
|
||||
import com.anytypeio.anytype.core_ui.extensions.colorRes
|
||||
import com.anytypeio.anytype.core_ui.foundation.DefaultSearchBar
|
||||
import com.anytypeio.anytype.core_ui.foundation.Divider
|
||||
import com.anytypeio.anytype.core_ui.foundation.Dragger
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
||||
import com.anytypeio.anytype.core_ui.views.BodyRegular
|
||||
import com.anytypeio.anytype.core_ui.views.Title1
|
||||
import com.anytypeio.anytype.core_ui.widgets.objectIcon.custom_icons.CustomIcons
|
||||
import com.anytypeio.anytype.feature_object_type.R
|
||||
import com.anytypeio.anytype.feature_object_type.ui.icons.ChangeIconScreenConst.secondRowColors
|
||||
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIconColor
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ChangeIconScreen(
|
||||
modifier: Modifier,
|
||||
onDismissRequest: () -> Unit,
|
||||
onIconClicked: (String, CustomIconColor?) -> Unit,
|
||||
onRemoveIconClicked: () -> Unit
|
||||
) {
|
||||
|
||||
val bottomSheetState = rememberModalBottomSheetState(
|
||||
skipPartiallyExpanded = true
|
||||
)
|
||||
|
||||
val allIconNames = remember { CustomIcons.iconsMap.keys.toList() }
|
||||
|
||||
ModalBottomSheet(
|
||||
modifier = modifier.windowInsetsPadding(WindowInsets.statusBars),
|
||||
dragHandle = {
|
||||
Column {
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
Dragger()
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
}
|
||||
},
|
||||
scrimColor = colorResource(id = R.color.modal_screen_outside_background),
|
||||
containerColor = colorResource(id = R.color.background_secondary),
|
||||
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
|
||||
sheetState = bottomSheetState,
|
||||
onDismissRequest = onDismissRequest
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(48.dp)
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
text = stringResource(R.string.object_type_icon_change_title),
|
||||
style = Title1,
|
||||
color = colorResource(R.color.text_primary),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.padding(end = 16.dp)
|
||||
.noRippleThrottledClickable {
|
||||
onRemoveIconClicked()
|
||||
},
|
||||
text = stringResource(R.string.object_type_icon_remove),
|
||||
style = BodyRegular,
|
||||
color = colorResource(R.color.palette_system_red),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
var searchQuery by remember { mutableStateOf("") }
|
||||
|
||||
DefaultSearchBar(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 10.dp),
|
||||
hint = R.string.object_type_icon_change_title_search_hint
|
||||
) { newQuery ->
|
||||
searchQuery = newQuery
|
||||
}
|
||||
|
||||
Divider(paddingStart = 0.dp, paddingEnd = 0.dp)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
val filteredIcons = if (searchQuery.isEmpty()) {
|
||||
allIconNames
|
||||
} else {
|
||||
allIconNames.filter { it.contains(searchQuery, ignoreCase = true) }
|
||||
}
|
||||
|
||||
IconSelectionGrid(
|
||||
icons = filteredIcons,
|
||||
onIconClicked = onIconClicked,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = 16.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(64.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun IconSelectionGrid(
|
||||
modifier: Modifier = Modifier,
|
||||
icons: List<String>,
|
||||
onIconClicked: (String, CustomIconColor?) -> Unit
|
||||
) {
|
||||
|
||||
val hapticFeedback = rememberReorderHapticFeedback()
|
||||
|
||||
LazyVerticalGrid(
|
||||
modifier = modifier,
|
||||
columns = GridCells.Adaptive(minSize = 57.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
items(
|
||||
items = icons,
|
||||
key = { iconName -> iconName },
|
||||
contentType = { "icon" }
|
||||
) { iconName ->
|
||||
IconItem(
|
||||
modifier = Modifier.wrapContentSize(),
|
||||
hapticFeedback = hapticFeedback,
|
||||
iconName = iconName,
|
||||
onIconClicked = onIconClicked
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun IconItem(
|
||||
modifier: Modifier,
|
||||
iconName: String,
|
||||
hapticFeedback: ReorderHapticFeedback,
|
||||
onIconClicked: (String, CustomIconColor?) -> Unit
|
||||
) {
|
||||
val showIconPreviews = remember { mutableStateOf(false) }
|
||||
Box(modifier = modifier
|
||||
.combinedClickable(
|
||||
enabled = true,
|
||||
onClick = {
|
||||
onIconClicked(iconName, null)
|
||||
},
|
||||
onLongClick = {
|
||||
hapticFeedback.performHapticFeedback(ReorderHapticFeedbackType.START)
|
||||
showIconPreviews.value = true
|
||||
}
|
||||
)) {
|
||||
val imageVector = CustomIcons.getImageVector(iconName)
|
||||
val tintColor = if (!showIconPreviews.value) {
|
||||
colorResource(id = CustomIconColor.Gray.colorRes())
|
||||
} else {
|
||||
colorResource(id = R.color.glyph_inactive)
|
||||
}
|
||||
if (imageVector != null) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.align(Alignment.Center),
|
||||
imageVector = imageVector,
|
||||
contentDescription = "Object Type icon",
|
||||
colorFilter = ColorFilter.tint(tintColor),
|
||||
)
|
||||
IconPreviews(
|
||||
imageVector = imageVector,
|
||||
show = showIconPreviews.value,
|
||||
onDismissRequest = { showIconPreviews.value = false },
|
||||
onIconClicked = { color ->
|
||||
showIconPreviews.value = false
|
||||
onIconClicked(iconName, color)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun IconPreviews(
|
||||
imageVector: ImageVector,
|
||||
show: Boolean,
|
||||
onDismissRequest: () -> Unit,
|
||||
onIconClicked: (CustomIconColor) -> Unit
|
||||
) {
|
||||
DropdownMenu(
|
||||
modifier = Modifier
|
||||
.wrapContentSize()
|
||||
.padding(horizontal = 12.dp, vertical = 4.dp),
|
||||
expanded = show,
|
||||
onDismissRequest = onDismissRequest,
|
||||
shape = RoundedCornerShape(size = 20.dp),
|
||||
containerColor = colorResource(id = R.color.background_primary),
|
||||
shadowElevation = 5.dp,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
ChangeIconScreenConst.firstRowColors.forEach { customColor ->
|
||||
val color = colorResource(id = customColor.colorRes())
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.noRippleThrottledClickable {
|
||||
onIconClicked(customColor)
|
||||
},
|
||||
imageVector = imageVector,
|
||||
contentDescription = "Object Type icon",
|
||||
colorFilter = ColorFilter.tint(color),
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
secondRowColors.forEach { customColor ->
|
||||
val color = colorResource(id = customColor.colorRes())
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.noRippleThrottledClickable {
|
||||
onIconClicked(customColor)
|
||||
},
|
||||
imageVector = imageVector,
|
||||
contentDescription = "Object Type icon",
|
||||
colorFilter = ColorFilter.tint(color),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ChangeIconScreenConst {
|
||||
val firstRowColors = listOf(
|
||||
CustomIconColor.Gray,
|
||||
CustomIconColor.Yellow,
|
||||
CustomIconColor.Amber,
|
||||
CustomIconColor.Red,
|
||||
CustomIconColor.Pink
|
||||
)
|
||||
|
||||
val secondRowColors = listOf(
|
||||
CustomIconColor.Purple,
|
||||
CustomIconColor.Blue,
|
||||
CustomIconColor.Sky,
|
||||
CustomIconColor.Teal,
|
||||
CustomIconColor.Green
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@DefaultPreviews
|
||||
fun DefaultChangeIconScreenPreview() {
|
||||
IconSelectionGrid(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
icons = CustomIcons.iconsMap.keys.toList(),
|
||||
onIconClicked = { _, _ -> },
|
||||
)
|
||||
}
|
|
@ -32,13 +32,13 @@ import com.anytypeio.anytype.feature_object_type.fields.UiFieldsListItem
|
|||
import com.anytypeio.anytype.feature_object_type.fields.UiFieldsListState
|
||||
import com.anytypeio.anytype.feature_object_type.fields.UiLocalsFieldsInfoState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.ObjectTypeCommand
|
||||
import com.anytypeio.anytype.feature_object_type.ui.ObjectTypeCommand.OpenEmojiPicker
|
||||
import com.anytypeio.anytype.feature_object_type.ui.ObjectTypeVmParams
|
||||
import com.anytypeio.anytype.feature_object_type.ui.TypeEvent
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiDeleteAlertState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiEditButton
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiErrorState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiFieldsButtonState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiIconsPickerState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiIconState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiLayoutButtonState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiLayoutTypeState
|
||||
|
@ -55,6 +55,7 @@ import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
|
|||
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
|
||||
import com.anytypeio.anytype.presentation.extension.sendAnalyticsScreenObjectType
|
||||
import com.anytypeio.anytype.presentation.mapper.objectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIconColor
|
||||
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants.defaultKeys
|
||||
import com.anytypeio.anytype.presentation.sync.SyncStatusWidgetState
|
||||
import com.anytypeio.anytype.presentation.sync.toSyncStatusWidgetState
|
||||
|
@ -135,6 +136,9 @@ class ObjectTypeViewModel(
|
|||
//edit property
|
||||
val uiEditPropertyScreen = MutableStateFlow<UiEditPropertyState>(UiEditPropertyState.Hidden)
|
||||
|
||||
//icons picker screen
|
||||
val uiIconsPickerScreen = MutableStateFlow<UiIconsPickerState>(UiIconsPickerState.Hidden)
|
||||
|
||||
//error
|
||||
val errorState = MutableStateFlow<UiErrorState>(UiErrorState.Hidden)
|
||||
//endregion
|
||||
|
@ -449,9 +453,7 @@ class ObjectTypeViewModel(
|
|||
}
|
||||
|
||||
TypeEvent.OnObjectTypeIconClick -> {
|
||||
viewModelScope.launch {
|
||||
commands.emit(OpenEmojiPicker)
|
||||
}
|
||||
uiIconsPickerScreen.value = UiIconsPickerState.Visible
|
||||
}
|
||||
|
||||
is TypeEvent.OnTemplateItemClick -> {
|
||||
|
@ -489,6 +491,20 @@ class ObjectTypeViewModel(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
TypeEvent.OnIconPickerDismiss -> {
|
||||
uiIconsPickerScreen.value = UiIconsPickerState.Hidden
|
||||
}
|
||||
|
||||
is TypeEvent.OnIconPickerItemClick -> {
|
||||
uiIconsPickerScreen.value = UiIconsPickerState.Hidden
|
||||
updateIcon(iconName = event.iconName, newColor = event.color)
|
||||
}
|
||||
|
||||
TypeEvent.OnIconPickerRemovedClick -> {
|
||||
uiIconsPickerScreen.value = UiIconsPickerState.Hidden
|
||||
removeIcon()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -584,30 +600,39 @@ class ObjectTypeViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun updateIcon(
|
||||
emoji: String
|
||||
private fun updateIcon(
|
||||
iconName: String,
|
||||
newColor: CustomIconColor?
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
val params = SetObjectDetails.Params(
|
||||
ctx = vmParams.objectId,
|
||||
details = mapOf(Relations.ICON_EMOJI to emoji)
|
||||
details = mapOf(
|
||||
Relations.ICON_EMOJI to null,
|
||||
Relations.ICON_NAME to iconName,
|
||||
Relations.ICON_OPTION to newColor?.iconOption?.toDouble()
|
||||
)
|
||||
)
|
||||
setObjectDetails.async(params).fold(
|
||||
onFailure = { error ->
|
||||
Timber.e(error, "Error while updating data view record")
|
||||
},
|
||||
onSuccess = {
|
||||
|
||||
Timber.d("Object type icon updated to icon: $iconName")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeIcon() {
|
||||
private fun removeIcon() {
|
||||
viewModelScope.launch {
|
||||
val params = SetObjectDetails.Params(
|
||||
ctx = vmParams.objectId,
|
||||
details = mapOf(Relations.ICON_EMOJI to null)
|
||||
details = mapOf(
|
||||
Relations.ICON_EMOJI to null,
|
||||
Relations.ICON_NAME to null,
|
||||
Relations.ICON_OPTION to null
|
||||
)
|
||||
)
|
||||
setObjectDetails.async(params).fold(
|
||||
onFailure = { error ->
|
||||
|
@ -700,6 +725,7 @@ class ObjectTypeViewModel(
|
|||
currentList.add(toIndex, item)
|
||||
uiFieldsListState.value = UiFieldsListState(items = currentList)
|
||||
}
|
||||
|
||||
is FieldEvent.EditProperty -> proceedWithEditPropertyEvent(event)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1986,4 +1986,8 @@ Please provide specific details of your needs here.</string>
|
|||
<string name="property_edit_menu_unlink">Unlink from type</string>
|
||||
<string name="delete_space_checkbox_text">I have read and want to delete this space</string>
|
||||
|
||||
<string name="object_type_icon_change_title">Change icon</string>
|
||||
<string name="object_type_icon_remove">Remove</string>
|
||||
<string name="object_type_icon_change_title_search_hint">Search..."</string>
|
||||
|
||||
</resources>
|
|
@ -5281,7 +5281,8 @@ class EditorViewModel(
|
|||
isWithCollection = false,
|
||||
isWithBookmark = false,
|
||||
selectedTypes = emptyList(),
|
||||
excludeTypes = emptyList()
|
||||
excludeTypes = emptyList(),
|
||||
urlBuilder = urlBuilder
|
||||
)
|
||||
action.invoke(views)
|
||||
}
|
||||
|
@ -6417,7 +6418,8 @@ class EditorViewModel(
|
|||
objects.getObjectTypeViewsForSBPage(
|
||||
isWithCollection = true,
|
||||
isWithBookmark = false,
|
||||
excludeTypes = excludeTypes
|
||||
excludeTypes = excludeTypes,
|
||||
urlBuilder = urlBuilder
|
||||
).filter {
|
||||
!excludeTypes.contains(it.key)
|
||||
}.map {
|
||||
|
|
|
@ -724,23 +724,27 @@ fun ColumnView.Format.toRelationFormat(): RelationFormat = when (this) {
|
|||
ColumnView.Format.UNDEFINED -> RelationFormat.UNDEFINED
|
||||
}
|
||||
|
||||
fun ObjectWrapper.Type.toObjectTypeView(selectedSources: List<Id> = emptyList()): ObjectTypeView =
|
||||
fun ObjectWrapper.Type.toObjectTypeView(
|
||||
selectedSources: List<Id> = emptyList(),
|
||||
urlBuilder: UrlBuilder
|
||||
): ObjectTypeView =
|
||||
ObjectTypeView(
|
||||
id = id,
|
||||
key = uniqueKey,
|
||||
name = name.orEmpty(),
|
||||
emoji = iconEmoji,
|
||||
description = description,
|
||||
isSelected = selectedSources.contains(id),
|
||||
defaultTemplate = defaultTemplateId,
|
||||
sourceObject = sourceObject
|
||||
sourceObject = sourceObject,
|
||||
icon = objectIcon(urlBuilder)
|
||||
)
|
||||
|
||||
fun List<ObjectWrapper.Type>.toTemplateObjectTypeViewItems(selectedType: Id): List<TemplateObjectTypeView.Item> {
|
||||
fun List<ObjectWrapper.Type>.toTemplateObjectTypeViewItems(selectedType: Id, urlBuilder: UrlBuilder): List<TemplateObjectTypeView.Item> {
|
||||
return map {
|
||||
TemplateObjectTypeView.Item(
|
||||
type = it,
|
||||
isSelected = it.id == selectedType
|
||||
isSelected = it.id == selectedType,
|
||||
icon = it.objectIcon(urlBuilder)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder
|
|||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon.Basic
|
||||
import com.anytypeio.anytype.core_models.SupportedLayouts
|
||||
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIcon
|
||||
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIconColor
|
||||
|
||||
fun ObjectWrapper.Basic.objectIcon(builder: UrlBuilder): ObjectIcon {
|
||||
|
||||
|
@ -17,7 +19,9 @@ fun ObjectWrapper.Basic.objectIcon(builder: UrlBuilder): ObjectIcon {
|
|||
image = iconImage,
|
||||
emoji = iconEmoji,
|
||||
builder = builder,
|
||||
name = name.orEmpty()
|
||||
name = name.orEmpty(),
|
||||
iconName = iconName,
|
||||
iconOption = iconOption?.toInt()
|
||||
)
|
||||
|
||||
if (objectIcon != null) {
|
||||
|
@ -49,7 +53,9 @@ fun ObjectWrapper.Type.objectIcon(builder: UrlBuilder): ObjectIcon {
|
|||
image = null,
|
||||
emoji = iconEmoji,
|
||||
builder = builder,
|
||||
name = name.orEmpty()
|
||||
name = name.orEmpty(),
|
||||
iconName = iconName,
|
||||
iconOption = iconOption?.toInt()
|
||||
)
|
||||
|
||||
if (objectIcon != null) {
|
||||
|
@ -76,16 +82,22 @@ fun ObjectType.Layout?.emptyType(): ObjectIcon.Empty {
|
|||
fun ObjectType.Layout.icon(
|
||||
image: String?,
|
||||
emoji: String?,
|
||||
iconName: String?,
|
||||
iconOption: Int?,
|
||||
name: String,
|
||||
builder: UrlBuilder
|
||||
): ObjectIcon? {
|
||||
return when (this) {
|
||||
ObjectType.Layout.OBJECT_TYPE -> handleObjectTypeIcon(
|
||||
emoji = emoji,
|
||||
iconName = iconName,
|
||||
iconOption = iconOption
|
||||
)
|
||||
|
||||
ObjectType.Layout.BASIC,
|
||||
ObjectType.Layout.SET,
|
||||
ObjectType.Layout.COLLECTION,
|
||||
ObjectType.Layout.IMAGE,
|
||||
ObjectType.Layout.OBJECT_TYPE -> basicIcon(
|
||||
ObjectType.Layout.IMAGE -> basicIcon(
|
||||
image = image,
|
||||
emoji = emoji,
|
||||
builder = builder,
|
||||
|
@ -110,6 +122,31 @@ fun ObjectType.Layout.icon(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles icons for OBJECT_TYPE layout.
|
||||
*/
|
||||
private fun handleObjectTypeIcon(
|
||||
emoji: String?,
|
||||
iconName: String?,
|
||||
iconOption: Int?,
|
||||
): ObjectIcon? {
|
||||
return when {
|
||||
!emoji.isNullOrEmpty() -> {
|
||||
Basic.Emoji(
|
||||
unicode = emoji,
|
||||
emptyState = ObjectType.Layout.OBJECT_TYPE.emptyType()
|
||||
)
|
||||
}
|
||||
iconName.isNullOrEmpty() -> ObjectIcon.Empty.ObjectType
|
||||
else -> ObjectIcon.ObjectType(
|
||||
icon = CustomIcon(
|
||||
rawValue = iconName,
|
||||
color = CustomIconColor.fromIconOption(iconOption)
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun basicIcon(
|
||||
image: String?,
|
||||
emoji: String?,
|
||||
|
|
|
@ -4,6 +4,8 @@ import com.anytypeio.anytype.core_models.Hash
|
|||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.Url
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIcon
|
||||
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIconColor
|
||||
|
||||
sealed class ObjectIcon {
|
||||
|
||||
|
@ -41,6 +43,7 @@ sealed class ObjectIcon {
|
|||
data object Deleted : ObjectIcon()
|
||||
|
||||
data class Checkbox(val isChecked: Boolean) : ObjectIcon()
|
||||
data class ObjectType(val icon: CustomIcon) : ObjectIcon()
|
||||
}
|
||||
|
||||
sealed class SpaceMemberIconView {
|
||||
|
|
|
@ -17,6 +17,7 @@ import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
|||
import com.anytypeio.anytype.domain.base.fold
|
||||
import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes
|
||||
import com.anytypeio.anytype.domain.launch.GetDefaultObjectType
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.spaces.AddObjectToSpace
|
||||
import com.anytypeio.anytype.domain.spaces.AddObjectTypeToSpace
|
||||
import com.anytypeio.anytype.domain.workspace.SpaceManager
|
||||
|
@ -42,6 +43,7 @@ class ObjectTypeChangeViewModel(
|
|||
private val dispatchers: AppCoroutineDispatchers,
|
||||
private val spaceManager: SpaceManager,
|
||||
private val getDefaultObjectType: GetDefaultObjectType,
|
||||
private val urlBuilder: UrlBuilder
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val userInput = MutableStateFlow(DEFAULT_INPUT)
|
||||
|
@ -219,7 +221,8 @@ class ObjectTypeChangeViewModel(
|
|||
isWithBookmark = setup.isWithBookmark,
|
||||
excludeTypes = setup.excludeTypes,
|
||||
selectedTypes = setup.selectedTypes,
|
||||
useCustomComparator = false
|
||||
useCustomComparator = false,
|
||||
urlBuilder = urlBuilder
|
||||
).map {
|
||||
ObjectTypeItemView.Type(it)
|
||||
}
|
||||
|
@ -234,7 +237,8 @@ class ObjectTypeChangeViewModel(
|
|||
isWithBookmark = setup.isWithBookmark,
|
||||
excludeTypes = setup.excludeTypes,
|
||||
selectedTypes = setup.selectedTypes,
|
||||
useCustomComparator = false
|
||||
useCustomComparator = false,
|
||||
urlBuilder = urlBuilder
|
||||
).map {
|
||||
ObjectTypeItemView.Type(it)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModelProvider
|
|||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes
|
||||
import com.anytypeio.anytype.domain.launch.GetDefaultObjectType
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.spaces.AddObjectTypeToSpace
|
||||
import com.anytypeio.anytype.domain.workspace.SpaceManager
|
||||
|
||||
|
@ -13,7 +14,8 @@ class ObjectTypeChangeViewModelFactory(
|
|||
private val addObjectTypeToSpace: AddObjectTypeToSpace,
|
||||
private val dispatchers: AppCoroutineDispatchers,
|
||||
private val spaceManager: SpaceManager,
|
||||
private val getDefaultObjectType: GetDefaultObjectType
|
||||
private val getDefaultObjectType: GetDefaultObjectType,
|
||||
private val urlBuilder: UrlBuilder
|
||||
) : ViewModelProvider.Factory {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
@ -23,7 +25,8 @@ class ObjectTypeChangeViewModelFactory(
|
|||
addObjectTypeToSpace = addObjectTypeToSpace,
|
||||
dispatchers = dispatchers,
|
||||
spaceManager = spaceManager,
|
||||
getDefaultObjectType = getDefaultObjectType
|
||||
getDefaultObjectType = getDefaultObjectType,
|
||||
urlBuilder = urlBuilder
|
||||
) as T
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ import com.anytypeio.anytype.presentation.mapper.toObjectTypeView
|
|||
import com.anytypeio.anytype.core_models.SupportedLayouts.editorLayouts
|
||||
import com.anytypeio.anytype.core_models.SupportedLayouts.fileLayouts
|
||||
import com.anytypeio.anytype.core_models.SupportedLayouts.systemLayouts
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
||||
|
||||
/**
|
||||
|
@ -34,7 +35,8 @@ fun List<ObjectWrapper.Type>.getObjectTypeViewsForSBPage(
|
|||
isWithBookmark: Boolean = false,
|
||||
excludeTypes: List<String> = emptyList(),
|
||||
selectedTypes: List<String> = emptyList(),
|
||||
useCustomComparator: Boolean = true
|
||||
useCustomComparator: Boolean = true,
|
||||
urlBuilder: UrlBuilder
|
||||
): List<ObjectTypeView> {
|
||||
val result = mutableListOf<ObjectTypeView>()
|
||||
forEach { obj ->
|
||||
|
@ -43,14 +45,14 @@ fun List<ObjectWrapper.Type>.getObjectTypeViewsForSBPage(
|
|||
}
|
||||
if (obj.uniqueKey == COLLECTION || obj.uniqueKey == SET) {
|
||||
if (isWithCollection) {
|
||||
val objTypeView = obj.toObjectTypeView(selectedTypes)
|
||||
val objTypeView = obj.toObjectTypeView(selectedTypes, urlBuilder)
|
||||
result.add(objTypeView)
|
||||
}
|
||||
return@forEach
|
||||
}
|
||||
if (obj.uniqueKey == BOOKMARK) {
|
||||
if (isWithBookmark) {
|
||||
val objTypeView = obj.toObjectTypeView(selectedTypes)
|
||||
val objTypeView = obj.toObjectTypeView(selectedTypes, urlBuilder)
|
||||
result.add(objTypeView)
|
||||
}
|
||||
return@forEach
|
||||
|
@ -58,7 +60,7 @@ fun List<ObjectWrapper.Type>.getObjectTypeViewsForSBPage(
|
|||
if (excludeTypes.contains(obj.id)) {
|
||||
return@forEach
|
||||
}
|
||||
val objTypeView = obj.toObjectTypeView(selectedTypes)
|
||||
val objTypeView = obj.toObjectTypeView(selectedTypes, urlBuilder)
|
||||
result.add(objTypeView)
|
||||
return@forEach
|
||||
}
|
||||
|
|
|
@ -21,10 +21,10 @@ data class ObjectTypeView(
|
|||
val key: Key,
|
||||
val name: String,
|
||||
val description: String?,
|
||||
val emoji: String?,
|
||||
val isSelected: Boolean = false,
|
||||
val defaultTemplate: Id? = null,
|
||||
val sourceObject: Id? = null
|
||||
val sourceObject: Id? = null,
|
||||
val icon: ObjectIcon
|
||||
)
|
||||
|
||||
class ObjectTypeViewComparator : Comparator<ObjectTypeView> {
|
||||
|
|
|
@ -26,6 +26,7 @@ import com.anytypeio.anytype.domain.base.fold
|
|||
import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes
|
||||
import com.anytypeio.anytype.domain.launch.GetDefaultObjectType
|
||||
import com.anytypeio.anytype.domain.launch.SetDefaultObjectType
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.objects.CreateBookmarkObject
|
||||
import com.anytypeio.anytype.domain.objects.CreatePrefilledNote
|
||||
import com.anytypeio.anytype.domain.spaces.AddObjectToSpace
|
||||
|
@ -35,6 +36,7 @@ import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
|
|||
import com.anytypeio.anytype.presentation.common.BaseViewModel
|
||||
import com.anytypeio.anytype.presentation.extension.sendAnalyticsObjectCreateEvent
|
||||
import com.anytypeio.anytype.presentation.home.OpenObjectNavigation
|
||||
import com.anytypeio.anytype.presentation.mapper.objectIcon
|
||||
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
@ -57,7 +59,8 @@ class SelectObjectTypeViewModel(
|
|||
private val createBookmarkObject: CreateBookmarkObject,
|
||||
private val createPrefilledNote: CreatePrefilledNote,
|
||||
private val analytics: Analytics,
|
||||
private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate
|
||||
private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate,
|
||||
private val urlBuilder: UrlBuilder
|
||||
) : BaseViewModel(), AnalyticSpaceHelperDelegate by analyticSpaceHelperDelegate {
|
||||
|
||||
val viewState = MutableStateFlow<SelectTypeViewState>(SelectTypeViewState.Loading)
|
||||
|
@ -133,7 +136,7 @@ class SelectObjectTypeViewModel(
|
|||
id = type.id,
|
||||
typeKey = type.uniqueKey,
|
||||
name = type.name.orEmpty(),
|
||||
icon = type.iconEmoji.orEmpty(),
|
||||
icon = type.objectIcon(urlBuilder),
|
||||
isPinned = true,
|
||||
isFirstInSection = index == 0,
|
||||
isLastInSection = index == pinnedTypes.lastIndex,
|
||||
|
@ -152,7 +155,7 @@ class SelectObjectTypeViewModel(
|
|||
id = type.id,
|
||||
typeKey = type.uniqueKey,
|
||||
name = type.name.orEmpty(),
|
||||
icon = type.iconEmoji.orEmpty(),
|
||||
icon = type.objectIcon(urlBuilder),
|
||||
isFirstInSection = index == 0,
|
||||
isLastInSection = index == pinnedTypes.lastIndex,
|
||||
isPinnable = true,
|
||||
|
@ -172,7 +175,7 @@ class SelectObjectTypeViewModel(
|
|||
id = type.id,
|
||||
typeKey = type.uniqueKey,
|
||||
name = type.name.orEmpty(),
|
||||
icon = type.iconEmoji.orEmpty(),
|
||||
icon = type.objectIcon(urlBuilder),
|
||||
isPinnable = true,
|
||||
isFirstInSection = index == 0,
|
||||
isLastInSection = index == pinnedTypes.lastIndex,
|
||||
|
@ -190,7 +193,7 @@ class SelectObjectTypeViewModel(
|
|||
id = type.id,
|
||||
typeKey = type.uniqueKey,
|
||||
name = type.name.orEmpty(),
|
||||
icon = type.iconEmoji.orEmpty(),
|
||||
icon = type.objectIcon(urlBuilder),
|
||||
isFromLibrary = true,
|
||||
isPinned = false,
|
||||
isPinnable = false,
|
||||
|
@ -464,7 +467,8 @@ class SelectObjectTypeViewModel(
|
|||
private val createBookmarkObject: CreateBookmarkObject,
|
||||
private val createPrefilledNote: CreatePrefilledNote,
|
||||
private val analytics: Analytics,
|
||||
private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate
|
||||
private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate,
|
||||
private val urlBuilder: UrlBuilder
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(
|
||||
|
@ -480,7 +484,8 @@ class SelectObjectTypeViewModel(
|
|||
createBookmarkObject = createBookmarkObject,
|
||||
createPrefilledNote = createPrefilledNote,
|
||||
analytics = analytics,
|
||||
analyticSpaceHelperDelegate = analyticSpaceHelperDelegate
|
||||
analyticSpaceHelperDelegate = analyticSpaceHelperDelegate,
|
||||
urlBuilder = urlBuilder
|
||||
) as T
|
||||
}
|
||||
|
||||
|
@ -515,7 +520,7 @@ sealed class SelectTypeView {
|
|||
val id: Id,
|
||||
val typeKey: Key,
|
||||
val name: String,
|
||||
val icon: String,
|
||||
val icon: ObjectIcon,
|
||||
val isFromLibrary: Boolean = false,
|
||||
val isPinned: Boolean = false,
|
||||
val isFirstInSection: Boolean = false,
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package com.anytypeio.anytype.presentation.objects.custom_icon
|
||||
|
||||
/**
|
||||
* Data class representing a custom icon.
|
||||
* @property rawValue The raw string representing the icon.
|
||||
* @property color The color of the icon, if any.
|
||||
*/
|
||||
data class CustomIcon(
|
||||
val rawValue: String,
|
||||
val color: CustomIconColor = CustomIconColor.DEFAULT
|
||||
) {
|
||||
/**
|
||||
* Returns the drawable resource name for this icon.
|
||||
*
|
||||
* The drawable name is generated by converting [rawValue] from kebab-case
|
||||
* (e.g., "battery-dead") to snake_case ("battery_dead") and prefixing it with "ci_".
|
||||
*/
|
||||
val drawableResId: String
|
||||
get() = DEFAULT_ICON_PREFIX + rawValue.toSnakeCase()
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_ICON_PREFIX = "ci_"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension function that converts a kebab-case string to snake_case.
|
||||
*
|
||||
* Simply replaces all occurrences of '-' with '_'.
|
||||
*
|
||||
* @receiver String to be converted.
|
||||
* @return The snake_case version of the string.
|
||||
*/
|
||||
private fun String.toSnakeCase(): String = replace("-", "_")
|
|
@ -0,0 +1,61 @@
|
|||
package com.anytypeio.anytype.presentation.objects.custom_icon
|
||||
|
||||
/**
|
||||
* Enum representing custom icon colors with associated raw integer values.
|
||||
*
|
||||
* Each color has a corresponding [iconOption] and [id]. The [iconOption] is
|
||||
* computed as the raw value plus one, while the [id] is equal to the raw value.
|
||||
* The default color is specified by [DEFAULT].
|
||||
*/
|
||||
enum class CustomIconColor(val rawValue: Int) {
|
||||
Gray(0),
|
||||
Yellow(1),
|
||||
Amber(2),
|
||||
Red(3),
|
||||
Pink(4),
|
||||
Purple(5),
|
||||
Blue(6),
|
||||
Sky(7),
|
||||
Teal(8),
|
||||
Green(9);
|
||||
|
||||
/**
|
||||
* Returns the icon option corresponding to this color.
|
||||
*
|
||||
* This is calculated as the [rawValue] plus one.
|
||||
*/
|
||||
val iconOption: Int
|
||||
get() = rawValue + 1
|
||||
|
||||
/**
|
||||
* Returns the id corresponding to this color.
|
||||
*
|
||||
* The id is equal to the [rawValue].
|
||||
*/
|
||||
val id: Int
|
||||
get() = rawValue
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Default color used when a specific color is not provided.
|
||||
*/
|
||||
val DEFAULT: CustomIconColor = Gray
|
||||
|
||||
/**
|
||||
* Returns the [CustomIconColor] associated with the provided [iconOption].
|
||||
*
|
||||
* If [iconOption] is null or does not match any [CustomIconColor],
|
||||
* the [DEFAULT] color is returned.
|
||||
*
|
||||
* @param iconOption The icon option integer, which may be null.
|
||||
* @return The matching [CustomIconColor] or [DEFAULT] if no match is found.
|
||||
*/
|
||||
fun fromIconOption(iconOption: Int?): CustomIconColor {
|
||||
return if (iconOption == null) {
|
||||
DEFAULT
|
||||
} else {
|
||||
CustomIconColor.entries.find { it.iconOption == iconOption } ?: DEFAULT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -105,6 +105,8 @@ class LimitObjectTypeViewModel(
|
|||
Relations.SNIPPET,
|
||||
Relations.DESCRIPTION,
|
||||
Relations.ICON_EMOJI,
|
||||
Relations.ICON_NAME,
|
||||
Relations.ICON_OPTION,
|
||||
Relations.ICON_IMAGE,
|
||||
Relations.LAYOUT
|
||||
)
|
||||
|
|
|
@ -663,6 +663,7 @@ object ObjectSearchConstants {
|
|||
Relations.NAME,
|
||||
Relations.ICON_IMAGE,
|
||||
Relations.ICON_EMOJI,
|
||||
Relations.ICON_NAME,
|
||||
Relations.ICON_OPTION,
|
||||
Relations.TYPE,
|
||||
Relations.LAYOUT,
|
||||
|
@ -708,6 +709,8 @@ object ObjectSearchConstants {
|
|||
Relations.NAME,
|
||||
Relations.ICON_IMAGE,
|
||||
Relations.ICON_EMOJI,
|
||||
Relations.ICON_NAME,
|
||||
Relations.ICON_OPTION,
|
||||
Relations.TYPE,
|
||||
Relations.LAYOUT,
|
||||
Relations.IS_ARCHIVED,
|
||||
|
@ -733,6 +736,8 @@ object ObjectSearchConstants {
|
|||
Relations.NAME,
|
||||
Relations.DESCRIPTION,
|
||||
Relations.ICON_EMOJI,
|
||||
Relations.ICON_NAME,
|
||||
Relations.ICON_OPTION,
|
||||
Relations.TYPE,
|
||||
Relations.LAYOUT,
|
||||
Relations.IS_ARCHIVED,
|
||||
|
@ -975,6 +980,8 @@ object ObjectSearchConstants {
|
|||
Relations.DESCRIPTION,
|
||||
Relations.ICON_IMAGE,
|
||||
Relations.ICON_EMOJI,
|
||||
Relations.ICON_NAME,
|
||||
Relations.ICON_OPTION,
|
||||
Relations.TYPE,
|
||||
Relations.LAYOUT,
|
||||
Relations.IS_ARCHIVED,
|
||||
|
@ -1295,6 +1302,7 @@ object ObjectSearchConstants {
|
|||
Relations.NAME,
|
||||
Relations.ICON_IMAGE,
|
||||
Relations.ICON_EMOJI,
|
||||
Relations.ICON_NAME,
|
||||
Relations.ICON_OPTION,
|
||||
Relations.CREATED_DATE,
|
||||
Relations.SPACE_ACCOUNT_STATUS,
|
||||
|
|
|
@ -2230,7 +2230,7 @@ class ObjectSetViewModel(
|
|||
onSuccess = { types ->
|
||||
val list = buildList {
|
||||
add(TemplateObjectTypeView.Search)
|
||||
addAll(types.toTemplateObjectTypeViewItems(selectedType))
|
||||
addAll(types.toTemplateObjectTypeViewItems(selectedType, urlBuilder))
|
||||
}
|
||||
typeTemplatesWidgetState.value = widgetState.copy(objectTypes = list)
|
||||
},
|
||||
|
|
|
@ -78,6 +78,7 @@ class DefaultObjectTypeTemplatesContainer(
|
|||
Relations.TYPE_UNIQUE_KEY,
|
||||
Relations.NAME,
|
||||
Relations.ICON_EMOJI,
|
||||
Relations.ICON_NAME,
|
||||
Relations.ICON_IMAGE,
|
||||
Relations.ICON_OPTION,
|
||||
Relations.COVER_ID,
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.anytypeio.anytype.core_models.Url
|
|||
import com.anytypeio.anytype.core_models.primitives.TypeId
|
||||
import com.anytypeio.anytype.core_models.primitives.TypeKey
|
||||
import com.anytypeio.anytype.presentation.editor.cover.CoverColor
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
|
||||
sealed class TemplateView {
|
||||
|
||||
|
@ -69,6 +70,7 @@ sealed class TemplateObjectTypeView {
|
|||
|
||||
data class Item(
|
||||
val type: ObjectWrapper.Type,
|
||||
val icon: ObjectIcon,
|
||||
val isSelected: Boolean = false
|
||||
) : TemplateObjectTypeView()
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.anytypeio.anytype.presentation.editor.editor
|
|||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import com.anytypeio.anytype.core_models.ObjectViewDetails
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.Relation
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.core_models.StubRelationObject
|
||||
|
@ -14,6 +15,7 @@ import com.anytypeio.anytype.presentation.editor.editor.slash.SlashItem
|
|||
import com.anytypeio.anytype.presentation.editor.editor.slash.SlashRelationView
|
||||
import com.anytypeio.anytype.presentation.editor.editor.slash.SlashWidgetState
|
||||
import com.anytypeio.anytype.presentation.number.NumberParser
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectTypeView
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
|
||||
import com.anytypeio.anytype.presentation.util.DefaultCoroutineTestRule
|
||||
|
@ -367,8 +369,11 @@ class EditorSlashWidgetClicksTest: EditorPresentationTestSetup() {
|
|||
id = type1.id,
|
||||
key = type1.uniqueKey,
|
||||
name = type1.name.orEmpty(),
|
||||
icon = ObjectIcon.Basic.Emoji(
|
||||
unicode = type1.iconEmoji.orEmpty(),
|
||||
emptyState = ObjectIcon.Empty.ObjectType
|
||||
),
|
||||
description = type1.description,
|
||||
emoji = type1.iconEmoji
|
||||
)
|
||||
),
|
||||
SlashItem.ObjectType(
|
||||
|
@ -377,7 +382,10 @@ class EditorSlashWidgetClicksTest: EditorPresentationTestSetup() {
|
|||
key = type2.uniqueKey,
|
||||
name = type2.name.orEmpty(),
|
||||
description = type2.description,
|
||||
emoji = type2.iconEmoji
|
||||
icon = ObjectIcon.Basic.Emoji(
|
||||
unicode = type2.iconEmoji.orEmpty(),
|
||||
emptyState = ObjectIcon.Empty.ObjectType
|
||||
),
|
||||
)
|
||||
),
|
||||
SlashItem.ObjectType(
|
||||
|
@ -386,7 +394,10 @@ class EditorSlashWidgetClicksTest: EditorPresentationTestSetup() {
|
|||
key = type3.uniqueKey,
|
||||
name = type3.name.orEmpty(),
|
||||
description = type3.description,
|
||||
emoji = type3.iconEmoji
|
||||
icon = ObjectIcon.Basic.Emoji(
|
||||
unicode = type3.iconEmoji.orEmpty(),
|
||||
emptyState = ObjectIcon.Empty.ObjectType
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -19,6 +19,7 @@ import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent
|
|||
import com.anytypeio.anytype.presentation.editor.editor.slash.SlashItem
|
||||
import com.anytypeio.anytype.presentation.editor.editor.slash.SlashRelationView
|
||||
import com.anytypeio.anytype.presentation.editor.editor.slash.SlashWidgetState
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectTypeView
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
|
||||
import com.anytypeio.anytype.presentation.util.CoroutinesTestRule
|
||||
|
@ -470,7 +471,10 @@ class EditorSlashWidgetFilterTest : EditorPresentationTestSetup() {
|
|||
key = type1.uniqueKey,
|
||||
name = type1.name.orEmpty(),
|
||||
description = type1.description,
|
||||
emoji = type1.iconEmoji
|
||||
icon = ObjectIcon.Basic.Emoji(
|
||||
unicode = type1.iconEmoji.orEmpty(),
|
||||
emptyState = ObjectIcon.Empty.ObjectType
|
||||
),
|
||||
)
|
||||
),
|
||||
SlashItem.ObjectType(
|
||||
|
@ -479,7 +483,10 @@ class EditorSlashWidgetFilterTest : EditorPresentationTestSetup() {
|
|||
key = type2.uniqueKey,
|
||||
name = type2.name.orEmpty(),
|
||||
description = type2.description,
|
||||
emoji = type2.iconEmoji
|
||||
icon = ObjectIcon.Basic.Emoji(
|
||||
unicode = type2.iconEmoji.orEmpty(),
|
||||
emptyState = ObjectIcon.Empty.ObjectType
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -1508,7 +1515,10 @@ class EditorSlashWidgetFilterTest : EditorPresentationTestSetup() {
|
|||
key = type1.uniqueKey.orEmpty(),
|
||||
name = type1.name.orEmpty(),
|
||||
description = type1.description,
|
||||
emoji = type1.iconEmoji
|
||||
icon = ObjectIcon.Basic.Emoji(
|
||||
unicode = type1.iconEmoji.orEmpty(),
|
||||
emptyState = ObjectIcon.Empty.ObjectType
|
||||
),
|
||||
)
|
||||
),
|
||||
SlashItem.ObjectType(
|
||||
|
@ -1517,7 +1527,10 @@ class EditorSlashWidgetFilterTest : EditorPresentationTestSetup() {
|
|||
key = type2.uniqueKey.orEmpty(),
|
||||
name = type2.name.orEmpty(),
|
||||
description = type2.description,
|
||||
emoji = type2.iconEmoji
|
||||
icon = ObjectIcon.Basic.Emoji(
|
||||
unicode = type2.iconEmoji.orEmpty(),
|
||||
emptyState = ObjectIcon.Empty.ObjectType
|
||||
),
|
||||
)
|
||||
),
|
||||
SlashItem.ObjectType(
|
||||
|
@ -1526,7 +1539,10 @@ class EditorSlashWidgetFilterTest : EditorPresentationTestSetup() {
|
|||
key = type3.uniqueKey.orEmpty(),
|
||||
name = type3.name.orEmpty(),
|
||||
description = type3.description,
|
||||
emoji = type3.iconEmoji
|
||||
icon = ObjectIcon.Basic.Emoji(
|
||||
unicode = type3.iconEmoji.orEmpty(),
|
||||
emptyState = ObjectIcon.Empty.ObjectType
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -15,6 +15,7 @@ import com.anytypeio.anytype.presentation.editor.EditorViewModel.Companion.TEXT_
|
|||
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types
|
||||
import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent
|
||||
import com.anytypeio.anytype.presentation.editor.editor.slash.SlashItem
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectTypeView
|
||||
import com.anytypeio.anytype.presentation.util.DefaultCoroutineTestRule
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
@ -96,7 +97,7 @@ class EditorSlashWidgetObjectTypeTest : EditorPresentationTestSetup() {
|
|||
id = type2.id,
|
||||
name = type2.name.orEmpty(),
|
||||
description = type2.description,
|
||||
emoji = type2.iconEmoji,
|
||||
icon = ObjectIcon.None,
|
||||
key = type2.getValue<Key>(Relations.UNIQUE_KEY)!!
|
||||
)
|
||||
)
|
||||
|
@ -164,8 +165,8 @@ class EditorSlashWidgetObjectTypeTest : EditorPresentationTestSetup() {
|
|||
id = type2.id,
|
||||
name = type2.name.orEmpty(),
|
||||
description = type2.description,
|
||||
emoji = type2.iconEmoji,
|
||||
key = type2.getValue(Relations.UNIQUE_KEY)!!
|
||||
key = type2.getValue(Relations.UNIQUE_KEY)!!,
|
||||
icon = ObjectIcon.None
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -23,6 +23,8 @@ import com.anytypeio.anytype.domain.workspace.SpaceManager
|
|||
import com.anytypeio.anytype.presentation.objects.ObjectTypeChangeViewModel
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectTypeView
|
||||
import com.anytypeio.anytype.core_models.SupportedLayouts
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants
|
||||
import com.anytypeio.anytype.presentation.util.CoroutinesTestRule
|
||||
import com.anytypeio.anytype.test_utils.MockDataFactory
|
||||
|
@ -530,7 +532,7 @@ class ObjectTypeChangeViewModelTest {
|
|||
key = marketplaceType3.uniqueKey.orEmpty(),
|
||||
name = marketplaceType3.name.orEmpty(),
|
||||
description = marketplaceType3.description.orEmpty(),
|
||||
emoji = marketplaceType3.iconEmoji.orEmpty(),
|
||||
icon = ObjectIcon.None
|
||||
)
|
||||
vm.onItemClicked(item)
|
||||
assertEquals(
|
||||
|
@ -594,12 +596,16 @@ class ObjectTypeChangeViewModelTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Mock
|
||||
lateinit var urlBuilder: UrlBuilder
|
||||
|
||||
private fun givenViewModel() = ObjectTypeChangeViewModel(
|
||||
getObjectTypes = getObjectTypes,
|
||||
addObjectTypeToSpace = addObjectToSpace,
|
||||
dispatchers = dispatchers,
|
||||
spaceManager = spaceManager,
|
||||
getDefaultObjectType = getDefaultObjectType
|
||||
getDefaultObjectType = getDefaultObjectType,
|
||||
urlBuilder = urlBuilder
|
||||
)
|
||||
|
||||
fun stubSpaceManager(spaceId: Id) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue