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

DROID-2611 Widgets | Fix | Show icon or cover based on view settings for widgets with 'View' layout (#1366)

This commit is contained in:
Evgenii Kozlov 2024-07-08 16:44:11 +02:00 committed by GitHub
parent 7323f50c9f
commit 6480c22c92
Signed by: github
GPG key ID: B5690EEEBB952194
5 changed files with 190 additions and 114 deletions

View file

@ -10,7 +10,7 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@ -21,6 +21,8 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.material.Divider
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@ -30,21 +32,21 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import androidx.core.graphics.toColor
import androidx.compose.ui.unit.em
import coil.compose.rememberAsyncImagePainter
import coil.compose.rememberImagePainter
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
@ -260,9 +262,12 @@ fun GalleryWidgetCard(
)
}
if (item.elements.isNotEmpty()) {
val isCardSmall = item.elements.none { it.cover != null }
val withCover = item.showCover || item.elements.none { it.cover != null }
val withIcon = item.showIcon
LazyRow(
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
item.elements.forEachIndexed { idx, element ->
@ -277,7 +282,8 @@ fun GalleryWidgetCard(
onItemClicked = {
onWidgetObjectClicked(element.obj)
},
isCardSmall = isCardSmall
withCover = withCover,
withIcon = withIcon
)
}
if (idx == item.elements.lastIndex) {
@ -285,7 +291,7 @@ fun GalleryWidgetCard(
Box(
modifier = Modifier
.width(136.dp)
.height(if (isCardSmall) 56.dp else 136.dp)
.height(if (withCover) 56.dp else 136.dp)
.border(
width = 1.dp,
color = colorResource(id = R.color.shape_primary),
@ -446,12 +452,13 @@ fun ListWidgetElement(
private fun GalleryWidgetItemCard(
item: WidgetView.SetOfObjects.Element,
onItemClicked: () -> Unit,
isCardSmall: Boolean = false
withCover: Boolean = false,
withIcon: Boolean = false
) {
Box(
modifier = Modifier
.width(136.dp)
.height(if (isCardSmall) 56.dp else 136.dp)
.height(if (withCover) 56.dp else 136.dp)
.clip(RoundedCornerShape(8.dp))
.clickable {
onItemClicked()
@ -466,69 +473,105 @@ private fun GalleryWidgetItemCard(
shape = RoundedCornerShape(8.dp)
)
)
if (withCover) {
when (val cover = item.cover) {
is CoverView.Color -> {
Box(
modifier = Modifier
.width(136.dp)
.height(80.dp)
.background(
color = Color(cover.coverColor.color),
shape = RoundedCornerShape(topEnd = 8.dp, topStart = 8.dp)
)
)
}
when(val cover = item.cover) {
is CoverView.Color -> {
Box(
modifier = Modifier
.width(136.dp)
.height(80.dp)
.background(
color = Color(cover.coverColor.color),
shape = RoundedCornerShape(topEnd = 8.dp, topStart = 8.dp)
)
)
}
is CoverView.Gradient -> {
Box(
modifier = Modifier
.width(136.dp)
.height(80.dp)
.background(
Brush.horizontalGradient(
colors = gradient(cover.gradient)
),
shape = RoundedCornerShape(topEnd = 8.dp, topStart = 8.dp)
)
)
}
is CoverView.Image -> {
Image(
painter = rememberAsyncImagePainter(cover.url),
contentDescription = "Cover image",
modifier = Modifier
.width(136.dp)
.height(80.dp)
.clip(RoundedCornerShape(topStart = 8.dp, topEnd = 8.dp))
,
contentScale = ContentScale.Crop,
)
}
else -> {
// Draw nothing.
is CoverView.Gradient -> {
Box(
modifier = Modifier
.width(136.dp)
.height(80.dp)
.background(
Brush.horizontalGradient(
colors = gradient(cover.gradient)
),
shape = RoundedCornerShape(topEnd = 8.dp, topStart = 8.dp)
)
)
}
is CoverView.Image -> {
Image(
painter = rememberAsyncImagePainter(cover.url),
contentDescription = "Cover image",
modifier = Modifier
.width(136.dp)
.height(80.dp)
.clip(RoundedCornerShape(topStart = 8.dp, topEnd = 8.dp)),
contentScale = ContentScale.Crop,
)
}
else -> {
// Draw nothing.
}
}
}
Text(
text = item.obj.getProperName().ifEmpty { stringResource(id = R.string.untitled) },
maxLines = 2,
overflow = TextOverflow.Ellipsis,
style = Caption1Medium,
color = colorResource(id = R.color.text_primary),
modifier = Modifier
.padding(
start = 12.dp,
end = 10.dp,
top = 9.dp,
bottom = 11.dp
)
.align(
if (withIcon && item.objectIcon != ObjectIcon.None) {
Row(
modifier = Modifier.align(
if (item.cover != null) {
Alignment.BottomStart
} else {
Alignment.TopStart
}
)
)
) {
TreeWidgetObjectIcon(
icon = item.objectIcon,
paddingStart = 0.dp,
paddingEnd = 0.dp,
onTaskIconClicked = {},
modifier = Modifier
.padding(
start = 12.dp,
top = 9.dp
),
size = 16.dp
)
Text(
text = item.obj.getProperName()
.ifEmpty { stringResource(id = R.string.untitled) },
maxLines = 2,
overflow = TextOverflow.Ellipsis,
style = Caption1Medium,
color = colorResource(id = R.color.text_primary),
modifier = Modifier
.padding(
start = 6.dp,
end = 10.dp,
top = 9.dp,
bottom = 11.dp
)
)
}
} else {
Text(
text = item.obj.getProperName().ifEmpty { stringResource(id = R.string.untitled) },
maxLines = 2,
overflow = TextOverflow.Ellipsis,
style = Caption1Medium,
color = colorResource(id = R.color.text_primary),
modifier = Modifier
.padding(
start = 12.dp,
end = 10.dp,
top = 9.dp,
bottom = 11.dp
)
)
}
}
}

View file

@ -5,6 +5,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Text
@ -32,15 +33,15 @@ fun TreeWidgetObjectIcon(
icon: ObjectIcon,
paddingStart: Dp,
paddingEnd: Dp,
onTaskIconClicked: (Boolean) -> Unit
onTaskIconClicked: (Boolean) -> Unit,
size: Dp = 18.dp
) {
when (icon) {
is ObjectIcon.Profile.Avatar -> {
Box(
modifier = modifier
.padding(start = paddingStart, end = paddingEnd)
.height(18.dp)
.width(18.dp)
.size(size)
.background(
shape = CircleShape,
color = colorResource(id = R.color.text_tertiary)
@ -65,25 +66,29 @@ fun TreeWidgetObjectIcon(
is ObjectIcon.Profile.Image -> {
UriCircleImage(
uri = icon.hash,
modifier = modifier.padding(start = paddingStart, end = paddingEnd)
modifier = modifier.padding(start = paddingStart, end = paddingEnd),
size = size
)
}
is ObjectIcon.Basic.Emoji -> {
UriImage(
uri = Emojifier.safeUri(icon.unicode),
modifier = modifier.padding(start = paddingStart, end = paddingEnd)
modifier = modifier.padding(start = paddingStart, end = paddingEnd),
size = size
)
}
is ObjectIcon.Basic.Image -> {
UriImage(
uri = icon.hash,
modifier = Modifier.padding(start = paddingStart, end = paddingEnd)
modifier = Modifier.padding(start = paddingStart, end = paddingEnd),
size = size
)
}
is ObjectIcon.Bookmark -> {
UriImage(
uri = icon.image,
modifier = Modifier.padding(start = paddingStart, end = paddingEnd)
modifier = Modifier.padding(start = paddingStart, end = paddingEnd),
size = size
)
}
is ObjectIcon.Task -> {
@ -94,6 +99,7 @@ fun TreeWidgetObjectIcon(
painterResource(id = R.drawable.ic_dashboard_task_checkbox_not_checked),
contentDescription = "Task icon",
modifier = modifier
.size(size)
.padding(start = paddingStart, end = paddingEnd)
.noRippleClickable { onTaskIconClicked(icon.isChecked) }
)
@ -107,28 +113,25 @@ fun TreeWidgetObjectIcon(
@Composable
fun UriImage(
uri: String,
modifier: Modifier
modifier: Modifier,
size: Dp = 18.dp
) {
Image(
painter = rememberAsyncImagePainter(uri),
contentDescription = "Icon from URI",
modifier = modifier
.height(18.dp)
.width(18.dp)
modifier = modifier.size(size)
)
}
@Composable
fun UriCircleImage(
uri: String,
modifier: Modifier
modifier: Modifier,
size: Dp = 18.dp
) {
Image(
painter = rememberAsyncImagePainter(uri),
contentDescription = "Icon from URI",
modifier = modifier
.height(18.dp)
.width(18.dp)
.clip(CircleShape)
modifier = modifier.size(size).clip(CircleShape)
)
}

View file

@ -33,6 +33,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.colorResource
@ -295,26 +296,12 @@ fun WidgetHeader(
)
)
val rotation = getAnimatableRotation(isExpanded)
Box(
modifier = Modifier
.align(Alignment.CenterEnd)
.then(
if (isInEditMode)
Modifier
else
Modifier.noRippleClickable { onExpandElement() }
)
) {
Image(
painterResource(R.drawable.ic_widget_tree_expand),
contentDescription = "Expand icon",
modifier = Modifier
.rotate(rotation.value)
.padding(horizontal = 12.dp)
)
}
WidgetArrow(
modifier = Modifier.align(Alignment.CenterEnd),
isInEditMode = isInEditMode,
onExpandElement = onExpandElement,
isExpanded = isExpanded
)
AnimatedVisibility(
visible = isInEditMode,
@ -346,7 +333,34 @@ fun WidgetHeader(
}
@Composable
fun getAnimatableRotation(isExpanded: Boolean): Animatable<Float, AnimationVector1D> {
private fun WidgetArrow(
modifier: Modifier,
isInEditMode: Boolean,
onExpandElement: () -> Unit,
isExpanded: Boolean
) {
val rotation = getAnimatedRotation(isExpanded)
Box(
modifier = modifier
.then(
if (isInEditMode)
Modifier
else
Modifier.noRippleClickable { onExpandElement() }
)
) {
Image(
painterResource(R.drawable.ic_widget_tree_expand),
contentDescription = "Expand icon",
modifier = Modifier
.graphicsLayer { rotationZ = rotation.value }
.padding(horizontal = 12.dp)
)
}
}
@Composable
fun getAnimatedRotation(isExpanded: Boolean): Animatable<Float, AnimationVector1D> {
val currentRotation = remember {
mutableStateOf(
if (isExpanded) ArrowIconDefaults.Expanded else ArrowIconDefaults.Collapsed

View file

@ -5,6 +5,7 @@ import com.anytypeio.anytype.core_models.Config
import com.anytypeio.anytype.core_models.DV
import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVFilterCondition
import com.anytypeio.anytype.core_models.DVViewerType
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectTypeIds
@ -18,6 +19,7 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.`object`.GetObject
import com.anytypeio.anytype.presentation.BuildConfig
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.presentation.relations.cover
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants
import java.lang.UnsupportedOperationException
@ -160,7 +162,9 @@ class DataViewListWidgetContainer(
} else {
null
}
if (target?.type == Block.Content.DataView.Viewer.Type.GALLERY) {
if (target != null && target.type == DVViewerType.GALLERY) {
val withCover = !target.coverRelationKey.isNullOrEmpty()
val withIcon = !target.hideIcon
WidgetView.Gallery(
id = widget.id,
source = widget.source,
@ -168,16 +172,26 @@ class DataViewListWidgetContainer(
elements = objects.map { obj ->
WidgetView.SetOfObjects.Element(
obj = obj,
objectIcon = obj.widgetElementIcon(
builder = urlBuilder
),
cover = obj.cover(
urlBuilder = urlBuilder,
coverImageHashProvider = coverImageHashProvider
)
objectIcon = if (withIcon) {
obj.widgetElementIcon(
builder = urlBuilder
)
} else {
ObjectIcon.None
},
cover = if (withCover) {
obj.cover(
urlBuilder = urlBuilder,
coverImageHashProvider = coverImageHashProvider
)
} else {
null
}
)
},
isExpanded = true
isExpanded = true,
showIcon = withIcon,
showCover = withCover
)
} else {
WidgetView.SetOfObjects(

View file

@ -79,7 +79,9 @@ sealed class WidgetView {
val source: Widget.Source,
val tabs: List<SetOfObjects.Tab>,
val elements: List<SetOfObjects.Element>,
val isExpanded: Boolean
val isExpanded: Boolean,
val showIcon: Boolean = false,
val showCover: Boolean = false
) : WidgetView(), Draggable
data class ListOfObjects(