mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-3142 Set | Fix | A view list is not editable after clicking on the edit (#1922)
This commit is contained in:
parent
07878fc27c
commit
998cd1cf2d
8 changed files with 541 additions and 712 deletions
|
@ -411,7 +411,6 @@ open class ObjectSetFragment :
|
|||
ViewersWidget(
|
||||
state = vm.viewersWidgetState.collectAsStateWithLifecycle().value,
|
||||
action = vm::onViewersWidgetAction,
|
||||
scope = lifecycleScope
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -422,7 +421,6 @@ open class ObjectSetFragment :
|
|||
ViewerEditWidget(
|
||||
state = vm.viewerEditWidgetState.collectAsStateWithLifecycle().value,
|
||||
action = vm::onViewerEditWidgetAction,
|
||||
scope = lifecycleScope
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -433,7 +431,6 @@ open class ObjectSetFragment :
|
|||
ViewerLayoutWidget(
|
||||
uiState = vm.viewerLayoutWidgetState.collectAsStateWithLifecycle().value,
|
||||
action = vm::onViewerLayoutWidgetAction,
|
||||
scope = lifecycleScope
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,16 @@
|
|||
package com.anytypeio.anytype.core_ui.widgets.dv
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.ime
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
|
@ -25,12 +18,11 @@ import androidx.compose.foundation.text.BasicTextField
|
|||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.FractionalThreshold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.rememberSwipeableState
|
||||
import androidx.compose.material.swipeable
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -45,13 +37,10 @@ import androidx.compose.ui.focus.FocusRequester
|
|||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.layout.boundsInRoot
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.platform.SoftwareKeyboardController
|
||||
|
@ -62,103 +51,57 @@ import androidx.compose.ui.text.input.ImeAction
|
|||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.constraintlayout.compose.Dimension
|
||||
import com.anytypeio.anytype.core_models.DVViewerType
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.foundation.Divider
|
||||
import com.anytypeio.anytype.core_ui.foundation.Dragger
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
||||
import com.anytypeio.anytype.core_ui.views.Caption1Medium
|
||||
import com.anytypeio.anytype.core_ui.views.Title1
|
||||
import com.anytypeio.anytype.core_ui.views.UXBody
|
||||
import com.anytypeio.anytype.core_ui.widgets.DragStates
|
||||
import com.anytypeio.anytype.presentation.sets.ViewEditAction
|
||||
import com.anytypeio.anytype.presentation.sets.ViewerEditWidgetUi
|
||||
import com.anytypeio.anytype.presentation.sets.isVisible
|
||||
import kotlin.math.roundToInt
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class, ExperimentalComposeUiApi::class)
|
||||
@OptIn(ExperimentalMaterialApi::class, ExperimentalComposeUiApi::class,
|
||||
ExperimentalMaterial3Api::class
|
||||
)
|
||||
@Composable
|
||||
fun ViewerEditWidget(
|
||||
state: ViewerEditWidgetUi,
|
||||
action: (ViewEditAction) -> Unit,
|
||||
scope: CoroutineScope
|
||||
) {
|
||||
|
||||
val bottomSheetState = rememberModalBottomSheetState(
|
||||
skipPartiallyExpanded = true
|
||||
)
|
||||
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val focusManager = LocalFocusManager.current
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.BottomStart,
|
||||
) {
|
||||
|
||||
val currentState by rememberUpdatedState(state)
|
||||
val swipeableState = rememberSwipeableState(DragStates.VISIBLE)
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = currentState.isVisible(),
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(tween(100))
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.Black.copy(alpha = 0.4f))
|
||||
.noRippleClickable { action(ViewEditAction.Dismiss) }
|
||||
)
|
||||
}
|
||||
|
||||
if (swipeableState.isAnimationRunning && swipeableState.targetValue == DragStates.DISMISSED) {
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
keyboardController?.hide()
|
||||
focusManager.clearFocus()
|
||||
action(ViewEditAction.Dismiss)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentState.isVisible()) {
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
scope.launch { swipeableState.snapTo(DragStates.VISIBLE) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val sizePx =
|
||||
with(LocalDensity.current) { LocalConfiguration.current.screenHeightDp.dp.toPx() }
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = currentState.isVisible(),
|
||||
enter = slideInVertically { it },
|
||||
exit = slideOutVertically { it },
|
||||
if (state is ViewerEditWidgetUi.Data) {
|
||||
ModalBottomSheet(
|
||||
modifier = Modifier
|
||||
.swipeable(state = swipeableState,
|
||||
orientation = Orientation.Vertical,
|
||||
anchors = mapOf(
|
||||
0f to DragStates.VISIBLE, sizePx to DragStates.DISMISSED
|
||||
),
|
||||
thresholds = { _, _ -> FractionalThreshold(0.3f) })
|
||||
.offset { IntOffset(0, swipeableState.offset.value.roundToInt()) }
|
||||
) {
|
||||
if (state is ViewerEditWidgetUi.Data) {
|
||||
.windowInsetsPadding(WindowInsets.ime)
|
||||
.padding(start = 8.dp, end = 8.dp, bottom = 30.dp)
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
scrimColor = colorResource(id = R.color.modal_screen_outside_background),
|
||||
containerColor = colorResource(id = R.color.background_secondary),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
onDismissRequest = { action(ViewEditAction.Dismiss) },
|
||||
sheetState = bottomSheetState,
|
||||
dragHandle = { DragHandle() },
|
||||
content = {
|
||||
ViewerEditWidgetContent(state, focusRequester, keyboardController) {
|
||||
focusManager.clearFocus()
|
||||
keyboardController?.hide()
|
||||
action.invoke(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,11 +122,7 @@ fun ViewerEditWidgetContent(
|
|||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(start = 8.dp, end = 8.dp, bottom = 15.dp)
|
||||
.background(
|
||||
color = colorResource(id = R.color.background_secondary),
|
||||
shape = RoundedCornerShape(size = 16.dp)
|
||||
),
|
||||
//.padding(start = 8.dp, end = 8.dp, bottom = 15.dp)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
@ -191,12 +130,6 @@ fun ViewerEditWidgetContent(
|
|||
.wrapContentHeight()
|
||||
.padding(bottom = 16.dp, start = 20.dp, end = 20.dp)
|
||||
) {
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 6.dp, bottom = 6.dp)
|
||||
) {
|
||||
Dragger(modifier = Modifier.align(Alignment.Center))
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
@ -477,5 +410,5 @@ fun PreviewViewerEditWidget() {
|
|||
id = "1",
|
||||
isActive = false
|
||||
)
|
||||
ViewerEditWidget(state = state, action = {}, scope = CoroutineScope(Dispatchers.Main))
|
||||
ViewerEditWidget(state = state, action = {})
|
||||
}
|
|
@ -1,46 +1,33 @@
|
|||
package com.anytypeio.anytype.core_ui.widgets.dv
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.ime
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.FractionalThreshold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.rememberSwipeableState
|
||||
import androidx.compose.material.swipeable
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_models.DVViewerType
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
|
@ -49,93 +36,80 @@ import com.anytypeio.anytype.core_ui.R
|
|||
import com.anytypeio.anytype.core_ui.foundation.Divider
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
||||
import com.anytypeio.anytype.core_ui.views.BodyRegular
|
||||
import com.anytypeio.anytype.core_ui.widgets.DragStates
|
||||
import com.anytypeio.anytype.core_ui.views.Title1
|
||||
import com.anytypeio.anytype.presentation.sets.ViewerLayoutWidgetUi
|
||||
import com.anytypeio.anytype.presentation.sets.ViewerLayoutWidgetUi.Action.Dismiss
|
||||
import com.anytypeio.anytype.presentation.sets.ViewerLayoutWidgetUi.State.ImagePreview
|
||||
import kotlin.math.roundToInt
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ViewerLayoutCoverWidget(
|
||||
uiState: ViewerLayoutWidgetUi,
|
||||
action: (ViewerLayoutWidgetUi.Action) -> Unit,
|
||||
scope: CoroutineScope
|
||||
) {
|
||||
|
||||
val swipeableState = rememberSwipeableState(DragStates.VISIBLE)
|
||||
val sizePx = with(LocalDensity.current) { LocalConfiguration.current.screenHeightDp.dp.toPx() }
|
||||
val bottomSheetState = rememberModalBottomSheetState(
|
||||
skipPartiallyExpanded = true
|
||||
)
|
||||
|
||||
val lazyListState = rememberLazyListState()
|
||||
|
||||
if (swipeableState.isAnimationRunning && swipeableState.targetValue == DragStates.DISMISSED) {
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
action(ViewerLayoutWidgetUi.Action.DismissCoverMenu)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!uiState.showCoverMenu) {
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
scope.launch { swipeableState.snapTo(DragStates.VISIBLE) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = uiState.showCoverMenu,
|
||||
enter = slideInVertically { it },
|
||||
exit = slideOutVertically(tween(200)) { it },
|
||||
modifier = Modifier
|
||||
.swipeable(state = swipeableState,
|
||||
orientation = Orientation.Vertical,
|
||||
anchors = mapOf(
|
||||
0f to DragStates.VISIBLE, sizePx to DragStates.DISMISSED
|
||||
),
|
||||
thresholds = { _, _ -> FractionalThreshold(0.3f) })
|
||||
.offset { IntOffset(0, swipeableState.offset.value.roundToInt()) }
|
||||
) {
|
||||
val shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
|
||||
Box(
|
||||
if (uiState.showCoverMenu) {
|
||||
ModalBottomSheet(
|
||||
modifier = Modifier
|
||||
.windowInsetsPadding(WindowInsets.ime)
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.background(
|
||||
color = colorResource(id = R.color.background_secondary),
|
||||
shape = shape
|
||||
.wrapContentHeight(),
|
||||
scrimColor = colorResource(id = R.color.modal_screen_outside_background),
|
||||
containerColor = colorResource(id = R.color.background_secondary),
|
||||
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
|
||||
onDismissRequest = { action(Dismiss) },
|
||||
sheetState = bottomSheetState,
|
||||
dragHandle = { DragHandle() },
|
||||
content = {
|
||||
Content(
|
||||
uiState = uiState,
|
||||
action = action
|
||||
)
|
||||
.clip(shape)
|
||||
) {
|
||||
WidgetHeader(title = stringResource(R.string.view_layout_cover_widget_title))
|
||||
LazyColumn(
|
||||
state = lazyListState,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 64.dp, bottom = 250.dp)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ColumnScope.Content(
|
||||
uiState: ViewerLayoutWidgetUi,
|
||||
action: (ViewerLayoutWidgetUi.Action) -> Unit,
|
||||
) {
|
||||
val lazyListState = rememberLazyListState()
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||
text = stringResource(R.string.view_layout_cover_widget_title),
|
||||
style = Title1,
|
||||
color = colorResource(R.color.text_primary)
|
||||
)
|
||||
LazyColumn(
|
||||
state = lazyListState,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 12.dp, bottom = 250.dp)
|
||||
) {
|
||||
items(
|
||||
count = uiState.imagePreviewItems.size,
|
||||
key = { index -> uiState.imagePreviewItems[index].relationKey.key }
|
||||
) { idx ->
|
||||
val item = uiState.imagePreviewItems[idx]
|
||||
val title = item.getTitle()
|
||||
val iconDrawableRes = when (item) {
|
||||
is ImagePreview.None -> null
|
||||
is ImagePreview.PageCover -> null
|
||||
is ImagePreview.Custom -> R.drawable.ic_relation_attachment_24
|
||||
}
|
||||
CoverItem(
|
||||
text = title,
|
||||
checked = item.isChecked,
|
||||
iconDrawableRes = iconDrawableRes
|
||||
) {
|
||||
items(
|
||||
count = uiState.imagePreviewItems.size,
|
||||
key = { index -> uiState.imagePreviewItems[index].relationKey.key }
|
||||
) { idx ->
|
||||
val item = uiState.imagePreviewItems[idx]
|
||||
val title = item.getTitle()
|
||||
val iconDrawableRes = when (item) {
|
||||
is ImagePreview.None -> null
|
||||
is ImagePreview.PageCover -> null
|
||||
is ImagePreview.Custom -> R.drawable.ic_relation_attachment_24
|
||||
}
|
||||
CoverItem(
|
||||
text = title,
|
||||
checked = item.isChecked,
|
||||
iconDrawableRes = iconDrawableRes
|
||||
) {
|
||||
action(ViewerLayoutWidgetUi.Action.ImagePreviewUpdate(item))
|
||||
}
|
||||
}
|
||||
action(ViewerLayoutWidgetUi.Action.ImagePreviewUpdate(item))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -217,9 +191,6 @@ fun PreviewLayoutCoverWidget() {
|
|||
)
|
||||
)
|
||||
),
|
||||
action = {},
|
||||
scope = CoroutineScope(
|
||||
Dispatchers.Main
|
||||
)
|
||||
action = {}
|
||||
)
|
||||
}
|
|
@ -21,6 +21,7 @@ import androidx.compose.ui.res.colorResource
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
|
||||
import com.anytypeio.anytype.core_ui.foundation.Divider
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
||||
import com.anytypeio.anytype.core_ui.views.BodyCallout
|
||||
|
@ -36,7 +37,7 @@ fun ViewerLayoutListMenu(
|
|||
if (show) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.offset(x = offsetX - 220.dp, y = (-52).dp)
|
||||
.offset(x = offsetX - 220.dp, y = 246.dp)
|
||||
.width(220.dp)
|
||||
.wrapContentHeight()
|
||||
.shadow(
|
||||
|
@ -88,4 +89,14 @@ fun ViewerLayoutListMenu(
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@DefaultPreviews
|
||||
fun ViewerLayoutListMenuPreview() {
|
||||
ViewerLayoutListMenu(
|
||||
show = true,
|
||||
action = {},
|
||||
coordinates = Rect(0f, 0f, 0f, 0f)
|
||||
)
|
||||
}
|
|
@ -1,230 +1,201 @@
|
|||
package com.anytypeio.anytype.core_ui.widgets.dv
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.ime
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.FractionalThreshold
|
||||
import androidx.compose.material.Switch
|
||||
import androidx.compose.material.SwitchDefaults
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.rememberSwipeableState
|
||||
import androidx.compose.material.swipeable
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.boundsInRoot
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Devices
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_models.DVViewerType
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.foundation.Divider
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
||||
import com.anytypeio.anytype.core_ui.views.Caption2Medium
|
||||
import com.anytypeio.anytype.core_ui.views.Caption2Regular
|
||||
import com.anytypeio.anytype.core_ui.views.Title1
|
||||
import com.anytypeio.anytype.core_ui.views.UXBody
|
||||
import com.anytypeio.anytype.core_ui.widgets.DragStates
|
||||
import com.anytypeio.anytype.presentation.sets.ViewerLayoutWidgetUi
|
||||
import com.anytypeio.anytype.presentation.sets.ViewerLayoutWidgetUi.Action.CardSizeMenu
|
||||
import com.anytypeio.anytype.presentation.sets.ViewerLayoutWidgetUi.Action.Dismiss
|
||||
import com.anytypeio.anytype.presentation.sets.ViewerLayoutWidgetUi.Action.FitImage
|
||||
import com.anytypeio.anytype.presentation.sets.ViewerLayoutWidgetUi.Action.Icon
|
||||
import kotlin.math.roundToInt
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import com.anytypeio.anytype.presentation.sets.ViewerLayoutWidgetUi.State.CardSize
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ViewerLayoutWidget(
|
||||
uiState: ViewerLayoutWidgetUi,
|
||||
action: (ViewerLayoutWidgetUi.Action) -> Unit,
|
||||
scope: CoroutineScope
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.BottomStart,
|
||||
) {
|
||||
val currentState by rememberUpdatedState(uiState)
|
||||
val swipeableState = rememberSwipeableState(DragStates.VISIBLE)
|
||||
val bottomSheetState = rememberModalBottomSheetState(
|
||||
skipPartiallyExpanded = true
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = currentState.showWidget,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(
|
||||
tween(200)
|
||||
)
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.Black.copy(alpha = 0.4f))
|
||||
.noRippleClickable { action(Dismiss) }
|
||||
)
|
||||
}
|
||||
var currentCoordinates: Rect by remember {
|
||||
mutableStateOf(Rect.Zero)
|
||||
}
|
||||
|
||||
if (swipeableState.isAnimationRunning && swipeableState.targetValue == DragStates.DISMISSED) {
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
action(Dismiss)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentState.showWidget) {
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
scope.launch { swipeableState.snapTo(DragStates.VISIBLE) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val sizePx = with(LocalDensity.current) { LocalConfiguration.current.screenHeightDp.dp.toPx() }
|
||||
|
||||
var currentCoordinates: androidx.compose.ui.geometry.Rect by remember {
|
||||
mutableStateOf(androidx.compose.ui.geometry.Rect.Zero)
|
||||
}
|
||||
|
||||
var currentCoverItem by remember {
|
||||
mutableStateOf(uiState.getActiveImagePreviewItem())
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = uiState) {
|
||||
currentCoverItem = uiState.getActiveImagePreviewItem()
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = currentState.showWidget,
|
||||
enter = slideInVertically { it },
|
||||
exit = slideOutVertically(tween(200)) { it },
|
||||
if (uiState.showWidget) {
|
||||
ModalBottomSheet(
|
||||
modifier = Modifier
|
||||
.swipeable(state = swipeableState,
|
||||
orientation = Orientation.Vertical,
|
||||
anchors = mapOf(
|
||||
0f to DragStates.VISIBLE, sizePx to DragStates.DISMISSED
|
||||
),
|
||||
thresholds = { _, _ -> FractionalThreshold(0.3f) })
|
||||
.offset { IntOffset(0, swipeableState.offset.value.roundToInt()) }
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.background(
|
||||
color = colorResource(id = R.color.background_secondary),
|
||||
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
|
||||
),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(bottom = 20.dp)
|
||||
) {
|
||||
WidgetHeader(title = stringResource(R.string.view_layout_widget_title))
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
LayoutIcons(uiState = currentState, action = action)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
LayoutSwitcherItem(
|
||||
text = stringResource(id = R.string.icon),
|
||||
checked = currentState.withIcon.toggled,
|
||||
onCheckedChanged = { action(Icon(it)) }
|
||||
)
|
||||
val isGallery = currentState.layoutType == DVViewerType.GALLERY
|
||||
Divider(visible = isGallery)
|
||||
ColumnItem(
|
||||
.windowInsetsPadding(WindowInsets.ime)
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
scrimColor = colorResource(id = R.color.modal_screen_outside_background),
|
||||
containerColor = colorResource(id = R.color.background_secondary),
|
||||
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
|
||||
onDismissRequest = { action(Dismiss) },
|
||||
sheetState = bottomSheetState,
|
||||
dragHandle = { DragHandle() },
|
||||
content = {
|
||||
var currentCoordinates: Rect by remember {
|
||||
mutableStateOf(Rect.Zero)
|
||||
}
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
ViewerLayoutContent(
|
||||
modifier = Modifier
|
||||
.padding(start = 20.dp, end = 20.dp)
|
||||
.alpha(if (isGallery) 1f else 0f),
|
||||
title = stringResource(id = R.string.card_size),
|
||||
value = when (currentState.cardSize) {
|
||||
ViewerLayoutWidgetUi.State.CardSize.Large -> stringResource(id = R.string.large)
|
||||
ViewerLayoutWidgetUi.State.CardSize.Small -> stringResource(id = R.string.small)
|
||||
},
|
||||
onClick = {
|
||||
action(ViewerLayoutWidgetUi.Action.CardSizeMenu)
|
||||
},
|
||||
arrow = painterResource(id = R.drawable.ic_list_arrow_18),
|
||||
imageModifier = Modifier
|
||||
.onGloballyPositioned { coordinates ->
|
||||
if (coordinates.isAttached) {
|
||||
with(coordinates.boundsInRoot()) {
|
||||
currentCoordinates = this
|
||||
}
|
||||
} else {
|
||||
currentCoordinates = androidx.compose.ui.geometry.Rect.Zero
|
||||
}
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(bottom = 20.dp),
|
||||
currentState = uiState,
|
||||
action = action,
|
||||
updateCurrentCoordinates = { currentCoordinates = it }
|
||||
)
|
||||
Divider(visible = isGallery)
|
||||
ColumnItem(
|
||||
modifier = Modifier
|
||||
.padding(start = 20.dp, end = 20.dp)
|
||||
.alpha(if (isGallery) 1f else 0f),
|
||||
title = stringResource(id = R.string.cover),
|
||||
value = currentCoverItem.getTitle(),
|
||||
onClick = {
|
||||
action(ViewerLayoutWidgetUi.Action.CoverMenu)
|
||||
},
|
||||
arrow = painterResource(id = R.drawable.ic_arrow_disclosure_18)
|
||||
)
|
||||
Divider(visible = isGallery)
|
||||
LayoutSwitcherItem(
|
||||
modifier = Modifier.alpha(if (isGallery) 1f else 0f),
|
||||
text = stringResource(id = R.string.fit_image),
|
||||
checked = currentState.fitImage.toggled,
|
||||
onCheckedChanged = { action(FitImage(it)) }
|
||||
ViewerLayoutListMenu(
|
||||
show = uiState.showCardSize,
|
||||
action = action,
|
||||
coordinates = currentCoordinates
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
ViewerLayoutListMenu(
|
||||
show = currentState.showCardSize,
|
||||
action = action,
|
||||
coordinates = currentCoordinates
|
||||
)
|
||||
ViewerLayoutCoverWidget(
|
||||
uiState = uiState,
|
||||
action = action,
|
||||
scope = scope
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ViewerLayoutContent(
|
||||
modifier: Modifier,
|
||||
currentState: ViewerLayoutWidgetUi,
|
||||
action: (ViewerLayoutWidgetUi.Action) -> Unit,
|
||||
updateCurrentCoordinates: (Rect) -> Unit = {}
|
||||
) {
|
||||
var currentCoverItem by remember {
|
||||
mutableStateOf(currentState.getActiveImagePreviewItem())
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = currentState) {
|
||||
currentCoverItem = currentState.getActiveImagePreviewItem()
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(48.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier,
|
||||
text = stringResource(R.string.view_layout_widget_title),
|
||||
style = Title1,
|
||||
color = colorResource(R.color.text_primary)
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
LayoutIcons(uiState = currentState, action = action)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
LayoutSwitcherItem(
|
||||
text = stringResource(id = R.string.icon),
|
||||
checked = currentState.withIcon.toggled,
|
||||
onCheckedChanged = { action(Icon(it)) }
|
||||
)
|
||||
val isGallery = currentState.layoutType == DVViewerType.GALLERY
|
||||
Divider(visible = isGallery)
|
||||
ColumnItem(
|
||||
modifier = Modifier
|
||||
.padding(start = 20.dp, end = 20.dp)
|
||||
.alpha(if (isGallery) 1f else 0f),
|
||||
title = stringResource(id = R.string.card_size),
|
||||
value = when (currentState.cardSize) {
|
||||
CardSize.Large -> stringResource(id = R.string.large)
|
||||
CardSize.Small -> stringResource(id = R.string.small)
|
||||
},
|
||||
onClick = {
|
||||
action(CardSizeMenu)
|
||||
},
|
||||
arrow = painterResource(id = R.drawable.ic_list_arrow_18),
|
||||
imageModifier = Modifier
|
||||
.onGloballyPositioned { coordinates ->
|
||||
if (coordinates.isAttached) {
|
||||
with(coordinates.boundsInRoot()) {
|
||||
updateCurrentCoordinates(this)
|
||||
}
|
||||
} else {
|
||||
updateCurrentCoordinates(Rect.Zero)
|
||||
}
|
||||
}
|
||||
)
|
||||
Divider(visible = isGallery)
|
||||
ColumnItem(
|
||||
modifier = Modifier
|
||||
.padding(start = 20.dp, end = 20.dp)
|
||||
.alpha(if (isGallery) 1f else 0f),
|
||||
title = stringResource(id = R.string.cover),
|
||||
value = currentCoverItem.getTitle(),
|
||||
onClick = {
|
||||
action(ViewerLayoutWidgetUi.Action.CoverMenu)
|
||||
},
|
||||
arrow = painterResource(id = R.drawable.ic_arrow_disclosure_18)
|
||||
)
|
||||
Divider(visible = isGallery)
|
||||
LayoutSwitcherItem(
|
||||
modifier = Modifier.alpha(if (isGallery) 1f else 0f),
|
||||
text = stringResource(id = R.string.fit_image),
|
||||
checked = currentState.fitImage.toggled,
|
||||
onCheckedChanged = { action(FitImage(it)) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -321,7 +292,7 @@ fun LayoutIcons(uiState: ViewerLayoutWidgetUi, action: (ViewerLayoutWidgetUi.Act
|
|||
layoutType = DVViewerType.GRID,
|
||||
imageResource = R.drawable.ic_layout_grid,
|
||||
imageResourceSelected = R.drawable.ic_layout_grid_selected,
|
||||
contentDescription = "Grid",
|
||||
contentDescription = stringResource(id = R.string.view_grid),
|
||||
click = { action(ViewerLayoutWidgetUi.Action.Type(DVViewerType.GRID)) }
|
||||
)
|
||||
LayoutIcon(
|
||||
|
@ -330,7 +301,7 @@ fun LayoutIcons(uiState: ViewerLayoutWidgetUi, action: (ViewerLayoutWidgetUi.Act
|
|||
layoutType = DVViewerType.GALLERY,
|
||||
imageResourceSelected = R.drawable.ic_layout_gallery_selected,
|
||||
imageResource = R.drawable.ic_layout_gallery,
|
||||
contentDescription = "Gallery",
|
||||
contentDescription = stringResource(id = R.string.view_gallery),
|
||||
click = { action(ViewerLayoutWidgetUi.Action.Type(DVViewerType.GALLERY)) }
|
||||
)
|
||||
LayoutIcon(
|
||||
|
@ -339,7 +310,7 @@ fun LayoutIcons(uiState: ViewerLayoutWidgetUi, action: (ViewerLayoutWidgetUi.Act
|
|||
layoutType = DVViewerType.LIST,
|
||||
imageResourceSelected = R.drawable.ic_layout_list_selected,
|
||||
imageResource = R.drawable.ic_layout_list,
|
||||
contentDescription = "List",
|
||||
contentDescription = stringResource(id = R.string.view_list),
|
||||
click = { action(ViewerLayoutWidgetUi.Action.Type(DVViewerType.LIST)) }
|
||||
)
|
||||
LayoutIcon(
|
||||
|
@ -348,7 +319,7 @@ fun LayoutIcons(uiState: ViewerLayoutWidgetUi, action: (ViewerLayoutWidgetUi.Act
|
|||
layoutType = DVViewerType.BOARD,
|
||||
imageResourceSelected = R.drawable.ic_layout_kanban_selected,
|
||||
imageResource = R.drawable.ic_layout_kanban,
|
||||
contentDescription = "Kanban",
|
||||
contentDescription = stringResource(id = R.string.view_kanban),
|
||||
click = { action(ViewerLayoutWidgetUi.Action.Type(DVViewerType.BOARD)) }
|
||||
)
|
||||
LayoutIcon(
|
||||
|
@ -421,7 +392,7 @@ fun PreviewLayoutScreen() {
|
|||
ViewerLayoutWidget(
|
||||
uiState = ViewerLayoutWidgetUi(
|
||||
showWidget = true,
|
||||
layoutType = DVViewerType.GRID,
|
||||
layoutType = DVViewerType.GALLERY,
|
||||
withIcon = ViewerLayoutWidgetUi.State.Toggle.WithIcon(
|
||||
toggled = true
|
||||
),
|
||||
|
@ -429,15 +400,12 @@ fun PreviewLayoutScreen() {
|
|||
toggled = false
|
||||
),
|
||||
cardSize = ViewerLayoutWidgetUi.State.CardSize.Small,
|
||||
showCardSize = false,
|
||||
showCardSize = true,
|
||||
viewer = "",
|
||||
showCoverMenu = false,
|
||||
imagePreviewItems = emptyList()
|
||||
),
|
||||
action = {},
|
||||
scope = CoroutineScope(
|
||||
Dispatchers.Main
|
||||
)
|
||||
action = {}
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,386 +1,188 @@
|
|||
package com.anytypeio.anytype.core_ui.widgets.dv
|
||||
|
||||
import android.view.HapticFeedbackConstants
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.ime
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.FractionalThreshold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.rememberSwipeableState
|
||||
import androidx.compose.material.swipeable
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.constraintlayout.compose.Dimension
|
||||
import androidx.constraintlayout.compose.Visibility
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.extensions.swapList
|
||||
import com.anytypeio.anytype.core_ui.foundation.Divider
|
||||
import com.anytypeio.anytype.core_ui.foundation.Dragger
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
||||
import com.anytypeio.anytype.core_ui.views.BodyRegular
|
||||
import com.anytypeio.anytype.core_ui.views.Caption2Regular
|
||||
import com.anytypeio.anytype.core_ui.views.HeadlineSubheading
|
||||
import com.anytypeio.anytype.core_ui.views.Title1
|
||||
import com.anytypeio.anytype.core_ui.widgets.DragStates
|
||||
import com.anytypeio.anytype.presentation.sets.ViewersWidgetUi
|
||||
import com.anytypeio.anytype.presentation.sets.ViewersWidgetUi.Action.Delete
|
||||
import com.anytypeio.anytype.presentation.sets.ViewersWidgetUi.Action.Dismiss
|
||||
import com.anytypeio.anytype.presentation.sets.ViewersWidgetUi.Action.DoneMode
|
||||
import com.anytypeio.anytype.presentation.sets.ViewersWidgetUi.Action.Edit
|
||||
import com.anytypeio.anytype.presentation.sets.ViewersWidgetUi.Action.EditMode
|
||||
import kotlin.math.roundToInt
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import com.anytypeio.anytype.presentation.sets.viewer.ViewerView
|
||||
import org.burnoutcrew.reorderable.ReorderableItem
|
||||
import org.burnoutcrew.reorderable.ReorderableLazyListState
|
||||
import org.burnoutcrew.reorderable.detectReorder
|
||||
import org.burnoutcrew.reorderable.rememberReorderableLazyListState
|
||||
import org.burnoutcrew.reorderable.reorderable
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ViewersWidget(
|
||||
state: ViewersWidgetUi,
|
||||
action: (ViewersWidgetUi.Action) -> Unit,
|
||||
scope: CoroutineScope
|
||||
) {
|
||||
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.BottomStart,
|
||||
) {
|
||||
val bottomSheetState = rememberModalBottomSheetState(
|
||||
skipPartiallyExpanded = true
|
||||
)
|
||||
|
||||
val currentState by rememberUpdatedState(state)
|
||||
val swipeableState = rememberSwipeableState(DragStates.VISIBLE)
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = currentState.showWidget,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(tween(100))
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.Black.copy(alpha = 0.4f))
|
||||
.noRippleClickable { action(Dismiss) }
|
||||
)
|
||||
}
|
||||
|
||||
if (swipeableState.isAnimationRunning && swipeableState.targetValue == DragStates.DISMISSED) {
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
action(Dismiss)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentState.showWidget) {
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
scope.launch { swipeableState.snapTo(DragStates.VISIBLE) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val sizePx =
|
||||
with(LocalDensity.current) { LocalConfiguration.current.screenHeightDp.dp.toPx() }
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = currentState.showWidget,
|
||||
enter = slideInVertically { it },
|
||||
exit = slideOutVertically { it },
|
||||
if (state.showWidget) {
|
||||
ModalBottomSheet(
|
||||
modifier = Modifier
|
||||
.swipeable(
|
||||
state = swipeableState,
|
||||
orientation = Orientation.Vertical,
|
||||
anchors = mapOf(
|
||||
0f to DragStates.VISIBLE, sizePx to DragStates.DISMISSED
|
||||
),
|
||||
thresholds = { _, _ -> FractionalThreshold(0.3f) })
|
||||
.offset { IntOffset(0, swipeableState.offset.value.roundToInt()) }
|
||||
) {
|
||||
ViewersWidgetContent(state, action)
|
||||
}
|
||||
.windowInsetsPadding(WindowInsets.ime)
|
||||
.padding(start = 8.dp, end = 8.dp, bottom = 30.dp)
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
scrimColor = colorResource(id = R.color.modal_screen_outside_background),
|
||||
containerColor = colorResource(id = R.color.background_secondary),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
onDismissRequest = { action(Dismiss) },
|
||||
sheetState = bottomSheetState,
|
||||
dragHandle = { DragHandle() },
|
||||
content = {
|
||||
ViewersWidgetContent(
|
||||
modifier = Modifier.padding(bottom = 168.dp),
|
||||
state = state,
|
||||
action = action
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DragHandle() {
|
||||
Column {
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
Dragger()
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ViewersWidgetContent(
|
||||
modifier: Modifier,
|
||||
state: ViewersWidgetUi,
|
||||
action: (ViewersWidgetUi.Action) -> Unit
|
||||
) {
|
||||
val currentState by rememberUpdatedState(state)
|
||||
|
||||
val views = remember { mutableStateOf(currentState.items) }
|
||||
views.value = currentState.items
|
||||
val views = remember { mutableStateListOf<ViewerView>() }
|
||||
views.swapList(state.items)
|
||||
|
||||
val isEditing = remember { mutableStateOf(currentState.isEditing && !state.isReadOnly) }
|
||||
isEditing.value = currentState.isEditing && !state.isReadOnly
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
val lazyListState = rememberReorderableLazyListState(
|
||||
onMove = { from, to ->
|
||||
val newList = views.toMutableList().apply {
|
||||
add(to.index, removeAt(from.index))
|
||||
}
|
||||
views.swapList(newList)
|
||||
},
|
||||
onDragEnd = { from, to ->
|
||||
action(
|
||||
ViewersWidgetUi.Action.OnMove(
|
||||
currentViews = views,
|
||||
from = from,
|
||||
to = to
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(start = 8.dp, end = 8.dp, bottom = 15.dp, top = 24.dp)
|
||||
.background(
|
||||
color = colorResource(id = R.color.background_secondary),
|
||||
shape = RoundedCornerShape(size = 16.dp)
|
||||
),
|
||||
) {
|
||||
Column(
|
||||
Header(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(bottom = 16.dp)
|
||||
) {
|
||||
Box(modifier = Modifier
|
||||
.height(48.dp),
|
||||
isEditingMode = state.isEditing,
|
||||
isReadOnlyState = state.isReadOnly,
|
||||
action = action
|
||||
)
|
||||
|
||||
LazyColumn(
|
||||
state = lazyListState.listState,
|
||||
modifier = Modifier
|
||||
.reorderable(lazyListState)
|
||||
.fillMaxWidth()
|
||||
.padding(top = 6.dp, bottom = 6.dp)
|
||||
) {
|
||||
Dragger(modifier = Modifier.align(Alignment.Center))
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(48.dp)
|
||||
) {
|
||||
if (!state.isReadOnly) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterStart),
|
||||
) {
|
||||
if (currentState.isEditing) {
|
||||
ActionText(
|
||||
text = stringResource(id = R.string.done),
|
||||
click = { action(DoneMode) }
|
||||
)
|
||||
} else {
|
||||
ActionText(
|
||||
text = stringResource(id = R.string.edit),
|
||||
click = { action(EditMode) }
|
||||
)
|
||||
}
|
||||
.wrapContentHeight()
|
||||
) {
|
||||
items(
|
||||
count = views.size,
|
||||
key = { index -> views[index].id },
|
||||
) { index ->
|
||||
|
||||
ReorderableItem(
|
||||
modifier = Modifier.animateItem(),
|
||||
reorderableState = lazyListState,
|
||||
key = views[index].id
|
||||
) { isDragging ->
|
||||
val currentItem = LocalView.current
|
||||
if (isDragging) {
|
||||
currentItem.isHapticFeedbackEnabled = true
|
||||
currentItem.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||
}
|
||||
}
|
||||
Box(modifier = Modifier.align(Alignment.Center)) {
|
||||
Text(
|
||||
text = stringResource(R.string.views),
|
||||
style = Title1,
|
||||
color = colorResource(R.color.text_primary)
|
||||
Item(
|
||||
modifier = Modifier,
|
||||
lazyListState = lazyListState,
|
||||
isDragging = isDragging,
|
||||
isEditing = state.isEditing,
|
||||
action = action,
|
||||
view = views[index]
|
||||
)
|
||||
|
||||
}
|
||||
if (!state.isReadOnly) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.noRippleThrottledClickable {
|
||||
action.invoke(ViewersWidgetUi.Action.Plus)
|
||||
}
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier.padding(
|
||||
start = 16.dp,
|
||||
top = 12.dp,
|
||||
bottom = 12.dp,
|
||||
end = 16.dp
|
||||
),
|
||||
painter = painterResource(id = R.drawable.ic_default_plus),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val lazyListState = rememberReorderableLazyListState(
|
||||
onMove = { from, to ->
|
||||
views.value = views.value.toMutableList().apply {
|
||||
add(to.index, removeAt(from.index))
|
||||
}
|
||||
},
|
||||
onDragEnd = { from, to ->
|
||||
action(
|
||||
ViewersWidgetUi.Action.OnMove(
|
||||
currentViews = views.value,
|
||||
from = from,
|
||||
to = to
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
LazyColumn(
|
||||
state = lazyListState.listState,
|
||||
modifier = Modifier
|
||||
.reorderable(lazyListState)
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
) {
|
||||
itemsIndexed(
|
||||
items = views.value,
|
||||
key = { _, item -> item.id }) { index, view ->
|
||||
ReorderableItem(
|
||||
reorderableState = lazyListState,
|
||||
key = view.id
|
||||
) { isDragging ->
|
||||
val currentItem = LocalView.current
|
||||
if (isDragging) {
|
||||
currentItem.isHapticFeedbackEnabled = true
|
||||
currentItem.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||
}
|
||||
val alpha =
|
||||
animateFloatAsState(if (isDragging) 0.8f else 1.0f, label = "")
|
||||
ConstraintLayout(
|
||||
modifier = Modifier
|
||||
.height(52.dp)
|
||||
.fillMaxWidth()
|
||||
.padding(start = 20.dp, end = 20.dp)
|
||||
.animateContentSize(
|
||||
animationSpec = spring(
|
||||
stiffness = Spring.StiffnessLow
|
||||
)
|
||||
)
|
||||
.alpha(alpha.value)
|
||||
) {
|
||||
val (delete, text, edit, dnd, unsupported) = createRefs()
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.noRippleThrottledClickable {
|
||||
action.invoke(Delete(view.id))
|
||||
}
|
||||
.constrainAs(delete) {
|
||||
start.linkTo(parent.start)
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
visibility =
|
||||
if (isEditing.value && !view.isActive) Visibility.Visible else Visibility.Gone
|
||||
},
|
||||
painter = painterResource(id = R.drawable.ic_relation_delete),
|
||||
contentDescription = "Delete view"
|
||||
)
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.detectReorder(lazyListState)
|
||||
.constrainAs(dnd) {
|
||||
end.linkTo(parent.end)
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
visibility =
|
||||
if (isEditing.value) Visibility.Visible else Visibility.Gone
|
||||
|
||||
},
|
||||
painter = painterResource(id = R.drawable.ic_dnd),
|
||||
contentDescription = "Dnd view"
|
||||
)
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.noRippleThrottledClickable {
|
||||
action.invoke(Edit(id = view.id))
|
||||
}
|
||||
.constrainAs(edit) {
|
||||
end.linkTo(dnd.start, margin = 16.dp)
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
visibility =
|
||||
if (isEditing.value) Visibility.Visible else Visibility.Gone
|
||||
},
|
||||
painter = painterResource(id = R.drawable.ic_edit_24),
|
||||
contentDescription = "Edit view"
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.constrainAs(unsupported) {
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
end.linkTo(edit.start)
|
||||
visibility =
|
||||
if (!isEditing.value && view.isUnsupported) Visibility.Visible else Visibility.Gone
|
||||
},
|
||||
text = stringResource(id = R.string.unsupported),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
style = Caption2Regular,
|
||||
textAlign = TextAlign.Left
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.noRippleThrottledClickable {
|
||||
if (!isEditing.value) {
|
||||
|
||||
action.invoke(
|
||||
ViewersWidgetUi.Action.SetActive(
|
||||
id = view.id,
|
||||
type = view.type
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
.constrainAs(text) {
|
||||
start.linkTo(
|
||||
delete.end,
|
||||
margin = 12.dp,
|
||||
goneMargin = 0.dp
|
||||
)
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
end.linkTo(
|
||||
unsupported.start,
|
||||
margin = 8.dp,
|
||||
goneMargin = 38.dp
|
||||
)
|
||||
width = Dimension.fillToConstraints
|
||||
},
|
||||
text = view.name.ifBlank { stringResource(id = R.string.untitled) },
|
||||
color = colorResource(id = if (view.isActive) R.color.text_primary else R.color.glyph_active),
|
||||
style = HeadlineSubheading,
|
||||
textAlign = TextAlign.Left,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
if (index != views.value.size - 1) {
|
||||
Divider()
|
||||
}
|
||||
if (index != views.size - 1) {
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -388,14 +190,195 @@ private fun ViewersWidgetContent(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun ActionText(text: String, click: () -> Unit) {
|
||||
private fun Item(
|
||||
modifier: Modifier,
|
||||
lazyListState: ReorderableLazyListState,
|
||||
isDragging: Boolean,
|
||||
isEditing: Boolean,
|
||||
action: (ViewersWidgetUi.Action) -> Unit,
|
||||
view: ViewerView
|
||||
) {
|
||||
val alpha = animateFloatAsState(if (isDragging) 0.8f else 1.0f, label = "")
|
||||
ConstraintLayout(
|
||||
modifier = modifier
|
||||
.height(52.dp)
|
||||
.fillMaxWidth()
|
||||
.padding(start = 20.dp, end = 20.dp)
|
||||
.animateContentSize(
|
||||
animationSpec = spring(
|
||||
stiffness = Spring.StiffnessLow
|
||||
)
|
||||
)
|
||||
.alpha(alpha.value)
|
||||
) {
|
||||
val (delete, text, edit, dnd, unsupported) = createRefs()
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.noRippleThrottledClickable {
|
||||
action.invoke(Delete(view.id))
|
||||
}
|
||||
.constrainAs(delete) {
|
||||
start.linkTo(parent.start)
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
visibility =
|
||||
if (isEditing && !view.isActive) Visibility.Visible else Visibility.Gone
|
||||
},
|
||||
painter = painterResource(id = R.drawable.ic_relation_delete),
|
||||
contentDescription = "Delete view"
|
||||
)
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.detectReorder(lazyListState)
|
||||
.constrainAs(dnd) {
|
||||
end.linkTo(parent.end)
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
visibility =
|
||||
if (isEditing) Visibility.Visible else Visibility.Gone
|
||||
|
||||
},
|
||||
painter = painterResource(id = R.drawable.ic_dnd),
|
||||
contentDescription = "Dnd view"
|
||||
)
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.noRippleThrottledClickable {
|
||||
action.invoke(Edit(id = view.id))
|
||||
}
|
||||
.constrainAs(edit) {
|
||||
end.linkTo(dnd.start, margin = 16.dp)
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
visibility =
|
||||
if (isEditing) Visibility.Visible else Visibility.Gone
|
||||
},
|
||||
painter = painterResource(id = R.drawable.ic_edit_24),
|
||||
contentDescription = "Edit view"
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.constrainAs(unsupported) {
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
end.linkTo(edit.start)
|
||||
visibility =
|
||||
if (!isEditing && view.isUnsupported) Visibility.Visible else Visibility.Gone
|
||||
},
|
||||
text = stringResource(id = R.string.unsupported),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
style = Caption2Regular,
|
||||
textAlign = TextAlign.Left
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.noRippleThrottledClickable {
|
||||
if (!isEditing) {
|
||||
|
||||
action.invoke(
|
||||
ViewersWidgetUi.Action.SetActive(
|
||||
id = view.id, type = view.type
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
.constrainAs(text) {
|
||||
start.linkTo(
|
||||
delete.end, margin = 12.dp, goneMargin = 0.dp
|
||||
)
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
end.linkTo(
|
||||
unsupported.start, margin = 8.dp, goneMargin = 38.dp
|
||||
)
|
||||
width = Dimension.fillToConstraints
|
||||
},
|
||||
text = view.name.ifBlank { stringResource(id = R.string.untitled) },
|
||||
color = colorResource(id = if (view.isActive) R.color.text_primary else R.color.glyph_active),
|
||||
style = HeadlineSubheading,
|
||||
textAlign = TextAlign.Left,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Header(
|
||||
modifier: Modifier,
|
||||
isReadOnlyState: Boolean,
|
||||
isEditingMode: Boolean,
|
||||
action: (ViewersWidgetUi.Action) -> Unit
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
if (!isReadOnlyState) {
|
||||
ActionButtons(
|
||||
modifier = Modifier.align(Alignment.CenterStart),
|
||||
isEditingMode = isEditingMode,
|
||||
action = action
|
||||
)
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
text = stringResource(R.string.views),
|
||||
style = Title1,
|
||||
color = colorResource(R.color.text_primary)
|
||||
)
|
||||
if (!isReadOnlyState) {
|
||||
PlusButton(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.noRippleThrottledClickable {
|
||||
action.invoke(ViewersWidgetUi.Action.Plus)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ActionButtons(
|
||||
modifier: Modifier,
|
||||
isEditingMode: Boolean,
|
||||
action: (ViewersWidgetUi.Action) -> Unit
|
||||
) {
|
||||
if (isEditingMode) {
|
||||
ActionText(
|
||||
modifier = modifier,
|
||||
text = stringResource(id = R.string.done),
|
||||
click = { action(DoneMode) }
|
||||
)
|
||||
} else {
|
||||
ActionText(
|
||||
modifier = modifier,
|
||||
text = stringResource(id = R.string.edit),
|
||||
click = { action(EditMode) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.PlusButton(
|
||||
modifier: Modifier
|
||||
) {
|
||||
Image(
|
||||
modifier = modifier.padding(
|
||||
start = 16.dp,
|
||||
top = 12.dp,
|
||||
bottom = 12.dp,
|
||||
end = 16.dp
|
||||
),
|
||||
painter = painterResource(id = R.drawable.ic_default_plus),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ActionText(modifier: Modifier, text: String, click: () -> Unit) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
modifier = modifier
|
||||
.padding(
|
||||
start = 16.dp,
|
||||
top = 12.dp,
|
||||
bottom = 12.dp,
|
||||
end = 16.dp
|
||||
start = 16.dp, top = 12.dp, bottom = 12.dp, end = 16.dp
|
||||
)
|
||||
.noRippleThrottledClickable { click() },
|
||||
text = text,
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
package com.anytypeio.anytype.core_ui.widgets.dv
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.foundation.Dragger
|
||||
import com.anytypeio.anytype.core_ui.views.Title1
|
||||
|
||||
@Composable
|
||||
fun WidgetHeader(title: String) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
Dragger()
|
||||
Spacer(modifier = Modifier.height(18.dp))
|
||||
Text(
|
||||
text = title,
|
||||
style = Title1,
|
||||
color = colorResource(R.color.text_primary)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -43,6 +43,4 @@ data class ViewersWidgetUi(
|
|||
|
||||
data object Plus : Action()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue