mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-10 10:00:44 +09:00
DROID-966 Widgets | Enhancement | Navigate from widget to an object (#2921)
This commit is contained in:
parent
de68de90aa
commit
781dcea806
6 changed files with 391 additions and 274 deletions
|
@ -1,50 +1,31 @@
|
|||
package com.anytypeio.anytype.ui.home
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
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
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
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.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
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.Immutable
|
||||
import androidx.compose.runtime.MutableState
|
||||
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.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.presentation.widgets.TreePath
|
||||
import com.anytypeio.anytype.presentation.widgets.WidgetView
|
||||
import com.anytypeio.anytype.ui.widgets.menu.DropDownMenuAction
|
||||
import com.anytypeio.anytype.ui.widgets.menu.WidgetActionButton
|
||||
import com.anytypeio.anytype.ui.widgets.types.LinkWidgetCard
|
||||
import com.anytypeio.anytype.ui.widgets.types.TreeWidgetCard
|
||||
|
||||
@Composable
|
||||
fun HomeScreen(
|
||||
widgets: List<WidgetView>,
|
||||
onExpand: (TreePath) -> Unit,
|
||||
onWidgetObjectClicked: (ObjectWrapper.Basic) -> Unit,
|
||||
onCreateWidget: () -> Unit,
|
||||
onEditWidgets: () -> Unit,
|
||||
onRefresh: () -> Unit,
|
||||
|
@ -62,10 +43,11 @@ fun HomeScreen(
|
|||
is WidgetView.Tree -> {
|
||||
TreeWidgetCard(
|
||||
item = item,
|
||||
onExpand = onExpand,
|
||||
onExpandElement = onExpand,
|
||||
onDropDownMenuAction = { action ->
|
||||
onWidgetMenuAction(item.id, action)
|
||||
}
|
||||
},
|
||||
onWidgetObjectClicked = onWidgetObjectClicked
|
||||
)
|
||||
}
|
||||
is WidgetView.Link -> {
|
||||
|
@ -73,7 +55,8 @@ fun HomeScreen(
|
|||
item = item,
|
||||
onDropDownMenuAction = { action ->
|
||||
onWidgetMenuAction(item.id, action)
|
||||
}
|
||||
},
|
||||
onWidgetObjectClicked = onWidgetObjectClicked
|
||||
)
|
||||
}
|
||||
is WidgetView.Action.CreateWidget -> {
|
||||
|
@ -107,244 +90,4 @@ fun HomeScreen(
|
|||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun LinkWidgetCard(
|
||||
item: WidgetView.Link,
|
||||
onDropDownMenuAction: (DropDownMenuAction) -> Unit
|
||||
) {
|
||||
val isDropDownMenuExpanded = remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
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()
|
||||
.combinedClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
isDropDownMenuExpanded.value = !isDropDownMenuExpanded.value
|
||||
}
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = item.obj.name.orEmpty().trim(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterStart)
|
||||
.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
WidgetMenu(
|
||||
isExpanded = isDropDownMenuExpanded,
|
||||
onDropDownMenuAction = onDropDownMenuAction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
private fun TreeWidgetCard(
|
||||
item: WidgetView.Tree,
|
||||
onExpand: (TreePath) -> Unit,
|
||||
onDropDownMenuAction: (DropDownMenuAction) -> 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)
|
||||
TreeWidgetTreeItem(item, onExpand)
|
||||
}
|
||||
WidgetMenu(
|
||||
isExpanded = isDropDownMenuExpanded,
|
||||
onDropDownMenuAction = onDropDownMenuAction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TreeWidgetTreeItem(
|
||||
item: WidgetView.Tree,
|
||||
onExpand: (TreePath) -> Unit
|
||||
) {
|
||||
item.elements.forEachIndexed { idx, element ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 8.dp)
|
||||
.clickable {
|
||||
onExpand(element.path)
|
||||
}
|
||||
) {
|
||||
if (element.indent > 0) {
|
||||
Spacer(
|
||||
Modifier.width(TreeWidgetTreeItemDefaults.Indent.times(element.indent))
|
||||
)
|
||||
}
|
||||
when (val icon = element.icon) {
|
||||
is WidgetView.Tree.Icon.Branch -> {
|
||||
Image(
|
||||
painterResource(R.drawable.ic_widget_tree_expand),
|
||||
contentDescription = "Expand icon",
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
.rotate(
|
||||
if (icon.isExpanded)
|
||||
ArrowIconDefaults.Expanded
|
||||
else
|
||||
ArrowIconDefaults.Collapsed
|
||||
)
|
||||
|
||||
)
|
||||
}
|
||||
is WidgetView.Tree.Icon.Leaf -> {
|
||||
Image(
|
||||
painterResource(R.drawable.ic_widget_tree_dot),
|
||||
contentDescription = "Dot icon",
|
||||
modifier = Modifier.align(Alignment.CenterVertically)
|
||||
)
|
||||
}
|
||||
is WidgetView.Tree.Icon.Set -> {
|
||||
Image(
|
||||
painterResource(R.drawable.ic_widget_tree_set),
|
||||
contentDescription = "Set icon",
|
||||
modifier = Modifier.align(Alignment.CenterVertically)
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = element.obj.name?.trim() ?: "Untitled",
|
||||
modifier = Modifier.padding(start = 8.dp),
|
||||
maxLines = 1
|
||||
)
|
||||
}
|
||||
if (idx != item.elements.lastIndex) {
|
||||
Divider(
|
||||
thickness = 0.5.dp,
|
||||
modifier = Modifier.padding(horizontal = 8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WidgetMenu(
|
||||
isExpanded: MutableState<Boolean>,
|
||||
onDropDownMenuAction: (DropDownMenuAction) -> Unit
|
||||
) {
|
||||
DropdownMenu(
|
||||
expanded = isExpanded.value,
|
||||
onDismissRequest = { isExpanded.value = false }
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
onDropDownMenuAction(DropDownMenuAction.ChangeWidgetSource).also {
|
||||
isExpanded.value = false
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.widget_change_source))
|
||||
}
|
||||
Divider(thickness = 0.5.dp)
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
onDropDownMenuAction(DropDownMenuAction.ChangeWidgetType).also {
|
||||
isExpanded.value = false
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.widget_change_type))
|
||||
}
|
||||
Divider(thickness = 0.5.dp)
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
onDropDownMenuAction(DropDownMenuAction.RemoveWidget).also {
|
||||
isExpanded.value = false
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(stringResource(id = R.string.remove_widget))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TreeWidgetHeader(item: WidgetView.Tree) {
|
||||
Box(Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
// TODO trimming should be a part of presentation module.
|
||||
text = item.obj.name.orEmpty().trim(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
modifier = Modifier.padding(vertical = 8.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Image(
|
||||
painterResource(R.drawable.ic_widget_tree_expand),
|
||||
contentDescription = "Expand icon",
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.rotate(90f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun WidgetActionButton(
|
||||
modifier: Modifier,
|
||||
label: String,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Button(
|
||||
onClick = onClick,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = colorResource(id = R.color.text_primary),
|
||||
contentColor = colorResource(id = R.color.widget_button)
|
||||
),
|
||||
modifier = modifier,
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
) {
|
||||
Text(text = label)
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private object ArrowIconDefaults {
|
||||
const val Collapsed = 0f
|
||||
const val Expanded = 90f
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private object TreeWidgetTreeItemDefaults {
|
||||
val Indent = 20.dp
|
||||
}
|
||||
|
||||
sealed class DropDownMenuAction {
|
||||
object ChangeWidgetType : DropDownMenuAction()
|
||||
object ChangeWidgetSource : DropDownMenuAction()
|
||||
object RemoveWidget : DropDownMenuAction()
|
||||
object EditWidgets : DropDownMenuAction()
|
||||
}
|
|
@ -21,9 +21,12 @@ import com.anytypeio.anytype.core_utils.ui.BaseComposeFragment
|
|||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.presentation.home.Command
|
||||
import com.anytypeio.anytype.presentation.home.HomeScreenViewModel
|
||||
import com.anytypeio.anytype.presentation.home.HomeScreenViewModel.Navigation
|
||||
import com.anytypeio.anytype.ui.base.navigation
|
||||
import com.anytypeio.anytype.ui.settings.typography
|
||||
import com.anytypeio.anytype.ui.widgets.SelectWidgetSourceFragment
|
||||
import com.anytypeio.anytype.ui.widgets.SelectWidgetTypeFragment
|
||||
import com.anytypeio.anytype.ui.widgets.menu.DropDownMenuAction
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
@ -51,7 +54,7 @@ class HomeScreenFragment : BaseComposeFragment() {
|
|||
onEditWidgets = { context.toast("Coming soon") },
|
||||
onRefresh = vm::onRefresh,
|
||||
onWidgetMenuAction = { widget: Id, action: DropDownMenuAction ->
|
||||
when(action) {
|
||||
when (action) {
|
||||
DropDownMenuAction.ChangeWidgetSource -> {
|
||||
vm.onChangeWidgetSourceClicked(widget)
|
||||
}
|
||||
|
@ -65,7 +68,8 @@ class HomeScreenFragment : BaseComposeFragment() {
|
|||
vm.onDeleteWidgetClicked(widget)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onWidgetObjectClicked = vm::onWidgetObjectClicked
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -75,13 +79,14 @@ class HomeScreenFragment : BaseComposeFragment() {
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
vm.commands.collect { command -> proceed(command) }
|
||||
launch { vm.commands.collect { command -> proceed(command) } }
|
||||
launch { vm.navigation.collect { command -> proceed(command) } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceed(command: Command) {
|
||||
when(command) {
|
||||
when (command) {
|
||||
is Command.ChangeWidgetSource -> {
|
||||
findNavController().navigate(
|
||||
R.id.selectWidgetSourceScreen,
|
||||
|
@ -110,6 +115,13 @@ class HomeScreenFragment : BaseComposeFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun proceed(destination: Navigation) {
|
||||
when (destination) {
|
||||
is Navigation.OpenObject -> navigation().launchDocument(destination.ctx)
|
||||
is Navigation.OpenSet -> navigation().launchObjectSet(destination.ctx)
|
||||
}
|
||||
}
|
||||
|
||||
override fun injectDependencies() {
|
||||
componentManager().homeScreenComponent.get().inject(this)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
package com.anytypeio.anytype.ui.widgets.menu
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.DropdownMenu
|
||||
import androidx.compose.material.DropdownMenuItem
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.R
|
||||
|
||||
@Composable
|
||||
fun WidgetMenu(
|
||||
isExpanded: MutableState<Boolean>,
|
||||
onDropDownMenuAction: (DropDownMenuAction) -> Unit
|
||||
) {
|
||||
DropdownMenu(
|
||||
expanded = isExpanded.value,
|
||||
onDismissRequest = { isExpanded.value = false }
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
onDropDownMenuAction(DropDownMenuAction.ChangeWidgetSource).also {
|
||||
isExpanded.value = false
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.widget_change_source))
|
||||
}
|
||||
Divider(thickness = 0.5.dp)
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
onDropDownMenuAction(DropDownMenuAction.ChangeWidgetType).also {
|
||||
isExpanded.value = false
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.widget_change_type))
|
||||
}
|
||||
Divider(thickness = 0.5.dp)
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
onDropDownMenuAction(DropDownMenuAction.RemoveWidget).also {
|
||||
isExpanded.value = false
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(stringResource(id = R.string.remove_widget))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun WidgetActionButton(
|
||||
modifier: Modifier,
|
||||
label: String,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Button(
|
||||
onClick = onClick,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = colorResource(id = R.color.text_primary),
|
||||
contentColor = colorResource(id = R.color.widget_button)
|
||||
),
|
||||
modifier = modifier,
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
) {
|
||||
Text(text = label)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DropDownMenuAction {
|
||||
object ChangeWidgetType : DropDownMenuAction()
|
||||
object ChangeWidgetSource : DropDownMenuAction()
|
||||
object RemoveWidget : DropDownMenuAction()
|
||||
object EditWidgets : DropDownMenuAction()
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.anytypeio.anytype.ui.widgets.types
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
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.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Card
|
||||
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.unit.dp
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.presentation.widgets.WidgetView
|
||||
import com.anytypeio.anytype.ui.widgets.menu.DropDownMenuAction
|
||||
import com.anytypeio.anytype.ui.widgets.menu.WidgetMenu
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun LinkWidgetCard(
|
||||
item: WidgetView.Link,
|
||||
onWidgetObjectClicked: (ObjectWrapper.Basic) -> Unit,
|
||||
onDropDownMenuAction: (DropDownMenuAction) -> Unit
|
||||
) {
|
||||
val isDropDownMenuExpanded = remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
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()
|
||||
.combinedClickable(
|
||||
onClick = { onWidgetObjectClicked(item.obj) },
|
||||
onLongClick = {
|
||||
isDropDownMenuExpanded.value = !isDropDownMenuExpanded.value
|
||||
}
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = item.obj.name.orEmpty().trim(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterStart)
|
||||
.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
WidgetMenu(
|
||||
isExpanded = isDropDownMenuExpanded,
|
||||
onDropDownMenuAction = onDropDownMenuAction
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
package com.anytypeio.anytype.ui.widgets.types
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
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
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.MutableState
|
||||
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.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.presentation.widgets.TreePath
|
||||
import com.anytypeio.anytype.presentation.widgets.WidgetView
|
||||
import com.anytypeio.anytype.ui.widgets.menu.DropDownMenuAction
|
||||
import com.anytypeio.anytype.ui.widgets.menu.WidgetMenu
|
||||
|
||||
@Composable
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun TreeWidgetCard(
|
||||
item: WidgetView.Tree,
|
||||
onExpandElement: (TreePath) -> Unit,
|
||||
onWidgetObjectClicked: (ObjectWrapper.Basic) -> Unit,
|
||||
onDropDownMenuAction: (DropDownMenuAction) -> 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,
|
||||
isDropDownMenuExpanded = isDropDownMenuExpanded,
|
||||
onWidgetObjectClicked = onWidgetObjectClicked
|
||||
)
|
||||
TreeWidgetTreeItem(
|
||||
item = item,
|
||||
onExpand = onExpandElement,
|
||||
onWidgetElementClicked = onWidgetObjectClicked
|
||||
)
|
||||
}
|
||||
WidgetMenu(
|
||||
isExpanded = isDropDownMenuExpanded,
|
||||
onDropDownMenuAction = onDropDownMenuAction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TreeWidgetTreeItem(
|
||||
item: WidgetView.Tree,
|
||||
onExpand: (TreePath) -> Unit,
|
||||
onWidgetElementClicked: (ObjectWrapper.Basic) -> Unit
|
||||
) {
|
||||
item.elements.forEachIndexed { idx, element ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 8.dp)
|
||||
.clickable { onWidgetElementClicked(element.obj) }
|
||||
) {
|
||||
if (element.indent > 0) {
|
||||
Spacer(
|
||||
Modifier.width(TreeWidgetTreeItemDefaults.Indent.times(element.indent))
|
||||
)
|
||||
}
|
||||
when (val icon = element.icon) {
|
||||
is WidgetView.Tree.Icon.Branch -> {
|
||||
Image(
|
||||
painterResource(R.drawable.ic_widget_tree_expand),
|
||||
contentDescription = "Expand icon",
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
.rotate(
|
||||
if (icon.isExpanded)
|
||||
ArrowIconDefaults.Expanded
|
||||
else
|
||||
ArrowIconDefaults.Collapsed
|
||||
).clickable { onExpand(element.path) }
|
||||
|
||||
)
|
||||
}
|
||||
is WidgetView.Tree.Icon.Leaf -> {
|
||||
Image(
|
||||
painterResource(R.drawable.ic_widget_tree_dot),
|
||||
contentDescription = "Dot icon",
|
||||
modifier = Modifier.align(Alignment.CenterVertically)
|
||||
)
|
||||
}
|
||||
is WidgetView.Tree.Icon.Set -> {
|
||||
Image(
|
||||
painterResource(R.drawable.ic_widget_tree_set),
|
||||
contentDescription = "Set icon",
|
||||
modifier = Modifier.align(Alignment.CenterVertically)
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = element.obj.name?.trim() ?: "Untitled",
|
||||
modifier = Modifier.padding(start = 8.dp),
|
||||
maxLines = 1
|
||||
)
|
||||
}
|
||||
if (idx != item.elements.lastIndex) {
|
||||
Divider(
|
||||
thickness = 0.5.dp,
|
||||
modifier = Modifier.padding(horizontal = 8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun TreeWidgetHeader(
|
||||
item: WidgetView.Tree,
|
||||
isDropDownMenuExpanded: MutableState<Boolean>,
|
||||
onWidgetObjectClicked: (ObjectWrapper.Basic) -> Unit
|
||||
) {
|
||||
Box(Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
// TODO trimming should be a part of presentation module.
|
||||
text = item.obj.name.orEmpty().trim(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp, bottom = 8.dp, end = 28.dp)
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
onWidgetObjectClicked(item.obj)
|
||||
},
|
||||
onLongClick = {
|
||||
isDropDownMenuExpanded.value = !isDropDownMenuExpanded.value
|
||||
}
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Image(
|
||||
painterResource(R.drawable.ic_widget_tree_expand),
|
||||
contentDescription = "Expand icon",
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.rotate(90f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Immutable
|
||||
private object TreeWidgetTreeItemDefaults {
|
||||
val Indent = 20.dp
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private object ArrowIconDefaults {
|
||||
const val Collapsed = 0f
|
||||
const val Expanded = 90f
|
||||
}
|
|
@ -5,7 +5,9 @@ import androidx.lifecycle.ViewModelProvider
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.anytypeio.anytype.core_models.Event
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.ObjectView
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_models.WidgetLayout
|
||||
import com.anytypeio.anytype.core_models.ext.process
|
||||
|
@ -20,7 +22,7 @@ import com.anytypeio.anytype.domain.search.ObjectSearchSubscriptionContainer
|
|||
import com.anytypeio.anytype.domain.widgets.CreateWidget
|
||||
import com.anytypeio.anytype.domain.widgets.DeleteWidget
|
||||
import com.anytypeio.anytype.domain.widgets.UpdateWidget
|
||||
import com.anytypeio.anytype.presentation.common.BaseViewModel
|
||||
import com.anytypeio.anytype.presentation.navigation.NavigationViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.presentation.widgets.LinkWidgetContainer
|
||||
import com.anytypeio.anytype.presentation.widgets.TreePath
|
||||
|
@ -55,7 +57,7 @@ class HomeScreenViewModel(
|
|||
private val widgetEventDispatcher: Dispatcher<WidgetDispatchEvent>,
|
||||
private val objectPayloadDispatcher: Dispatcher<Payload>,
|
||||
private val interceptEvents: InterceptEvents
|
||||
) : BaseViewModel(), Reducer<ObjectView, Payload> {
|
||||
) : NavigationViewModel<HomeScreenViewModel.Navigation>(), Reducer<ObjectView, Payload> {
|
||||
|
||||
val views = MutableStateFlow<List<WidgetView>>(actions)
|
||||
val commands = MutableSharedFlow<Command>()
|
||||
|
@ -301,6 +303,10 @@ class HomeScreenViewModel(
|
|||
proceedWithDeletingWidget(widget)
|
||||
}
|
||||
|
||||
fun onWidgetObjectClicked(obj: ObjectWrapper.Basic) {
|
||||
proceedWithOpeningObject(obj)
|
||||
}
|
||||
|
||||
fun onChangeWidgetTypeClicked(widget: Id) {
|
||||
Timber.d("onChangeWidgetSourceClicked, widget:[$widget]")
|
||||
val curr = widgets.value.find { it.id == widget }
|
||||
|
@ -378,6 +384,24 @@ class HomeScreenViewModel(
|
|||
return curr
|
||||
}
|
||||
|
||||
private fun proceedWithOpeningObject(obj: ObjectWrapper.Basic) {
|
||||
when (obj.layout) {
|
||||
ObjectType.Layout.BASIC,
|
||||
ObjectType.Layout.PROFILE,
|
||||
ObjectType.Layout.NOTE,
|
||||
ObjectType.Layout.TODO,
|
||||
ObjectType.Layout.FILE,
|
||||
ObjectType.Layout.BOOKMARK -> navigate(Navigation.OpenObject(obj.id))
|
||||
ObjectType.Layout.SET -> navigate(Navigation.OpenSet(obj.id))
|
||||
else -> sendToast("Unexpected layout: ${obj.layout}")
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Navigation {
|
||||
data class OpenObject(val ctx: Id) : Navigation()
|
||||
data class OpenSet(val ctx: Id) : Navigation()
|
||||
}
|
||||
|
||||
class Factory @Inject constructor(
|
||||
private val configStorage: ConfigStorage,
|
||||
private val openObject: OpenObject,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue