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:
parent
03935a7bc3
commit
6ad8e54721
7 changed files with 95 additions and 61 deletions
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -106,6 +106,7 @@ fun ProfileImageView(
|
|||
AsyncImagePainter.State.Empty,
|
||||
is AsyncImagePainter.State.Loading -> {
|
||||
LoadingIndicator(
|
||||
containerModifier = modifier,
|
||||
containerSize = iconSize
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ fun ImageIconView(
|
|||
AsyncImagePainter.State.Empty,
|
||||
is AsyncImagePainter.State.Loading -> {
|
||||
LoadingIndicator(
|
||||
containerModifier = modifier,
|
||||
containerSize = backgroundSize
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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"
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue