mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-10 10:00:44 +09:00
DROID-952 Widgets | Enhancement | Basic dropdown menu for widgets (#2905)
This commit is contained in:
parent
1309af7752
commit
790d22fda2
3 changed files with 187 additions and 105 deletions
|
@ -1,7 +1,8 @@
|
|||
package com.anytypeio.anytype.ui.home
|
||||
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
|
@ -10,7 +11,6 @@ import androidx.compose.foundation.layout.fillMaxHeight
|
|||
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.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
|
@ -18,13 +18,17 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.DropdownMenu
|
||||
import androidx.compose.material.DropdownMenuItem
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
@ -32,8 +36,8 @@ import com.anytypeio.anytype.R
|
|||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.presentation.widgets.TreePath
|
||||
import com.anytypeio.anytype.presentation.widgets.WidgetView
|
||||
import timber.log.Timber
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun HomeScreen(
|
||||
widgets: List<WidgetView>,
|
||||
|
@ -41,7 +45,9 @@ fun HomeScreen(
|
|||
onCreateWidget: () -> Unit,
|
||||
onEditWidgets: () -> Unit,
|
||||
onRefresh: () -> Unit,
|
||||
onDeleteWidget: (Id) -> Unit
|
||||
onDeleteWidget: (Id) -> Unit,
|
||||
onChangeWidgetSource: (Id) -> Unit,
|
||||
onChangeWidgetType: (Id) -> Unit
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
|
@ -49,90 +55,22 @@ fun HomeScreen(
|
|||
.fillMaxWidth()
|
||||
.padding(top = 12.dp)
|
||||
) {
|
||||
Timber.d("Widgets:\n$widgets")
|
||||
items(
|
||||
items = widgets, itemContent = { item ->
|
||||
when (item) {
|
||||
is WidgetView.Tree -> {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
) {
|
||||
Circle {
|
||||
onDeleteWidget(item.id)
|
||||
}
|
||||
Column(Modifier.padding(16.dp)) {
|
||||
TreeWidgetHeader(item)
|
||||
item.elements.forEach { element ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 8.dp)
|
||||
.clickable {
|
||||
onExpand(element.path)
|
||||
}
|
||||
) {
|
||||
if (element.indent > 0) {
|
||||
Spacer(Modifier.width(20.dp.times(element.indent)))
|
||||
}
|
||||
Box(
|
||||
Modifier
|
||||
.width(20.dp)
|
||||
.height(20.dp)
|
||||
) {
|
||||
when (val icon = element.icon) {
|
||||
is WidgetView.Tree.Icon.Branch -> {
|
||||
Text(
|
||||
text = ">",
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.rotate(if (icon.isExpanded) 90f else 0f)
|
||||
)
|
||||
}
|
||||
is WidgetView.Tree.Icon.Leaf -> {
|
||||
Text(
|
||||
text = "•",
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
is WidgetView.Tree.Icon.Set -> {
|
||||
Text(
|
||||
text = "#",
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = element.obj.name?.trim() ?: "Untitled"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TreeWidgetCard(
|
||||
item = item,
|
||||
onExpand = onExpand,
|
||||
onChangeWidgetSource = onChangeWidgetSource,
|
||||
onChangeWidgetType = onChangeWidgetType,
|
||||
onDeleteWidget = onDeleteWidget
|
||||
)
|
||||
}
|
||||
is WidgetView.Link -> {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(52.dp)
|
||||
.padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
) {
|
||||
Box(Modifier.fillMaxHeight()) {
|
||||
Text(
|
||||
text = item.obj.name.orEmpty().trim(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterStart)
|
||||
.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
Circle {
|
||||
onDeleteWidget(item.id)
|
||||
}
|
||||
LinkWidgetCard(
|
||||
item = item
|
||||
)
|
||||
}
|
||||
is WidgetView.Action.CreateWidget -> {
|
||||
Box(Modifier.fillMaxWidth()) {
|
||||
|
@ -167,6 +105,162 @@ fun HomeScreen(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LinkWidgetCard(item: WidgetView.Link) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(52.dp)
|
||||
.padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
) {
|
||||
Box(Modifier.fillMaxHeight()) {
|
||||
Text(
|
||||
text = item.obj.name.orEmpty().trim(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterStart)
|
||||
.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
private fun TreeWidgetCard(
|
||||
item: WidgetView.Tree,
|
||||
onExpand: (TreePath) -> Unit,
|
||||
onChangeWidgetSource: (Id) -> Unit,
|
||||
onChangeWidgetType: (Id) -> Unit,
|
||||
onDeleteWidget: (Id) -> Unit
|
||||
) {
|
||||
val isDropDownMenuExpanded = remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(16.dp)
|
||||
.combinedClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
isDropDownMenuExpanded.value =
|
||||
!isDropDownMenuExpanded.value
|
||||
}
|
||||
)
|
||||
) {
|
||||
TreeWidgetHeader(item)
|
||||
item.elements.forEach { element ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 8.dp)
|
||||
.clickable {
|
||||
onExpand(element.path)
|
||||
}
|
||||
) {
|
||||
if (element.indent > 0) {
|
||||
Spacer(Modifier.width(20.dp.times(element.indent)))
|
||||
}
|
||||
Box(
|
||||
Modifier
|
||||
.width(20.dp)
|
||||
.height(20.dp)
|
||||
) {
|
||||
when (val icon = element.icon) {
|
||||
is WidgetView.Tree.Icon.Branch -> {
|
||||
Text(
|
||||
// TODO replace with drawable
|
||||
text = ">",
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.rotate(if (icon.isExpanded) 90f else 0f)
|
||||
)
|
||||
}
|
||||
is WidgetView.Tree.Icon.Leaf -> {
|
||||
Text(
|
||||
// TODO replace with drawable
|
||||
text = "•",
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
is WidgetView.Tree.Icon.Set -> {
|
||||
Text(
|
||||
// TODO replace with drawable
|
||||
text = "#",
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = element.obj.name?.trim() ?: "Untitled"
|
||||
)
|
||||
}
|
||||
Divider(
|
||||
thickness = 0.5.dp,
|
||||
modifier = Modifier.padding(horizontal = 8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
WidgetMenu(
|
||||
expanded = isDropDownMenuExpanded.value,
|
||||
onDismiss = {
|
||||
isDropDownMenuExpanded.value = false
|
||||
},
|
||||
onChangeSourceClicked = {
|
||||
isDropDownMenuExpanded.value = false
|
||||
onChangeWidgetSource(item.id)
|
||||
},
|
||||
onChangeTypeClicked = {
|
||||
isDropDownMenuExpanded.value = false
|
||||
onChangeWidgetType(item.id)
|
||||
},
|
||||
onRemoveWidgetClicked = {
|
||||
isDropDownMenuExpanded.value = false
|
||||
onDeleteWidget(item.id)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WidgetMenu(
|
||||
expanded: Boolean,
|
||||
onDismiss: () -> Unit,
|
||||
onChangeTypeClicked: () -> Unit,
|
||||
onRemoveWidgetClicked: () -> Unit,
|
||||
onChangeSourceClicked: () -> Unit
|
||||
) {
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = onDismiss
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
onClick = onChangeSourceClicked
|
||||
) {
|
||||
Text(stringResource(R.string.widget_change_source))
|
||||
}
|
||||
Divider(thickness = 0.5.dp)
|
||||
DropdownMenuItem(
|
||||
onClick = onChangeTypeClicked
|
||||
) {
|
||||
Text(stringResource(R.string.widget_change_type))
|
||||
}
|
||||
Divider(thickness = 0.5.dp)
|
||||
DropdownMenuItem(
|
||||
onClick = onRemoveWidgetClicked
|
||||
) {
|
||||
Text(stringResource(id = R.string.remove_widget))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TreeWidgetHeader(item: WidgetView.Tree) {
|
||||
Row() {
|
||||
|
@ -204,24 +298,3 @@ fun WidgetActionButton(
|
|||
Text(text = label)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Circle(
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.height(24.dp)
|
||||
.width(24.dp)) {
|
||||
Canvas(
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.align(Alignment.CenterEnd)
|
||||
.padding(4.dp)
|
||||
.clickable { onClick() },
|
||||
onDraw = {
|
||||
drawCircle(color = Color.Red)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,13 @@ class HomeScreenFragment : BaseComposeFragment() {
|
|||
},
|
||||
onDeleteWidget = vm::onDeleteWidgetClicked,
|
||||
onEditWidgets = { context.toast("Coming soon") },
|
||||
onRefresh = vm::onRefresh
|
||||
onRefresh = vm::onRefresh,
|
||||
onChangeWidgetSource = {
|
||||
toast("TODO")
|
||||
},
|
||||
onChangeWidgetType = {
|
||||
toast("TODO")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -323,5 +323,8 @@ Do the computation of an expensive paragraph of text on a background thread:
|
|||
<string name="widget_type_link_description">Compact version of the object</string>
|
||||
<string name="widget_type_list_description">Widget with list view of set object</string>
|
||||
<string name="widget_type_list">List</string>
|
||||
<string name="widget_change_source">Change source</string>
|
||||
<string name="widget_change_type">Change widget type</string>
|
||||
<string name="remove_widget">Remove widget</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue