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

DROID-3367 Primitives | Primitives | Object icons xml, part 3 (#2190)

This commit is contained in:
Konstantin Ivanov 2025-03-25 17:58:29 +01:00 committed by GitHub
parent 03935a7bc3
commit 6ad8e54721
Signed by: github
GPG key ID: B5690EEEBB952194
7 changed files with 95 additions and 61 deletions

View file

@ -71,7 +71,7 @@ private val CircularIndicatorDiameter = 40.dp
@Composable
fun LoadingIndicator(
containerModifier: Modifier = Modifier,
containerModifier: Modifier,
containerSize: Dp,
colorStart: Color = colorResource(id = R.color.glyph_active),
colorEnd: Color = Color.Transparent,

View file

@ -24,6 +24,8 @@ import com.anytypeio.anytype.core_utils.ext.invisible
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.emojifier.Emojifier
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.presentation.objects.ObjectIcon.TypeIcon
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIconColor
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import timber.log.Timber
@ -80,6 +82,11 @@ class ObjectIconWidget @JvmOverloads constructor(
this.width = emojiSize
}
tvEmojiFallback.updateLayoutParams<LayoutParams> {
this.height = emojiSize
this.width = emojiSize
}
ivImage.updateLayoutParams<LayoutParams> {
this.height = imageSize
this.width = imageSize
@ -138,7 +145,7 @@ class ObjectIconWidget @JvmOverloads constructor(
fun setIcon(icon: ObjectIcon) {
when (icon) {
is ObjectIcon.Basic.Emoji -> setEmoji(icon.unicode)
is ObjectIcon.Basic.Emoji -> setEmoji(emoji = icon.unicode, fallback = icon.fallback)
is ObjectIcon.Basic.Image -> setRectangularImage(icon.hash)
is ObjectIcon.Profile.Avatar -> setProfileInitials(icon.name)
is ObjectIcon.Profile.Image -> setCircularImage(icon.hash)
@ -149,9 +156,16 @@ class ObjectIconWidget @JvmOverloads constructor(
mime = icon.mime,
extension = icon.extensions
)
ObjectIcon.Deleted -> setDeletedIcon()
is ObjectIcon.Checkbox -> setCheckbox(icon.isChecked)
is ObjectIcon.TypeIcon -> setTypeIcon(icon)
is ObjectIcon.TypeIcon.Fallback -> setTypeIcon(icon)
is ObjectIcon.TypeIcon.Default -> setTypeIcon(icon)
ObjectIcon.TypeIcon.Deleted -> setTypeIcon(TypeIcon.Fallback.DEFAULT)
is ObjectIcon.TypeIcon.Emoji -> setEmoji(
emoji = icon.unicode,
fallback = TypeIcon.Fallback(rawValue = icon.rawValue)
)
}
}
@ -176,7 +190,10 @@ class ObjectIconWidget @JvmOverloads constructor(
}
}
private fun setEmoji(emoji: String?) {
private fun setEmoji(
emoji: String?,
fallback: ObjectIcon.TypeIcon.Fallback
) {
if (!emoji.isNullOrBlank()) {
with(binding) {
ivCheckbox.invisible()
@ -188,17 +205,17 @@ class ObjectIconWidget @JvmOverloads constructor(
}
try {
val adapted = Emojifier.safeUri(emoji)
if (adapted != Emojifier.Config.EMPTY_URI) {
binding.tvEmojiFallback.gone()
binding.ivEmoji.visible()
Glide
.with(this)
.load(Emojifier.uri(emoji))
.load(adapted)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(binding.ivEmoji)
} else {
binding.ivEmoji.setImageDrawable(null)
binding.tvEmojiFallback.text = emoji
binding.tvEmojiFallback.visible()
setTypeIcon(fallback)
}
} catch (e: Throwable) {
Timber.w(e, "Error while setting emoji icon for: $emoji")
@ -354,16 +371,37 @@ class ObjectIconWidget @JvmOverloads constructor(
//todo next PR
val (resId, tint) = when (icon) {
is ObjectIcon.TypeIcon.Default -> {
val resId = context.resources.getIdentifier(icon.drawableResId, DRAWABLE_DIR, context.packageName)
val resId = context.resources.getIdentifier(
icon.drawableResId,
DRAWABLE_DIR,
context.packageName
)
if (resId != 0) {
resId to context.getColor(icon.color.colorRes())
} else {
0 to 0
}
}
ObjectIcon.TypeIcon.Deleted -> 0 to 0
is ObjectIcon.TypeIcon.Emoji -> 0 to 0
is ObjectIcon.TypeIcon.Fallback -> 0 to 0
is ObjectIcon.TypeIcon.Fallback -> {
val resId = context.resources.getIdentifier(
icon.drawableResId,
DRAWABLE_DIR,
context.packageName
)
if (resId != 0) {
resId to context.getColor(CustomIconColor.Transparent.colorRes())
} else {
val defaultFallback = ObjectIcon.TypeIcon.Fallback.DEFAULT
context.resources.getIdentifier(
defaultFallback.drawableResId,
DRAWABLE_DIR,
context.packageName
) to context.getColor(CustomIconColor.Transparent.colorRes())
}
}
}
with(binding) {
@ -373,17 +411,12 @@ class ObjectIconWidget @JvmOverloads constructor(
ivBookmark.setImageDrawable(null)
ivBookmark.gone()
emojiContainer.visible()
ivEmoji.gone()
tvEmojiFallback.visible()
}
try {
if (resId != 0) {
binding.tvEmojiFallback.gone()
binding.ivEmoji.setImageResource(resId)
binding.ivEmoji.imageTintList = ColorStateList.valueOf(tint)
} else {
binding.ivEmoji.setImageDrawable(null)
binding.tvEmojiFallback.gone()
binding.tvEmojiFallback.visible()
}
binding.tvEmojiFallback.setImageResource(resId)
binding.tvEmojiFallback.imageTintList = ColorStateList.valueOf(tint)
} catch (e: Throwable) {
Timber.w(e, "Error while setting object type icon for")
}

View file

@ -106,6 +106,7 @@ fun ProfileImageView(
AsyncImagePainter.State.Empty,
is AsyncImagePainter.State.Loading -> {
LoadingIndicator(
containerModifier = modifier,
containerSize = iconSize
)
}

View file

@ -1,6 +1,5 @@
package com.anytypeio.anytype.core_ui.widgets.objectIcon
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
@ -24,31 +23,32 @@ fun BookmarkIconView(
) {
val painter = rememberAsyncImagePainter(model = icon.image)
val painterState by painter.state.collectAsState()
val state by painter.state.collectAsState()
Crossfade(targetState = painterState) { state ->
when (state) {
AsyncImagePainter.State.Empty,
is AsyncImagePainter.State.Loading -> {
LoadingIndicator(containerSize = backgroundSize)
}
is AsyncImagePainter.State.Error -> {
TypeIconView(
modifier = modifier,
icon = icon.fallback,
backgroundSize = backgroundSize
)
}
is AsyncImagePainter.State.Success -> {
Image(
painter = painter,
contentDescription = "Icon from URI",
modifier = modifier
.size(backgroundSize)
.clip(CircleShape),
contentScale = ContentScale.Crop,
)
}
when (state) {
AsyncImagePainter.State.Empty,
is AsyncImagePainter.State.Loading -> {
LoadingIndicator(
containerModifier = modifier,
containerSize = backgroundSize
)
}
is AsyncImagePainter.State.Error -> {
TypeIconView(
modifier = modifier,
icon = icon.fallback,
backgroundSize = backgroundSize
)
}
is AsyncImagePainter.State.Success -> {
Image(
painter = painter,
contentDescription = "Icon from URI",
modifier = modifier
.size(backgroundSize)
.clip(CircleShape),
contentScale = ContentScale.Crop,
)
}
}
}

View file

@ -31,6 +31,7 @@ fun ImageIconView(
AsyncImagePainter.State.Empty,
is AsyncImagePainter.State.Loading -> {
LoadingIndicator(
containerModifier = modifier,
containerSize = backgroundSize
)
}

View file

@ -12,7 +12,7 @@
android:layout_height="match_parent"
android:layout_gravity="center" />
<TextView
<ImageView
android:id="@+id/tvEmojiFallback"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -59,10 +59,4 @@
android:layout_gravity="center"
android:contentDescription="@string/bookmark_icon"
android:visibility="gone" />
<androidx.compose.ui.platform.ComposeView
android:id="@+id/composeView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</merge>

View file

@ -4,6 +4,7 @@ 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.ObjectIcon.TypeIcon.Default.Companion.DEFAULT_ICON_PREFIX
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIconColor
sealed class ObjectIcon {
@ -46,6 +47,16 @@ sealed class ObjectIcon {
sealed class TypeIcon : ObjectIcon() {
/**
* 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.
*/
internal fun String.toSnakeCase(): String = replace("-", "_")
data object Deleted : TypeIcon() {
const val DEFAULT_DELETED_ICON = "extension-puzzle"
}
@ -70,16 +81,6 @@ sealed class ObjectIcon {
val drawableResId: String
get() = DEFAULT_ICON_PREFIX + rawValue.toSnakeCase()
/**
* 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("-", "_")
companion object {
const val DEFAULT_ICON_PREFIX = "ci_"
const val DEFAULT_CUSTOM_ICON = "extension-puzzle"
@ -91,6 +92,10 @@ sealed class ObjectIcon {
//we use this icon when we can't find the emoji for object or image icon can't be loaded
data class Fallback(val rawValue: String) : TypeIcon() {
val drawableResId: String
get() = DEFAULT_ICON_PREFIX + rawValue.toSnakeCase()
companion object {
const val DEFAULT_FALLBACK_ICON = "extension-puzzle"