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:
parent
7323f50c9f
commit
6480c22c92
5 changed files with 190 additions and 114 deletions
|
@ -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
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue