mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-3108 Date as an Object | Add the “Open selected date” option to the Date Picker. (#1899)
This commit is contained in:
parent
a03f37129b
commit
98952de76b
13 changed files with 182 additions and 26 deletions
|
@ -52,6 +52,7 @@ import com.anytypeio.anytype.core_models.Id
|
|||
import com.anytypeio.anytype.core_models.Key
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.ThemeColor
|
||||
import com.anytypeio.anytype.core_models.TimeInMillis
|
||||
import com.anytypeio.anytype.core_models.Url
|
||||
import com.anytypeio.anytype.core_models.multiplayer.SpaceSyncAndP2PStatusState
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
|
@ -2120,6 +2121,10 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
)
|
||||
}
|
||||
|
||||
override fun onOpenDateObject(timeInMillis: TimeInMillis) {
|
||||
vm.onOpenDateObjectByTimeInMillis(timeInMillis)
|
||||
}
|
||||
|
||||
override fun onMoveTo(
|
||||
target: Id,
|
||||
space: Id,
|
||||
|
|
|
@ -13,6 +13,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Key
|
||||
import com.anytypeio.anytype.core_models.TimeInMillis
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_ui.features.relations.DocumentRelationAdapter
|
||||
import com.anytypeio.anytype.core_ui.reactive.textChanges
|
||||
|
@ -283,6 +284,10 @@ open class ObjectRelationListFragment : BaseBottomSheetFragment<FragmentRelation
|
|||
)
|
||||
}
|
||||
|
||||
override fun onOpenDateObject(timeInMillis: TimeInMillis) {
|
||||
vm.onOpenDateObjectByTimeInMillis(timeInMillis)
|
||||
}
|
||||
|
||||
override fun injectDependencies() {
|
||||
val param = DefaultComponentParam(
|
||||
ctx = ctx,
|
||||
|
|
|
@ -13,6 +13,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Key
|
||||
import com.anytypeio.anytype.core_models.TimeInMillis
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_ui.relations.DatePickerContent
|
||||
import com.anytypeio.anytype.core_ui.views.Title3
|
||||
|
@ -53,11 +54,14 @@ open class RelationDateValueFragment : BaseBottomSheetComposeFragment() {
|
|||
typography = MaterialTheme.typography.copy(bodyLarge = Title3)
|
||||
) {
|
||||
DatePickerContent(
|
||||
showHeader = true,
|
||||
showOpenSelectDate = true,
|
||||
state = vm.views.collectAsStateWithLifecycle().value,
|
||||
onDateSelected = vm::onDateSelected,
|
||||
onClear = vm::onClearClicked,
|
||||
onTodayClicked = vm::onTodayClicked,
|
||||
onTomorrowClicked = vm::onTomorrowClicked
|
||||
onTomorrowClicked = vm::onTomorrowClicked,
|
||||
openSelectedDate = vm::openSelectedDateClicked
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +88,14 @@ open class RelationDateValueFragment : BaseBottomSheetComposeFragment() {
|
|||
DatePickerFragment.new(command.timeInSeconds)
|
||||
.showChildFragment()
|
||||
}
|
||||
is DateValueCommand.OpenDateObject -> {
|
||||
withParent<DateValueEditReceiver> {
|
||||
onOpenDateObject(
|
||||
timeInMillis = command.timeInMillis
|
||||
)
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,5 +181,9 @@ open class RelationDateValueFragment : BaseBottomSheetComposeFragment() {
|
|||
objectId: Id,
|
||||
relationKey: Key
|
||||
)
|
||||
|
||||
fun onOpenDateObject(
|
||||
timeInMillis: TimeInMillis
|
||||
)
|
||||
}
|
||||
}
|
|
@ -44,6 +44,7 @@ import com.anytypeio.anytype.R
|
|||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Key
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.TimeInMillis
|
||||
import com.anytypeio.anytype.core_models.multiplayer.SpaceSyncAndP2PStatusState
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_ui.extensions.setEmojiOrNull
|
||||
|
@ -1410,6 +1411,10 @@ open class ObjectSetFragment :
|
|||
)
|
||||
}
|
||||
|
||||
override fun onOpenDateObject(timeInMillis: TimeInMillis) {
|
||||
vm.onOpenDateObjectByTimeInMillis(timeInMillis)
|
||||
}
|
||||
|
||||
override fun onProceedWithSelectSource(id: Id) {
|
||||
vm.onObjectSetQueryPicked(query = id)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
showSystemUi = true
|
||||
)
|
||||
@Preview(
|
||||
backgroundColor = 0x000000,
|
||||
backgroundColor = 0xFF121212,
|
||||
showBackground = true,
|
||||
uiMode = UI_MODE_NIGHT_YES,
|
||||
name = "Dark Mode",
|
||||
|
|
|
@ -51,7 +51,6 @@ fun EditorDatePicker(
|
|||
content = {
|
||||
DatePickerContent(
|
||||
state = DateValueView(timeInMillis = null),
|
||||
showHeader = false,
|
||||
onDateSelected = { onEvent(getDateSelectedEvent(uiState, it)) },
|
||||
onTodayClicked = { onEvent(getTodayEvent(uiState)) },
|
||||
onTomorrowClicked = { onEvent(getTomorrowEvent(uiState)) }
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
package com.anytypeio.anytype.core_ui.relations
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.Row
|
||||
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.wrapContentHeight
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.DatePicker
|
||||
import androidx.compose.material3.DatePickerDefaults
|
||||
import androidx.compose.material3.DatePickerState
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.SelectableDates
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -25,15 +30,18 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
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.dp
|
||||
import com.anytypeio.anytype.core_models.DATE_PICKER_YEAR_RANGE
|
||||
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.Dragger
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
||||
import com.anytypeio.anytype.core_ui.views.Title1
|
||||
import com.anytypeio.anytype.core_ui.views.UXBody
|
||||
import com.anytypeio.anytype.presentation.sets.DateValueView
|
||||
|
@ -42,11 +50,13 @@ import com.anytypeio.anytype.presentation.sets.DateValueView
|
|||
@Composable
|
||||
fun DatePickerContent(
|
||||
state: DateValueView,
|
||||
showHeader: Boolean = true,
|
||||
showHeader: Boolean = false,
|
||||
showOpenSelectDate: Boolean = false,
|
||||
onDateSelected: (Long?) -> Unit,
|
||||
onClear: () -> Unit = {},
|
||||
onTodayClicked: () -> Unit,
|
||||
onTomorrowClicked: () -> Unit
|
||||
onTomorrowClicked: () -> Unit,
|
||||
openSelectedDate: (Long) -> Unit = {}
|
||||
) {
|
||||
|
||||
val datePickerState = rememberDatePickerState(
|
||||
|
@ -123,30 +133,82 @@ fun DatePickerContent(
|
|||
colors = datePickerColors,
|
||||
)
|
||||
if (state.isEditable) {
|
||||
Divider(paddingStart = 0.dp, paddingEnd = 0.dp)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp, top = 11.dp, bottom = 11.dp)
|
||||
.noRippleClickable { onTodayClicked() },
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
text = stringResource(id = R.string.today),
|
||||
style = UXBody
|
||||
)
|
||||
Divider(paddingStart = 0.dp, paddingEnd = 0.dp)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp, top = 11.dp, bottom = 11.dp)
|
||||
.noRippleClickable { onTomorrowClicked() },
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
text = stringResource(id = R.string.tomorrow),
|
||||
style = UXBody
|
||||
CalendarShortcuts(
|
||||
showOpenSelectDate = showOpenSelectDate,
|
||||
datePickerState = datePickerState,
|
||||
onTodayClicked = onTodayClicked,
|
||||
onTomorrowClicked = onTomorrowClicked,
|
||||
openSelectedDate = openSelectedDate
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun ColumnScope.CalendarShortcuts(
|
||||
showOpenSelectDate: Boolean,
|
||||
datePickerState: DatePickerState,
|
||||
onTodayClicked: () -> Unit,
|
||||
onTomorrowClicked: () -> Unit,
|
||||
openSelectedDate: (Long) -> Unit
|
||||
) {
|
||||
Divider(paddingStart = 16.dp, paddingEnd = 0.dp)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.height(44.dp)
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp, top = 11.dp, bottom = 11.dp)
|
||||
.noRippleClickable { onTodayClicked() },
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
text = stringResource(id = R.string.today),
|
||||
style = UXBody
|
||||
)
|
||||
Divider(paddingStart = 16.dp, paddingEnd = 0.dp)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.height(44.dp)
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp, top = 11.dp, bottom = 11.dp)
|
||||
.noRippleClickable { onTomorrowClicked() },
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
text = stringResource(id = R.string.tomorrow),
|
||||
style = UXBody
|
||||
)
|
||||
if (datePickerState.selectedDateMillis != null && showOpenSelectDate) {
|
||||
Divider(paddingStart = 16.dp, paddingEnd = 0.dp)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.height(44.dp)
|
||||
.noRippleThrottledClickable {
|
||||
val timeInMillis = datePickerState.selectedDateMillis
|
||||
if (timeInMillis != null) {
|
||||
openSelectedDate(timeInMillis)
|
||||
}
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.padding(start = 16.dp),
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
text = stringResource(id = R.string.open_selected_date),
|
||||
style = UXBody
|
||||
)
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.wrapContentSize()
|
||||
.padding(end = 16.dp),
|
||||
painter = painterResource(id = R.drawable.ic_arrow_forward),
|
||||
contentDescription = "Open selected date"
|
||||
)
|
||||
}
|
||||
Divider(paddingStart = 16.dp, paddingEnd = 0.dp)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CalendarDragger(modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
|
@ -198,4 +260,19 @@ private fun Header(state: DateValueView, onClear: () -> Unit) {
|
|||
maxLines = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@DefaultPreviews
|
||||
@Composable
|
||||
private fun CalendarShortcutsPreview() {
|
||||
Column {
|
||||
CalendarShortcuts(
|
||||
showOpenSelectDate = true,
|
||||
onTodayClicked = {},
|
||||
onTomorrowClicked = {},
|
||||
openSelectedDate = {},
|
||||
datePickerState = rememberDatePickerState()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -35,10 +35,9 @@ fun CalendarScreen(
|
|||
is UiCalendarState.Calendar -> {
|
||||
DatePickerContent(
|
||||
state = DateValueView(timeInMillis = uiState.timeInMillis),
|
||||
showHeader = false,
|
||||
onDateSelected = { onDateEvent(DateEvent.Calendar.OnCalendarDateSelected(it)) },
|
||||
onTodayClicked = { onDateEvent(DateEvent.Calendar.OnTodayClick) },
|
||||
onTomorrowClicked = { onDateEvent(DateEvent.Calendar.OnTomorrowClick) }
|
||||
onTomorrowClicked = { onDateEvent(DateEvent.Calendar.OnTomorrowClick) },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -749,6 +749,7 @@
|
|||
<string name="today">Today</string>
|
||||
<string name="yesterday">Yesterday</string>
|
||||
<string name="tomorrow">Tomorrow</string>
|
||||
<string name="open_selected_date">Open selected date</string>
|
||||
<string name="no_date">No date</string>
|
||||
<string name="exact_day">Exact day</string>
|
||||
<string name="reorder">Reorder</string>
|
||||
|
|
|
@ -7752,6 +7752,21 @@ class EditorViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onOpenDateObjectByTimeInMillis(timeInMillis: TimeInMillis) {
|
||||
Timber.d("onOpenDateObjectByTimeInMillis, timeInMillis:[$timeInMillis]")
|
||||
viewModelScope.launch {
|
||||
fieldParser.getDateObjectByTimeInSeconds(
|
||||
timeInSeconds = timeInMillis / 1000,
|
||||
spaceId = vmParams.space,
|
||||
actionSuccess = { obj -> navigateToDateObject(obj.id) },
|
||||
actionFailure = {
|
||||
sendToast("Error while opening date object")
|
||||
Timber.e(it, "Error while opening date object")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDateSelected(
|
||||
timeInMillis: TimeInMillis?,
|
||||
actionType: EditorCalendarActionType,
|
||||
|
|
|
@ -14,6 +14,7 @@ import com.anytypeio.anytype.core_models.ObjectWrapper
|
|||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_models.RelationFormat
|
||||
import com.anytypeio.anytype.core_models.RelationLink
|
||||
import com.anytypeio.anytype.core_models.TimeInMillis
|
||||
import com.anytypeio.anytype.core_models.ext.mapToObjectWrapperType
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_utils.diff.DefaultObjectDiffIdentifier
|
||||
|
@ -566,6 +567,23 @@ class RelationListViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onOpenDateObjectByTimeInMillis(timeInMillis: TimeInMillis) {
|
||||
Timber.d("onOpenDateObjectByTimeInMillis, timeInMillis: $timeInMillis")
|
||||
viewModelScope.launch {
|
||||
fieldParser.getDateObjectByTimeInSeconds(
|
||||
timeInSeconds = timeInMillis / 1000,
|
||||
spaceId = vmParams.spaceId,
|
||||
actionSuccess = { obj ->
|
||||
commands.emit(Command.NavigateToDateObject(obj.id))
|
||||
},
|
||||
actionFailure = {
|
||||
Timber.e(it, "Failed to get date object by timestamp")
|
||||
_toasts.emit("Failed to get date object by timestamp")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Model : DefaultObjectDiffIdentifier {
|
||||
sealed class Section : Model() {
|
||||
object Featured : Section() {
|
||||
|
|
|
@ -2870,6 +2870,13 @@ class ObjectSetViewModel(
|
|||
toast("Date is not set")
|
||||
}
|
||||
}
|
||||
|
||||
fun onOpenDateObjectByTimeInMillis(timeInMillis: TimeInMillis) {
|
||||
Timber.d("onOpenDateObjectByTimeInMillis, timeInMillis:[$timeInMillis]")
|
||||
viewModelScope.launch {
|
||||
handleReadOnlyValue(timeInMillis = timeInMillis)
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -81,6 +81,14 @@ class RelationDateValueViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun openSelectedDateClicked(timeInMillis: TimeInMillis) {
|
||||
viewModelScope.launch {
|
||||
commands.emit(
|
||||
DateValueCommand.OpenDateObject(timeInMillis)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onYesterdayClicked() {
|
||||
setDate(timeInSeconds = dateProvider.getTimestampForYesterdayAtStartOfDay())
|
||||
}
|
||||
|
@ -165,6 +173,7 @@ class RelationDateValueViewModel(
|
|||
sealed class DateValueCommand {
|
||||
data class DispatchResult(val timeInSeconds: Double?, val dismiss: Boolean = false) : DateValueCommand()
|
||||
data class OpenDatePicker(val timeInSeconds: Long?) : DateValueCommand()
|
||||
data class OpenDateObject(val timeInMillis: TimeInMillis) : DateValueCommand()
|
||||
}
|
||||
|
||||
data class DateValueView(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue