diff --git a/app/src/main/java/com/anytypeio/anytype/ui/relations/RelationTextValueFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/relations/RelationTextValueFragment.kt index 00f2e094d3..dcdf8052a6 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/relations/RelationTextValueFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/relations/RelationTextValueFragment.kt @@ -14,6 +14,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_ui.features.relations.RelationTextValueAdapter import com.anytypeio.anytype.core_utils.ext.arg +import com.anytypeio.anytype.core_utils.ext.argOrNull import com.anytypeio.anytype.core_utils.ext.hideKeyboard import com.anytypeio.anytype.core_utils.ext.normalizeUrl import com.anytypeio.anytype.core_utils.ext.subscribe @@ -42,6 +43,8 @@ open class RelationTextValueFragment : private val objectId get() = arg(OBJECT_ID) private val flow get() = arg(FLOW_KEY) private val isLocked get() = arg(LOCKED_KEY) + private val value get() = argOrNull(KEY_VALUE) + private val name get() = arg(KEY_NAME) private val relationValueAdapter by lazy { RelationTextValueAdapter( @@ -78,11 +81,19 @@ open class RelationTextValueFragment : jobs += lifecycleScope.subscribe(vm.views) { relationValueAdapter.update(it) } jobs += lifecycleScope.subscribe(vm.title) { binding.tvRelationHeader.text = it } super.onStart() - vm.onStart( - relationId = relationId, - recordId = objectId, - isLocked = isLocked - ) + + if (flow == FLOW_CHANGE_DATE) { + vm.onDateStart( + name = name, + value = value + ) + } else { + vm.onStart( + relationId = relationId, + recordId = objectId, + isLocked = isLocked, + ) + } } override fun onStop() { @@ -177,7 +188,7 @@ open class RelationTextValueFragment : } override fun injectDependencies() { - if (flow == FLOW_DATAVIEW) { + if (flow == FLOW_DATAVIEW || flow == FLOW_CHANGE_DATE) { componentManager().relationTextValueDVComponent.get(ctx).inject(this) } else { componentManager().relationTextValueComponent.get(ctx).inject(this) @@ -185,7 +196,7 @@ open class RelationTextValueFragment : } override fun releaseDependencies() { - if (flow == FLOW_DATAVIEW) { + if (flow == FLOW_DATAVIEW || flow == FLOW_CHANGE_DATE) { componentManager().relationTextValueDVComponent.release(ctx) } else { componentManager().relationTextValueComponent.release(ctx) @@ -206,7 +217,7 @@ open class RelationTextValueFragment : relationId: Id, objectId: Id, flow: Int = FLOW_DEFAULT, - isLocked: Boolean = false + isLocked: Boolean = false, ) = RelationTextValueFragment().apply { arguments = bundleOf( CONTEXT_ID to ctx, @@ -217,14 +228,29 @@ open class RelationTextValueFragment : ) } + fun new( + ctx: Id, + name: String = "", + value: Long? = null + ) = new(ctx, "", "", FLOW_CHANGE_DATE) + .apply { + arguments?.apply { + putString(KEY_NAME, name) + value?.let { putLong(KEY_VALUE, it) } + } + } + const val CONTEXT_ID = "arg.edit-relation-value.context" const val RELATION_ID = "arg.edit-relation-value.relation.id" const val OBJECT_ID = "arg.edit-relation-value.object.id" const val FLOW_KEY = "arg.edit-relation-value.flow" const val LOCKED_KEY = "arg.edit-relation-value.locked" + const val KEY_VALUE = "arg.edit-relation-value.value" + const val KEY_NAME = "arg.edit-relation-value.name" const val FLOW_DEFAULT = 0 const val FLOW_DATAVIEW = 1 + const val FLOW_CHANGE_DATE = 2 } interface TextValueEditReceiver { diff --git a/app/src/main/java/com/anytypeio/anytype/ui/sets/ViewerFilterFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/sets/ViewerFilterFragment.kt index 44586dc20e..79d4e6275e 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/sets/ViewerFilterFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/sets/ViewerFilterFragment.kt @@ -49,12 +49,6 @@ open class ViewerFilterFragment : BaseBottomSheetFragment subscribe(binding.addButton.clicks()) { vm.onAddNewFilterClicked() } subscribe(binding.doneBtn.clicks()) { vm.onDoneButtonClicked() } subscribe(binding.editBtn.clicks()) { vm.onEditButtonClicked() } - } - } - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - with(lifecycleScope) { subscribe(vm.views) { filterAdapter.update(it) } subscribe(vm.screenState) { render(it) } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/sets/modals/filter/CreateFilterFromSelectedValueFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/sets/modals/filter/CreateFilterFromSelectedValueFragment.kt index e5c684a5ce..2359d37571 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/sets/modals/filter/CreateFilterFromSelectedValueFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/sets/modals/filter/CreateFilterFromSelectedValueFragment.kt @@ -22,6 +22,7 @@ import com.anytypeio.anytype.databinding.FragmentCreateOrUpdateFilterBinding import com.anytypeio.anytype.di.common.componentManager import com.anytypeio.anytype.presentation.sets.filter.FilterViewModel import com.anytypeio.anytype.presentation.sets.model.Viewer +import com.anytypeio.anytype.ui.relations.RelationTextValueFragment import com.anytypeio.anytype.ui.sets.modals.DatePickerFragment import com.anytypeio.anytype.ui.sets.modals.DatePickerFragment.DatePickerReceiver import com.anytypeio.anytype.ui.sets.modals.PickFilterConditionFragment @@ -34,11 +35,14 @@ import javax.inject.Inject open class CreateFilterFromSelectedValueFragment : BaseFragment(R.layout.fragment_create_or_update_filter), UpdateConditionActionReceiver, - DatePickerReceiver { + DatePickerReceiver, + RelationTextValueFragment.TextValueEditReceiver { private val ctx: String get() = arg(CTX_KEY) private val relation: String get() = arg(RELATION_KEY) + private val helper = FilterHelper() + private lateinit var searchRelationInput: EditText lateinit var clearSearchText: View @@ -114,6 +118,12 @@ open class CreateFilterFromSelectedValueFragment : } } + override fun onTextValueChanged(ctx: Id, text: String, objectId: Id, relationId: Id) {} + + override fun onNumberValueChanged(ctx: Id, number: Double?, objectId: Id, relationId: Id) { + helper.handleNumberValueChanged(this, number, vm) + } + override fun onStart() { super.onStart() vm.onStart(relationId = relation, filterIndex = FILTER_INDEX_EMPTY) @@ -147,6 +157,13 @@ open class CreateFilterFromSelectedValueFragment : FilterViewModel.Commands.TagDivider -> setDivider(R.drawable.divider_relation_tag) FilterViewModel.Commands.ShowInput -> {} FilterViewModel.Commands.HideInput -> {} + is FilterViewModel.Commands.OpenNumberPicker -> { + helper.handleOpenNumberPicker( + fragment = this, + command = commands, + ctx = ctx + ) + } } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/sets/modals/filter/FilterHelper.kt b/app/src/main/java/com/anytypeio/anytype/ui/sets/modals/filter/FilterHelper.kt new file mode 100644 index 0000000000..44cba98e6d --- /dev/null +++ b/app/src/main/java/com/anytypeio/anytype/ui/sets/modals/filter/FilterHelper.kt @@ -0,0 +1,41 @@ +package com.anytypeio.anytype.ui.sets.modals.filter + +import androidx.fragment.app.Fragment +import com.anytypeio.anytype.core_models.DVFilterQuickOption +import com.anytypeio.anytype.presentation.relations.toName +import com.anytypeio.anytype.presentation.sets.filter.FilterViewModel +import com.anytypeio.anytype.ui.relations.RelationTextValueFragment + +class FilterHelper { + fun handleOpenNumberPicker( + fragment: Fragment, + command: FilterViewModel.Commands.OpenNumberPicker, + ctx: String, + ) { + fragment.arguments?.apply { + putSerializable(KEY_OPTION, command.option) + } + + RelationTextValueFragment.new( + ctx = ctx, + name = command.option.toName(), + value = command.value + ).show(fragment.childFragmentManager, null) + } + + fun handleNumberValueChanged( + fragment: Fragment, + number: Double?, + vm: FilterViewModel + ) { + number?.let { + fragment.arguments + ?.let { it.getSerializable(KEY_OPTION) as? DVFilterQuickOption? } + ?.let { + vm.onExactNumberOfDays(it, number.toLong()) + } + } + } +} + +private const val KEY_OPTION = "arg.filter-helper.option" \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/sets/modals/filter/ModifyFilterFromSelectedValueFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/sets/modals/filter/ModifyFilterFromSelectedValueFragment.kt index a2bb2bbef1..fc037947cb 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/sets/modals/filter/ModifyFilterFromSelectedValueFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/sets/modals/filter/ModifyFilterFromSelectedValueFragment.kt @@ -23,6 +23,7 @@ import com.anytypeio.anytype.di.common.componentManager import com.anytypeio.anytype.presentation.sets.filter.FilterViewModel import com.anytypeio.anytype.presentation.sets.model.ColumnView import com.anytypeio.anytype.presentation.sets.model.Viewer +import com.anytypeio.anytype.ui.relations.RelationTextValueFragment import com.anytypeio.anytype.ui.sets.modals.DatePickerFragment import com.anytypeio.anytype.ui.sets.modals.DatePickerFragment.DatePickerReceiver import com.anytypeio.anytype.ui.sets.modals.PickFilterConditionFragment @@ -33,12 +34,15 @@ import javax.inject.Inject open class ModifyFilterFromSelectedValueFragment : BaseBottomSheetFragment(), - UpdateConditionActionReceiver, DatePickerReceiver { + UpdateConditionActionReceiver, DatePickerReceiver, + RelationTextValueFragment.TextValueEditReceiver { private val ctx: String get() = arg(CTX_KEY) private val relation: String get() = arg(RELATION_KEY) private val index: Int get() = arg(IDX_KEY) + private val helper = FilterHelper() + private lateinit var searchRelationInput: EditText lateinit var clearSearchText: View @@ -136,8 +140,13 @@ open class ModifyFilterFromSelectedValueFragment : FilterViewModel.Commands.DateDivider -> setDivider(R.drawable.divider_relation_date) FilterViewModel.Commands.ObjectDivider -> setDivider(R.drawable.divider_relation_object) FilterViewModel.Commands.TagDivider -> setDivider(R.drawable.divider_relation_tag) - FilterViewModel.Commands.ShowInput -> {} - FilterViewModel.Commands.HideInput -> {} + is FilterViewModel.Commands.OpenNumberPicker -> { + helper.handleOpenNumberPicker( + fragment = this, + command = commands, + ctx = ctx, + ) + } } } @@ -159,6 +168,12 @@ open class ModifyFilterFromSelectedValueFragment : vm.onExactDayPicked(timeInSeconds) } + override fun onTextValueChanged(ctx: Id, text: String, objectId: Id, relationId: Id) {} + + override fun onNumberValueChanged(ctx: Id, number: Double?, objectId: Id, relationId: Id) { + helper.handleNumberValueChanged(this, number, vm) + } + override fun onStart() { super.onStart() expand() diff --git a/core-models/src/main/java/com/anytypeio/anytype/core_models/Alias.kt b/core-models/src/main/java/com/anytypeio/anytype/core_models/Alias.kt index 455cc0fb3e..380e98b1b6 100644 --- a/core-models/src/main/java/com/anytypeio/anytype/core_models/Alias.kt +++ b/core-models/src/main/java/com/anytypeio/anytype/core_models/Alias.kt @@ -16,6 +16,7 @@ typealias DVViewerType = Block.Content.DataView.Viewer.Type typealias DVViewerCardSize= Block.Content.DataView.Viewer.Size typealias DVFilter = Block.Content.DataView.Filter typealias DVFilterCondition = Block.Content.DataView.Filter.Condition +typealias DVFilterQuickOption = Block.Content.DataView.Filter.QuickOption typealias DVFilterOperator = Block.Content.DataView.Filter.Operator typealias DVSort = Block.Content.DataView.Sort typealias DVSortType = Block.Content.DataView.Sort.Type diff --git a/core-models/src/main/java/com/anytypeio/anytype/core_models/Block.kt b/core-models/src/main/java/com/anytypeio/anytype/core_models/Block.kt index 2e06e2e5e1..b2ded6bfc5 100644 --- a/core-models/src/main/java/com/anytypeio/anytype/core_models/Block.kt +++ b/core-models/src/main/java/com/anytypeio/anytype/core_models/Block.kt @@ -329,6 +329,7 @@ data class Block( val relationKey: String, val operator: Operator = Operator.AND, val condition: Condition, + val quickOption: QuickOption = QuickOption.EXACT_DATE, val value: Any? ) { enum class Operator { AND, OR } @@ -337,6 +338,11 @@ data class Block( LIKE, NOT_LIKE, IN, NOT_IN, EMPTY, NOT_EMPTY, ALL_IN, NOT_ALL_IN, NONE, EXACT_IN, NOT_EXACT_IN } + + enum class QuickOption { + EXACT_DATE, YESTERDAY, TODAY, TOMORROW, LAST_WEEK, CURRENT_WEEK, NEXT_WEEK, + LAST_MONTH, CURRENT_MONTH, NEXT_MONTH, DAYS_AGO, DAYS_AHEAD, + } } } diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/dataview/holders/DVGridCellDateHolder.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/dataview/holders/DVGridCellDateHolder.kt index dd0901b4be..2245a93b34 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/dataview/holders/DVGridCellDateHolder.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/dataview/holders/DVGridCellDateHolder.kt @@ -10,8 +10,8 @@ import com.anytypeio.anytype.presentation.sets.model.CellView class DVGridCellDateHolder(view: View) : RecyclerView.ViewHolder(view) { fun bind(cell: CellView.Date) { - itemView.findViewById(R.id.tvText).text = cell.timeInMillis?.formatTimestamp( - isMillis = true, + itemView.findViewById(R.id.tvText).text = cell.timeInSecs?.formatTimestamp( + isMillis = false, format = cell.dateFormat ) } diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/dataview/modals/FilterDateViewHolder.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/dataview/modals/FilterDateViewHolder.kt index 106cd370df..c2a67ec80f 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/dataview/modals/FilterDateViewHolder.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/dataview/modals/FilterDateViewHolder.kt @@ -2,14 +2,17 @@ package com.anytypeio.anytype.core_ui.features.dataview.modals import android.widget.ImageView import android.widget.TextView +import com.anytypeio.anytype.core_models.DVFilterQuickOption import com.anytypeio.anytype.core_ui.databinding.ItemDvViewerFilterDateBinding import com.anytypeio.anytype.core_utils.ext.formatTimestamp import com.anytypeio.anytype.core_utils.ext.invisible import com.anytypeio.anytype.core_utils.ext.visible import com.anytypeio.anytype.presentation.extension.hasValue +import com.anytypeio.anytype.presentation.relations.toName import com.anytypeio.anytype.presentation.sets.model.FilterView -class FilterDateViewHolder(val binding: ItemDvViewerFilterDateBinding) : FilterViewHolder(binding.root) { +class FilterDateViewHolder(val binding: ItemDvViewerFilterDateBinding) : + FilterViewHolder(binding.root) { override val textTitle: TextView get() = binding.tvTitle override val textCondition: TextView get() = binding.tvCondition @@ -28,7 +31,13 @@ class FilterDateViewHolder(val binding: ItemDvViewerFilterDateBinding) : FilterV ) if (item.condition.hasValue()) { binding.tvValue.visible() - binding.tvValue.text = item.filterValue.value?.formatTimestamp(isMillis = true) + + binding.tvValue.text = when (item.quickOption) { + DVFilterQuickOption.DAYS_AGO -> "${item.filterValue.value?.toString()} days ago" + DVFilterQuickOption.DAYS_AHEAD -> "${item.filterValue.value?.toString()} days from now" + DVFilterQuickOption.EXACT_DATE -> item.filterValue.value?.formatTimestamp(isMillis = false) + else -> item.quickOption.toName() + } } else { binding.tvValue.text = null binding.tvValue.invisible() diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/sets/CreateFilterAdapter.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/sets/CreateFilterAdapter.kt index 422e3d4b61..3ab9ba4a12 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/sets/CreateFilterAdapter.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/sets/CreateFilterAdapter.kt @@ -4,6 +4,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView +import com.anytypeio.anytype.core_models.DVFilterQuickOption import com.anytypeio.anytype.core_ui.R import com.anytypeio.anytype.core_ui.databinding.ItemCreateFilterCheckboxBinding import com.anytypeio.anytype.core_ui.databinding.ItemCreateFilterDateBinding @@ -17,7 +18,6 @@ import com.anytypeio.anytype.core_utils.ext.invisible import com.anytypeio.anytype.core_utils.ext.setDrawableColor import com.anytypeio.anytype.core_utils.ext.visible import com.anytypeio.anytype.presentation.editor.editor.ThemeColor -import com.anytypeio.anytype.presentation.relations.DateDescription import com.anytypeio.anytype.presentation.sets.filter.CreateFilterView class CreateFilterAdapter( @@ -172,11 +172,18 @@ class CreateFilterAdapter( class Date(val binding: ItemCreateFilterDateBinding) : ViewHolder(binding.root) { fun bind(item: CreateFilterView.Date) = with(binding) { tvDateTitle.text = item.description - if (item.type == DateDescription.EXACT_DAY) { - tvDate.visible() - tvDate.text = item.timeInMillis.formatTimestamp(isMillis = true) - } else { - tvDate.invisible() + when (item.type) { + DVFilterQuickOption.EXACT_DATE -> { + tvDate.visible() + tvDate.text = item.value.formatTimestamp(isMillis = false) + } + DVFilterQuickOption.DAYS_AGO, DVFilterQuickOption.DAYS_AHEAD -> { + tvDate.visible() + tvDate.text = item.value.toString() + } + else -> { + tvDate.invisible() + } } if (item.isSelected) { iconChecked.visible() diff --git a/core-ui/src/main/res/layout/item_dv_viewer_filter_date.xml b/core-ui/src/main/res/layout/item_dv_viewer_filter_date.xml index e4e727a4ab..9f2fae3cb0 100644 --- a/core-ui/src/main/res/layout/item_dv_viewer_filter_date.xml +++ b/core-ui/src/main/res/layout/item_dv_viewer_filter_date.xml @@ -45,6 +45,7 @@ android:layout_marginStart="4dp" android:layout_marginEnd="12dp" app:layout_goneMarginEnd="@dimen/dp_20" + android:maxLines="2" style="@style/ViewerFilterTextValueStyle" app:layout_constraintBottom_toBottomOf="@+id/tvCondition" app:layout_constraintEnd_toStartOf="@+id/iconArrow" diff --git a/core-ui/src/test/java/com/anytypeio/anytype/core_ui/features/dv/CellViewDiffUtilTest.kt b/core-ui/src/test/java/com/anytypeio/anytype/core_ui/features/dv/CellViewDiffUtilTest.kt index 3184c55ff0..e48b0c6456 100644 --- a/core-ui/src/test/java/com/anytypeio/anytype/core_ui/features/dv/CellViewDiffUtilTest.kt +++ b/core-ui/src/test/java/com/anytypeio/anytype/core_ui/features/dv/CellViewDiffUtilTest.kt @@ -103,12 +103,12 @@ class CellViewDiffUtilTest { val oldCell = CellView.Date( id = MockDataFactory.randomString(), key = MockDataFactory.randomString(), - timeInMillis = MockDataFactory.randomLong(), + timeInSecs = MockDataFactory.randomLong(), dateFormat = MockDataFactory.randomString() ) val newCell = oldCell.copy( - timeInMillis = MockDataFactory.randomLong() + timeInSecs = MockDataFactory.randomLong() ) val old = listOf(oldCell) diff --git a/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/DateUtils.kt b/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/DateUtils.kt index 8bbbbf4c6a..f32c936c29 100644 --- a/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/DateUtils.kt +++ b/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/DateUtils.kt @@ -11,7 +11,7 @@ fun Calendar.isSameDay(compare: Calendar): Boolean = fun Calendar.timeInSeconds() = this.timeInMillis / 1000 -fun getTodayTimeUnit() = Calendar.getInstance() +fun getTodayTimeUnit(): Calendar = Calendar.getInstance() fun getTomorrowTimeUnit(): Calendar = Calendar.getInstance().apply { add(Calendar.DATE, 1) } fun getYesterdayTimeUnit(): Calendar = Calendar.getInstance().apply { add(Calendar.DATE, -1) } fun getWeekAheadTimeUnit(): Calendar = @@ -47,9 +47,9 @@ fun Long.formatTimestamp(isMillis: Boolean, format: String? = null): String { val isYesterday = filterTime.isSameDay(yesterday) if (isYesterday) return YESTERDAY val isWeekAgo = filterTime.isSameDay(weekAgo) - if (isWeekAgo) return WEEK_AGO + if (isWeekAgo) return LAST_WEEK val isWeekAhead = filterTime.isSameDay(weekForward) - if (isWeekAhead) return WEEK_AHEAD + if (isWeekAhead) return NEXT_WEEK val isMonthAgo = filterTime.isSameDay(monthAgo) if (isMonthAgo) return MONTH_AGO val isMonthAhead = filterTime.isSameDay(monthForward) @@ -77,10 +77,13 @@ const val NO_DATE = "No date" const val TODAY = "Today" const val TOMORROW = "Tomorrow" const val YESTERDAY = "Yesterday" -const val WEEK_AGO = "One week ago" -const val WEEK_AHEAD = "One week from now" +const val LAST_WEEK = "One week ago" +const val CURRENT_WEEK = "Current week" +const val NEXT_WEEK = "One week from now" const val MONTH_AGO = "One month ago" +const val CURRENT_MONTH = "Current month" const val MONTH_AHEAD = "One month from now" const val EXACT_DAY = "Exact day" +const val NUMBER_OF_DAYS_AGO = "Number of days ago" +const val NUMBER_OF_DAYS_FROM_NOW = "Number of days from now" -const val EMPTY_TIMESTAMP = 0L diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/Alias.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/Alias.kt index c305b8314d..2072056135 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/Alias.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/Alias.kt @@ -36,6 +36,7 @@ typealias MDVSort = anytype.model.Block.Content.Dataview.Sort typealias MDVSortType = anytype.model.Block.Content.Dataview.Sort.Type typealias MDVFilter = anytype.model.Block.Content.Dataview.Filter typealias MDVFilterCondition = anytype.model.Block.Content.Dataview.Filter.Condition +typealias MDVFilterQuickOption = anytype.model.Block.Content.Dataview.Filter.QuickOption typealias MDVFilterOperator = anytype.model.Block.Content.Dataview.Filter.Operator typealias MDVRelation = anytype.model.Block.Content.Dataview.Relation typealias MDVDateFormat = anytype.model.Block.Content.Dataview.Relation.DateFormat diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/ToCoreModelMappers.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/ToCoreModelMappers.kt index a47aa55add..9e9d4ebff5 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/ToCoreModelMappers.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/ToCoreModelMappers.kt @@ -451,10 +451,12 @@ fun MDVFilter.toCoreModels(): DVFilter = DVFilter( relationKey = RelationKey, operator = operator_.toCoreModels(), condition = condition.toCoreModels(), + quickOption = quickOption.toCoreModels(), value = value_ ) fun MDVFilterCondition.toCoreModels(): DVFilterCondition = when (this) { + MDVFilterCondition.None -> DVFilterCondition.NONE MDVFilterCondition.Equal -> DVFilterCondition.EQUAL MDVFilterCondition.NotEqual -> DVFilterCondition.NOT_EQUAL MDVFilterCondition.Greater -> DVFilterCondition.GREATER @@ -469,11 +471,25 @@ fun MDVFilterCondition.toCoreModels(): DVFilterCondition = when (this) { MDVFilterCondition.NotEmpty -> DVFilterCondition.NOT_EMPTY MDVFilterCondition.AllIn -> DVFilterCondition.ALL_IN MDVFilterCondition.NotAllIn -> DVFilterCondition.NOT_ALL_IN - MDVFilterCondition.None -> DVFilterCondition.NONE MDVFilterCondition.ExactIn -> DVFilterCondition.EXACT_IN MDVFilterCondition.NotExactIn -> DVFilterCondition.NOT_EXACT_IN } +fun MDVFilterQuickOption.toCoreModels(): DVFilterQuickOption = when (this) { + MDVFilterQuickOption.ExactDate -> DVFilterQuickOption.EXACT_DATE + MDVFilterQuickOption.Yesterday -> DVFilterQuickOption.YESTERDAY + MDVFilterQuickOption.Today -> DVFilterQuickOption.TODAY + MDVFilterQuickOption.Tomorrow -> DVFilterQuickOption.TOMORROW + MDVFilterQuickOption.LastWeek -> DVFilterQuickOption.LAST_WEEK + MDVFilterQuickOption.CurrentWeek -> DVFilterQuickOption.CURRENT_WEEK + MDVFilterQuickOption.NextWeek -> DVFilterQuickOption.NEXT_WEEK + MDVFilterQuickOption.LastMonth -> DVFilterQuickOption.LAST_MONTH + MDVFilterQuickOption.CurrentMonth -> DVFilterQuickOption.CURRENT_MONTH + MDVFilterQuickOption.NextMonth -> DVFilterQuickOption.NEXT_MONTH + MDVFilterQuickOption.NumberOfDaysAgo -> DVFilterQuickOption.DAYS_AGO + MDVFilterQuickOption.NumberOfDaysNow -> DVFilterQuickOption.DAYS_AHEAD +} + fun MDVFilterOperator.toCoreModels(): DVFilterOperator = when (this) { MDVFilterOperator.And -> DVFilterOperator.AND MDVFilterOperator.Or -> DVFilterOperator.OR diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/ToMiddlewareModelMappers.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/ToMiddlewareModelMappers.kt index 5454ab6bc8..b1a0fde722 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/ToMiddlewareModelMappers.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/ToMiddlewareModelMappers.kt @@ -339,6 +339,7 @@ fun Block.Content.DataView.Filter.toMiddlewareModel(): MDVFilter = RelationKey = relationKey, operator_ = operator.toMiddlewareModel(), condition = condition.toMiddlewareModel(), + quickOption = quickOption.toMiddlewareModel(), value_ = value ) @@ -347,6 +348,21 @@ fun Block.Content.DataView.Filter.Operator.toMiddlewareModel(): MDVFilterOperato Block.Content.DataView.Filter.Operator.OR -> MDVFilterOperator.Or } +fun Block.Content.DataView.Filter.QuickOption.toMiddlewareModel(): MDVFilterQuickOption = when (this) { + Block.Content.DataView.Filter.QuickOption.EXACT_DATE -> MDVFilterQuickOption.ExactDate + Block.Content.DataView.Filter.QuickOption.YESTERDAY -> MDVFilterQuickOption.Yesterday + Block.Content.DataView.Filter.QuickOption.TODAY -> MDVFilterQuickOption.Today + Block.Content.DataView.Filter.QuickOption.TOMORROW -> MDVFilterQuickOption.Tomorrow + Block.Content.DataView.Filter.QuickOption.LAST_WEEK -> MDVFilterQuickOption.LastWeek + Block.Content.DataView.Filter.QuickOption.CURRENT_WEEK -> MDVFilterQuickOption.CurrentWeek + Block.Content.DataView.Filter.QuickOption.NEXT_WEEK -> MDVFilterQuickOption.NextWeek + Block.Content.DataView.Filter.QuickOption.LAST_MONTH -> MDVFilterQuickOption.LastMonth + Block.Content.DataView.Filter.QuickOption.CURRENT_MONTH -> MDVFilterQuickOption.CurrentMonth + Block.Content.DataView.Filter.QuickOption.NEXT_MONTH -> MDVFilterQuickOption.NextMonth + Block.Content.DataView.Filter.QuickOption.DAYS_AGO -> MDVFilterQuickOption.NumberOfDaysAgo + Block.Content.DataView.Filter.QuickOption.DAYS_AHEAD -> MDVFilterQuickOption.NumberOfDaysNow +} + fun Block.Content.DataView.Filter.Condition.toMiddlewareModel(): MDVFilterCondition = when (this) { Block.Content.DataView.Filter.Condition.EQUAL -> MDVFilterCondition.Equal Block.Content.DataView.Filter.Condition.NOT_EQUAL -> MDVFilterCondition.NotEqual diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/FilterConditionExtension.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/FilterConditionExtension.kt index 2da2dae48b..774e6523f7 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/FilterConditionExtension.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/FilterConditionExtension.kt @@ -11,6 +11,7 @@ fun Viewer.Filter.Condition.index(): Int = this.getConditions().indexOf(this) fun Viewer.Filter.Condition.getConditions(): List = when (this) { is Viewer.Filter.Condition.Checkbox -> Viewer.Filter.Condition.Checkbox.checkboxConditions() is Viewer.Filter.Condition.Number -> Viewer.Filter.Condition.Number.numberConditions() + is Viewer.Filter.Condition.Date -> Viewer.Filter.Condition.Date.dateConditions() is Viewer.Filter.Condition.Selected -> Viewer.Filter.Condition.Selected.selectConditions() is Viewer.Filter.Condition.Text -> Viewer.Filter.Condition.Text.textConditions() } @@ -18,6 +19,7 @@ fun Viewer.Filter.Condition.getConditions(): List = whe fun Viewer.Filter.Condition.type(): Viewer.Filter.Type = when (this) { is Viewer.Filter.Condition.Checkbox -> Viewer.Filter.Type.CHECKBOX is Viewer.Filter.Condition.Number -> Viewer.Filter.Type.NUMBER + is Viewer.Filter.Condition.Date -> Viewer.Filter.Type.DATE is Viewer.Filter.Condition.Selected -> Viewer.Filter.Type.SELECTED is Viewer.Filter.Condition.Text -> Viewer.Filter.Type.TEXT } @@ -32,11 +34,14 @@ fun Relation.toConditionView(condition: DVFilterCondition?): Viewer.Filter.Condi condition?.toView(category = DVFilterConditionCategory.TEXT) ?: Viewer.Filter.Condition.Text.textConditions().first() } - Relation.Format.NUMBER, - Relation.Format.DATE -> { + Relation.Format.NUMBER -> { condition?.toView(category = DVFilterConditionCategory.NUMBER) ?: Viewer.Filter.Condition.Number.numberConditions().first() } + Relation.Format.DATE -> { + condition?.toView(category = DVFilterConditionCategory.DATE) + ?: Viewer.Filter.Condition.Date.dateConditions().first() + } Relation.Format.STATUS, Relation.Format.TAG, Relation.Format.OBJECT -> { @@ -57,6 +62,7 @@ private fun DVFilterCondition.toView( when (category) { DVFilterConditionCategory.TEXT -> Viewer.Filter.Condition.Text.Equal() DVFilterConditionCategory.NUMBER -> Viewer.Filter.Condition.Number.Equal() + DVFilterConditionCategory.DATE -> Viewer.Filter.Condition.Date.Equal() DVFilterConditionCategory.SELECT -> Viewer.Filter.Condition.Selected.Equal() DVFilterConditionCategory.CHECKBOX -> Viewer.Filter.Condition.Checkbox.Equal() } @@ -72,24 +78,28 @@ private fun DVFilterCondition.toView( DVFilterCondition.GREATER -> { when (category) { DVFilterConditionCategory.NUMBER -> Viewer.Filter.Condition.Number.Greater() + DVFilterConditionCategory.DATE -> Viewer.Filter.Condition.Date.Greater() else -> throw IllegalArgumentException("Condition ${this.name} is not present in $category") } } DVFilterCondition.LESS -> { when (category) { DVFilterConditionCategory.NUMBER -> Viewer.Filter.Condition.Number.Less() + DVFilterConditionCategory.DATE -> Viewer.Filter.Condition.Date.Less() else -> throw IllegalArgumentException("Condition ${this.name} is not present in $category") } } DVFilterCondition.GREATER_OR_EQUAL -> { when (category) { DVFilterConditionCategory.NUMBER -> Viewer.Filter.Condition.Number.GreaterOrEqual() + DVFilterConditionCategory.DATE -> Viewer.Filter.Condition.Date.GreaterOrEqual() else -> throw IllegalArgumentException("Condition ${this.name} is not present in $category") } } DVFilterCondition.LESS_OR_EQUAL -> { when (category) { DVFilterConditionCategory.NUMBER -> Viewer.Filter.Condition.Number.LessOrEqual() + DVFilterConditionCategory.DATE -> Viewer.Filter.Condition.Date.LessOrEqual() else -> throw IllegalArgumentException("Condition ${this.name} is not present in $category") } } @@ -108,6 +118,7 @@ private fun DVFilterCondition.toView( DVFilterCondition.IN -> { when (category) { DVFilterConditionCategory.SELECT -> Viewer.Filter.Condition.Selected.In() + DVFilterConditionCategory.DATE -> Viewer.Filter.Condition.Date.In() else -> throw IllegalArgumentException("Condition ${this.name} is not present in $category") } } @@ -121,6 +132,7 @@ private fun DVFilterCondition.toView( when (category) { DVFilterConditionCategory.TEXT -> Viewer.Filter.Condition.Text.Empty() DVFilterConditionCategory.SELECT -> Viewer.Filter.Condition.Selected.Empty() + DVFilterConditionCategory.DATE -> Viewer.Filter.Condition.Date.Empty() DVFilterConditionCategory.NUMBER -> Viewer.Filter.Condition.Number.Empty() else -> throw IllegalArgumentException("Condition ${this.name} is not present in $category") } @@ -130,6 +142,7 @@ private fun DVFilterCondition.toView( DVFilterConditionCategory.TEXT -> Viewer.Filter.Condition.Text.NotEmpty() DVFilterConditionCategory.SELECT -> Viewer.Filter.Condition.Selected.NotEmpty() DVFilterConditionCategory.NUMBER -> Viewer.Filter.Condition.Number.NotEmpty() + DVFilterConditionCategory.DATE -> Viewer.Filter.Condition.Date.NotEmpty() else -> throw IllegalArgumentException("Condition ${this.name} is not present in $category") } } @@ -146,6 +159,7 @@ private fun DVFilterCondition.toView( when (category) { DVFilterConditionCategory.TEXT -> Viewer.Filter.Condition.Text.None() DVFilterConditionCategory.NUMBER -> Viewer.Filter.Condition.Number.None() + DVFilterConditionCategory.DATE -> Viewer.Filter.Condition.Date.None() DVFilterConditionCategory.SELECT -> Viewer.Filter.Condition.Selected.None() DVFilterConditionCategory.CHECKBOX -> Viewer.Filter.Condition.Checkbox.None() } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/FilterExtension.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/FilterExtension.kt index 4e8025162b..f665983cfc 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/FilterExtension.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/FilterExtension.kt @@ -1,6 +1,10 @@ package com.anytypeio.anytype.presentation.extension -import com.anytypeio.anytype.core_models.* +import com.anytypeio.anytype.core_models.Block +import com.anytypeio.anytype.core_models.DVFilter +import com.anytypeio.anytype.core_models.DVFilterCondition +import com.anytypeio.anytype.core_models.Id +import com.anytypeio.anytype.core_models.Relation import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.presentation.mapper.toDomain import com.anytypeio.anytype.presentation.relations.toView @@ -18,6 +22,9 @@ fun Viewer.Filter.Condition.hasValue(): Boolean = when (this) { is Viewer.Filter.Condition.Number.None, is Viewer.Filter.Condition.Number.Empty, is Viewer.Filter.Condition.Number.NotEmpty, + is Viewer.Filter.Condition.Date.None, + is Viewer.Filter.Condition.Date.Empty, + is Viewer.Filter.Condition.Date.NotEmpty, is Viewer.Filter.Condition.Selected.None, is Viewer.Filter.Condition.Text.None -> false else -> true diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt index c0989a48f3..7a50b321d3 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt @@ -533,6 +533,20 @@ fun DVFilterCondition.toTextView(): Viewer.Filter.Condition.Text = when (this) { else -> throw IllegalStateException("Unexpected filter condition $this for Text relations") } + +fun DVFilterCondition.toDateView(): Viewer.Filter.Condition.Date = when (this) { + DVFilterCondition.EQUAL -> Viewer.Filter.Condition.Date.Equal() + DVFilterCondition.GREATER -> Viewer.Filter.Condition.Date.Greater() + DVFilterCondition.LESS -> Viewer.Filter.Condition.Date.Less() + DVFilterCondition.GREATER_OR_EQUAL -> Viewer.Filter.Condition.Date.GreaterOrEqual() + DVFilterCondition.LESS_OR_EQUAL -> Viewer.Filter.Condition.Date.LessOrEqual() + DVFilterCondition.IN -> Viewer.Filter.Condition.Date.In() + DVFilterCondition.EMPTY -> Viewer.Filter.Condition.Date.Empty() + DVFilterCondition.NOT_EMPTY -> Viewer.Filter.Condition.Date.NotEmpty() + DVFilterCondition.NONE -> Viewer.Filter.Condition.Date.None() + else -> throw IllegalStateException("Unexpected filter condition $this for Number or Date relations") +} + fun DVFilterCondition.toNumberView(): Viewer.Filter.Condition.Number = when (this) { DVFilterCondition.EQUAL -> Viewer.Filter.Condition.Number.Equal() DVFilterCondition.NOT_EQUAL -> Viewer.Filter.Condition.Number.NotEqual() @@ -600,6 +614,14 @@ fun Viewer.FilterOperator.toDomain(): DVFilterOperator = when (this) { fun Viewer.Filter.Condition.toDomain(): DVFilterCondition = when (this) { is Viewer.Filter.Condition.Checkbox.Equal -> DVFilterCondition.EQUAL is Viewer.Filter.Condition.Checkbox.NotEqual -> DVFilterCondition.NOT_EQUAL + is Viewer.Filter.Condition.Date.Equal -> DVFilterCondition.EQUAL + is Viewer.Filter.Condition.Date.Greater -> DVFilterCondition.GREATER + is Viewer.Filter.Condition.Date.GreaterOrEqual -> DVFilterCondition.GREATER_OR_EQUAL + is Viewer.Filter.Condition.Date.Less -> DVFilterCondition.LESS + is Viewer.Filter.Condition.Date.LessOrEqual -> DVFilterCondition.LESS_OR_EQUAL + is Viewer.Filter.Condition.Date.In -> DVFilterCondition.IN + is Viewer.Filter.Condition.Date.Empty -> DVFilterCondition.EMPTY + is Viewer.Filter.Condition.Date.NotEmpty -> DVFilterCondition.NOT_EMPTY is Viewer.Filter.Condition.Number.Equal -> DVFilterCondition.EQUAL is Viewer.Filter.Condition.Number.Greater -> DVFilterCondition.GREATER is Viewer.Filter.Condition.Number.GreaterOrEqual -> DVFilterCondition.GREATER_OR_EQUAL @@ -621,6 +643,7 @@ fun Viewer.Filter.Condition.toDomain(): DVFilterCondition = when (this) { is Viewer.Filter.Condition.Text.NotEqual -> DVFilterCondition.NOT_EQUAL is Viewer.Filter.Condition.Text.NotLike -> DVFilterCondition.NOT_LIKE is Viewer.Filter.Condition.Checkbox.None -> DVFilterCondition.NONE + is Viewer.Filter.Condition.Date.None -> DVFilterCondition.NONE is Viewer.Filter.Condition.Number.None -> DVFilterCondition.NONE is Viewer.Filter.Condition.Selected.None -> DVFilterCondition.NONE is Viewer.Filter.Condition.Text.None -> DVFilterCondition.NONE diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/ObjectSetRenderMapper.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/ObjectSetRenderMapper.kt index 1cba8509c8..cd07bc0a7e 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/ObjectSetRenderMapper.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/ObjectSetRenderMapper.kt @@ -4,6 +4,8 @@ import com.anytypeio.anytype.core_models.Block import com.anytypeio.anytype.core_models.CoverType import com.anytypeio.anytype.core_models.DV import com.anytypeio.anytype.core_models.DVFilter +import com.anytypeio.anytype.core_models.DVFilterCondition +import com.anytypeio.anytype.core_models.DVFilterQuickOption import com.anytypeio.anytype.core_models.DVViewer import com.anytypeio.anytype.core_models.DVViewerCardSize import com.anytypeio.anytype.core_models.DVViewerType @@ -14,28 +16,24 @@ import com.anytypeio.anytype.core_models.Relation import com.anytypeio.anytype.core_models.Url import com.anytypeio.anytype.core_models.ext.content import com.anytypeio.anytype.core_models.ext.title -import com.anytypeio.anytype.core_utils.ext.EMPTY_TIMESTAMP +import com.anytypeio.anytype.core_utils.ext.CURRENT_MONTH +import com.anytypeio.anytype.core_utils.ext.CURRENT_WEEK import com.anytypeio.anytype.core_utils.ext.EXACT_DAY +import com.anytypeio.anytype.core_utils.ext.LAST_WEEK import com.anytypeio.anytype.core_utils.ext.MONTH_AGO import com.anytypeio.anytype.core_utils.ext.MONTH_AHEAD +import com.anytypeio.anytype.core_utils.ext.NEXT_WEEK +import com.anytypeio.anytype.core_utils.ext.NUMBER_OF_DAYS_AGO +import com.anytypeio.anytype.core_utils.ext.NUMBER_OF_DAYS_FROM_NOW import com.anytypeio.anytype.core_utils.ext.TODAY import com.anytypeio.anytype.core_utils.ext.TOMORROW -import com.anytypeio.anytype.core_utils.ext.WEEK_AGO -import com.anytypeio.anytype.core_utils.ext.WEEK_AHEAD import com.anytypeio.anytype.core_utils.ext.YESTERDAY -import com.anytypeio.anytype.core_utils.ext.getMonthAgoTimeUnit -import com.anytypeio.anytype.core_utils.ext.getMonthAheadTimeUnit -import com.anytypeio.anytype.core_utils.ext.getTodayTimeUnit -import com.anytypeio.anytype.core_utils.ext.getTomorrowTimeUnit -import com.anytypeio.anytype.core_utils.ext.getWeekAgoTimeUnit -import com.anytypeio.anytype.core_utils.ext.getWeekAheadTimeUnit -import com.anytypeio.anytype.core_utils.ext.getYesterdayTimeUnit -import com.anytypeio.anytype.core_utils.ext.isSameDay import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.presentation.editor.cover.CoverColor import com.anytypeio.anytype.presentation.editor.editor.model.BlockView import com.anytypeio.anytype.presentation.extension.isValueRequired import com.anytypeio.anytype.presentation.mapper.toCheckboxView +import com.anytypeio.anytype.presentation.mapper.toDateView import com.anytypeio.anytype.presentation.mapper.toGridRecordRows import com.anytypeio.anytype.presentation.mapper.toNumberView import com.anytypeio.anytype.presentation.mapper.toSelectedView @@ -62,7 +60,6 @@ import com.anytypeio.anytype.presentation.sets.model.TagView import com.anytypeio.anytype.presentation.sets.model.Viewer import com.anytypeio.anytype.presentation.sets.model.ViewerTabView import timber.log.Timber -import java.util.* fun ObjectSet.tabs(activeViewerId: String? = null): List { @@ -160,7 +157,8 @@ fun ObjectSet.render( Viewer.ListView( id = viewer.id, items = viewer.buildListViews( - objects = (viewerDb[viewer.id]?.records ?: emptyList()).map { ObjectWrapper.Basic(it) }, + objects = (viewerDb[viewer.id]?.records + ?: emptyList()).map { ObjectWrapper.Basic(it) }, details = details, relations = relations, urlBuilder = builder @@ -301,94 +299,105 @@ fun Relation.toCreateFilterStatusView(ids: List<*>? = null): List { - val filterTime = Calendar.getInstance() - if (exactDayTimestamp != EMPTY_TIMESTAMP) { - filterTime.timeInMillis = exactDayTimestamp * 1000 - } - val today = getTodayTimeUnit() - val tomorrow = getTomorrowTimeUnit() - val yesterday = getYesterdayTimeUnit() - val weekAgo = getWeekAgoTimeUnit() - val weekForward = getWeekAheadTimeUnit() - val monthAgo = getMonthAgoTimeUnit() - val monthForward = getMonthAheadTimeUnit() - - val isToday = filterTime.isSameDay(today) - val isTomorrow = filterTime.isSameDay(tomorrow) - val isYesterday = filterTime.isSameDay(yesterday) - val isWeekAgo = filterTime.isSameDay(weekAgo) - val isWeekAhead = filterTime.isSameDay(weekForward) - val isMonthAgo = filterTime.isSameDay(monthAgo) - val isMonthAhead = filterTime.isSameDay(monthForward) - val isExactDay = !isToday && !isTomorrow && !isYesterday && !isWeekAgo && !isWeekAhead - && !isMonthAgo && !isMonthAhead - - return listOf( +fun Relation.toCreateFilterDateView( + quickOption: DVFilterQuickOption?, + condition: DVFilterCondition, + value: Long +) = quickOptionOrderMap.getOrDefault(condition, quickOptionDefaultOrder) + .map { + val isSelected = quickOption.isSelected(it, value) CreateFilterView.Date( id = key, - description = TODAY, - type = DateDescription.TODAY, - timeInMillis = today.timeInMillis, - isSelected = isToday - ), - CreateFilterView.Date( - id = key, - description = TOMORROW, - type = DateDescription.TOMORROW, - timeInMillis = tomorrow.timeInMillis, - isSelected = isTomorrow - ), - CreateFilterView.Date( - id = key, - description = YESTERDAY, - type = DateDescription.YESTERDAY, - timeInMillis = yesterday.timeInMillis, - isSelected = isYesterday - ), - CreateFilterView.Date( - id = key, - description = WEEK_AGO, - type = DateDescription.ONE_WEEK_AGO, - timeInMillis = weekAgo.timeInMillis, - isSelected = isWeekAgo - ), - CreateFilterView.Date( - id = key, - description = WEEK_AHEAD, - type = DateDescription.ONE_WEEK_FORWARD, - timeInMillis = weekForward.timeInMillis, - isSelected = isWeekAhead - ), - CreateFilterView.Date( - id = key, - description = MONTH_AGO, - type = DateDescription.ONE_MONTH_AGO, - timeInMillis = monthAgo.timeInMillis, - isSelected = isMonthAgo - ), - CreateFilterView.Date( - id = key, - description = MONTH_AHEAD, - type = DateDescription.ONE_MONTH_FORWARD, - timeInMillis = monthForward.timeInMillis, - isSelected = isMonthAhead - ), - CreateFilterView.Date( - id = key, - description = EXACT_DAY, - type = DateDescription.EXACT_DAY, - timeInMillis = filterTime.timeInMillis, - isSelected = isExactDay + description = it.toName(), + type = it, + condition = condition, + value = if (isSelected) value else CreateFilterView.Date.NO_VALUE, + isSelected = isSelected ) + } + +private fun DVFilterQuickOption?.isSelected( + quickOption: DVFilterQuickOption, + value: Long +) = if (this == quickOption) { + if (quickOption == DVFilterQuickOption.EXACT_DATE) { + value > 0 + } else { + true + } +} else { + false +} + + +private val quickOptionDefaultOrder by lazy { + listOf( + DVFilterQuickOption.TODAY, + DVFilterQuickOption.TOMORROW, + DVFilterQuickOption.YESTERDAY, + DVFilterQuickOption.CURRENT_WEEK, + DVFilterQuickOption.LAST_WEEK, + DVFilterQuickOption.NEXT_WEEK, + DVFilterQuickOption.CURRENT_MONTH, + DVFilterQuickOption.LAST_MONTH, + DVFilterQuickOption.NEXT_MONTH, + DVFilterQuickOption.DAYS_AGO, + DVFilterQuickOption.DAYS_AHEAD, + DVFilterQuickOption.EXACT_DATE, ) } -enum class DateDescription { - TODAY, TOMORROW, YESTERDAY, ONE_WEEK_AGO, - ONE_WEEK_FORWARD, ONE_MONTH_AGO, ONE_MONTH_FORWARD, EXACT_DAY +private val quickOptionOrderMap: Map> by lazy { + buildMap { + put( + DVFilterCondition.EQUAL, listOf( + DVFilterQuickOption.TODAY, + DVFilterQuickOption.TOMORROW, + DVFilterQuickOption.YESTERDAY, + DVFilterQuickOption.DAYS_AGO, + DVFilterQuickOption.DAYS_AHEAD, + DVFilterQuickOption.EXACT_DATE, + ) + ) + + put( + DVFilterCondition.IN, listOf( + DVFilterQuickOption.TODAY, + DVFilterQuickOption.TOMORROW, + DVFilterQuickOption.YESTERDAY, + DVFilterQuickOption.LAST_WEEK, + DVFilterQuickOption.CURRENT_WEEK, + DVFilterQuickOption.NEXT_WEEK, + DVFilterQuickOption.LAST_MONTH, + DVFilterQuickOption.CURRENT_MONTH, + DVFilterQuickOption.NEXT_MONTH, + ) + ) + + put(DVFilterCondition.EMPTY, emptyList()) + put(DVFilterCondition.NOT_EMPTY, emptyList()) + } } +private val quickOptionToNameMapping: Map by lazy { + buildMap { + put(DVFilterQuickOption.EXACT_DATE, EXACT_DAY) + put(DVFilterQuickOption.YESTERDAY, YESTERDAY) + put(DVFilterQuickOption.TODAY, TODAY) + put(DVFilterQuickOption.TOMORROW, TOMORROW) + put(DVFilterQuickOption.LAST_WEEK, LAST_WEEK) + put(DVFilterQuickOption.CURRENT_WEEK, CURRENT_WEEK) + put(DVFilterQuickOption.NEXT_WEEK, NEXT_WEEK) + put(DVFilterQuickOption.LAST_MONTH, MONTH_AGO) + put(DVFilterQuickOption.CURRENT_MONTH, CURRENT_MONTH) + put(DVFilterQuickOption.NEXT_MONTH, MONTH_AHEAD) + put(DVFilterQuickOption.DAYS_AGO, NUMBER_OF_DAYS_AGO) + put(DVFilterQuickOption.DAYS_AHEAD, NUMBER_OF_DAYS_FROM_NOW) + } +} + +fun DVFilterQuickOption.toName() = quickOptionToNameMapping.getOrDefault(this, "Error") + fun ObjectSet.columns(viewerId: Id): ArrayList { val block = blocks.first { it.content is DV } @@ -617,7 +626,8 @@ fun DVFilter.toView( key = relationKey, title = relation.name, operator = operator.toView(), - condition = condition.toNumberView(), + condition = condition.toDateView(), + quickOption = quickOption, filterValue = FilterValue.Date(DateParser.parse(value)), format = relation.format.toView(), isValueRequired = condition.isValueRequired(), diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationExtensions.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationExtensions.kt index 5643ec07fd..817b74b1b9 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationExtensions.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationExtensions.kt @@ -12,6 +12,7 @@ import com.anytypeio.anytype.presentation.sets.model.Viewer import java.sql.Date import java.text.SimpleDateFormat import java.util.* +import java.util.concurrent.TimeUnit fun List.views( details: Block.Details, @@ -67,9 +68,10 @@ fun Relation.view( // see {SetsExtension:buildGridRow()} val format = SimpleDateFormat(DateConst.DEFAULT_DATE_FORMAT, Locale.getDefault()) val value = values[relation.key] - val timeInMillis = DateParser.parse(value) - val formattedDate = if (timeInMillis != null) { - format.format(Date(timeInMillis)) + + val timeInSec = DateParser.parse(value) + val formattedDate = if (timeInSec != null) { + format.format(Date(TimeUnit.SECONDS.toMillis(timeInSec))) } else { null } @@ -187,13 +189,13 @@ object FilterInputValueParser { */ object DateParser { fun parse(value: Any?): Long? { - val timeInMillis: Long? = when (value) { + val result: Long? = when (value) { is String -> value.toLongOrNull() is Double -> value.toLong() is Long -> value else -> null } - return timeInMillis?.times(1000) + return result } } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/RelationTextValueViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/RelationTextValueViewModel.kt index 19e0632ab3..3b9b3b6334 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/RelationTextValueViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/RelationTextValueViewModel.kt @@ -26,6 +26,18 @@ class RelationTextValueViewModel( private val jobs = mutableListOf() + fun onDateStart( + name: String, + value: Long?, + ) { + title.value = name + views.value = listOf( + RelationTextValueView.Number( + value = NumberParser.parse(value) + ) + ) + } + fun onStart( relationId: Id, recordId: String, @@ -36,48 +48,43 @@ class RelationTextValueViewModel( relations.observe(relationId), values.subscribe(recordId) ) { relation, values -> - title.value = relation.name + val value = values[relationId]?.toString() val isValueReadOnly = values[Relations.IS_READ_ONLY] as? Boolean ?: false val isValueEditable = !(isValueReadOnly || isLocked) + title.value = relation.name views.value = listOf( when (relation.format) { Relation.Format.SHORT_TEXT -> { - val value = values[relationId] as? String RelationTextValueView.TextShort( value = value, isEditable = isValueEditable ) } Relation.Format.LONG_TEXT -> { - val value = values[relationId] as? String RelationTextValueView.Text( value = value, isEditable = isValueEditable ) } Relation.Format.NUMBER -> { - val value = NumberParser.parse(values[relationId]) RelationTextValueView.Number( - value = value, + value = NumberParser.parse(value), isEditable = isValueEditable ) } Relation.Format.URL -> { - val value = values[relationId] as? String RelationTextValueView.Url( value = value, isEditable = isValueEditable ) } Relation.Format.EMAIL -> { - val value = values[relationId] as? String RelationTextValueView.Email( value = value, isEditable = isValueEditable ) } Relation.Format.PHONE -> { - val value = values[relationId] as? String RelationTextValueView.Phone( value = value, isEditable = isValueEditable diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/SetsExtension.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/SetsExtension.kt index f64d756df4..d235c7a39c 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/SetsExtension.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/SetsExtension.kt @@ -75,7 +75,7 @@ fun List.buildGridRow( CellView.Date( id = record[ObjectSetConfig.ID_KEY] as String, key = column.key, - timeInMillis = DateParser.parse(value), + timeInSecs = DateParser.parse(value), dateFormat = column.getDateRelationFormat() ) } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/CreateFilterView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/CreateFilterView.kt index 89c7a72bfa..80bd5c798e 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/CreateFilterView.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/CreateFilterView.kt @@ -1,8 +1,9 @@ package com.anytypeio.anytype.presentation.sets.filter +import com.anytypeio.anytype.core_models.DVFilterCondition +import com.anytypeio.anytype.core_models.DVFilterQuickOption import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.presentation.objects.ObjectIcon -import com.anytypeio.anytype.presentation.relations.DateDescription sealed class CreateFilterView { @@ -32,12 +33,17 @@ sealed class CreateFilterView { data class Date( val id: Id, val description: String, - val type: DateDescription, - val timeInMillis: Long, + val type: DVFilterQuickOption, + val condition: DVFilterCondition, + val value: Long, override val isSelected: Boolean ) : CreateFilterView() { override val text: String get() = description + + companion object { + const val NO_VALUE = 0L + } } data class Object( diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/DVFilterConditionCategory.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/DVFilterConditionCategory.kt index 55e4e0239e..ab9786ed67 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/DVFilterConditionCategory.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/DVFilterConditionCategory.kt @@ -1,3 +1,3 @@ package com.anytypeio.anytype.presentation.sets.filter -enum class DVFilterConditionCategory { TEXT, NUMBER, SELECT, CHECKBOX } \ No newline at end of file +enum class DVFilterConditionCategory { TEXT, NUMBER, DATE, SELECT, CHECKBOX } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/FilterViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/FilterViewModel.kt index 6c1abe2640..cc5ba42fe9 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/FilterViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/FilterViewModel.kt @@ -4,18 +4,35 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope import com.anytypeio.anytype.analytics.base.Analytics -import com.anytypeio.anytype.core_models.* -import com.anytypeio.anytype.core_utils.ext.EMPTY_TIMESTAMP +import com.anytypeio.anytype.core_models.DV +import com.anytypeio.anytype.core_models.DVFilter +import com.anytypeio.anytype.core_models.DVFilterQuickOption +import com.anytypeio.anytype.core_models.DVViewer +import com.anytypeio.anytype.core_models.Id +import com.anytypeio.anytype.core_models.ObjectType +import com.anytypeio.anytype.core_models.Payload +import com.anytypeio.anytype.core_models.Relation import com.anytypeio.anytype.core_utils.ext.cancel -import com.anytypeio.anytype.core_utils.ext.toTimeSeconds import com.anytypeio.anytype.domain.`object`.ObjectTypesProvider import com.anytypeio.anytype.domain.dataview.interactor.SearchObjects import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer import com.anytypeio.anytype.domain.misc.UrlBuilder -import com.anytypeio.anytype.presentation.extension.* +import com.anytypeio.anytype.presentation.extension.checkboxFilter +import com.anytypeio.anytype.presentation.extension.hasValue +import com.anytypeio.anytype.presentation.extension.index +import com.anytypeio.anytype.presentation.extension.sendAnalyticsAddFilterEvent +import com.anytypeio.anytype.presentation.extension.sendAnalyticsChangeFilterValueEvent +import com.anytypeio.anytype.presentation.extension.toConditionView +import com.anytypeio.anytype.presentation.extension.type import com.anytypeio.anytype.presentation.mapper.toDomain import com.anytypeio.anytype.presentation.objects.toCreateFilterObjectView -import com.anytypeio.anytype.presentation.relations.* +import com.anytypeio.anytype.presentation.relations.FilterInputValueParser +import com.anytypeio.anytype.presentation.relations.toCreateFilterCheckboxView +import com.anytypeio.anytype.presentation.relations.toCreateFilterDateView +import com.anytypeio.anytype.presentation.relations.toCreateFilterStatusView +import com.anytypeio.anytype.presentation.relations.toCreateFilterTagView +import com.anytypeio.anytype.presentation.relations.toFilterValue +import com.anytypeio.anytype.presentation.relations.toViewRelation import com.anytypeio.anytype.presentation.search.ObjectSearchConstants import com.anytypeio.anytype.presentation.sets.ObjectSet import com.anytypeio.anytype.presentation.sets.ObjectSetSession @@ -25,7 +42,10 @@ import com.anytypeio.anytype.presentation.sets.model.SimpleRelationView import com.anytypeio.anytype.presentation.sets.model.Viewer import com.anytypeio.anytype.presentation.util.Dispatcher import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import timber.log.Timber @@ -112,7 +132,7 @@ open class FilterViewModel( } private fun updateUi(format: Relation.Format, condition: Viewer.Filter.Condition) { - when(format) { + when (format) { Relation.Format.SHORT_TEXT, Relation.Format.LONG_TEXT, Relation.Format.URL, @@ -200,7 +220,8 @@ open class FilterViewModel( proceedWithFilterValueList( relation = relation, filter = null, - objectTypes = objectTypesProvider.get() + objectTypes = objectTypesProvider.get(), + condition = condition ) } else { val filter = viewer.filters[index] @@ -213,7 +234,8 @@ open class FilterViewModel( proceedWithFilterValueList( relation = relation, filter = filter, - objectTypes = objectTypesProvider.get() + objectTypes = objectTypesProvider.get(), + condition = condition ) } } @@ -221,11 +243,16 @@ open class FilterViewModel( private fun proceedWithFilterValueList( relation: Relation, filter: DVFilter?, - objectTypes: List + objectTypes: List, + condition: Viewer.Filter.Condition ) = when (relation.format) { Relation.Format.DATE -> { - val timestamp = (filter?.value as? Double)?.toLong() ?: EMPTY_TIMESTAMP - filterValueListState.value = relation.toCreateFilterDateView(timestamp) + val value = (filter?.value as? Double)?.toLong() ?: 0L + filterValueListState.value = relation.toCreateFilterDateView( + quickOption = filter?.quickOption, + condition = condition.toDomain(), + value = value + ) } Relation.Format.TAG -> { val ids = filter?.value as? List<*> @@ -382,11 +409,15 @@ open class FilterViewModel( } fun onExactDayPicked(timeInSeconds: Long) { + setFilterState(DVFilterQuickOption.EXACT_DATE, timeInSeconds) + } + + private fun setFilterState(quickOption: DVFilterQuickOption, value: Long) { filterValueListState.value = filterValueListState.value.map { view -> if (view is CreateFilterView.Date) { - if (view.type == DateDescription.EXACT_DAY) { + if (view.type == quickOption) { view.copy( - timeInMillis = timeInSeconds * 1000, + value = value, isSelected = true ) } else { @@ -398,6 +429,10 @@ open class FilterViewModel( } } + fun onExactNumberOfDays(quickOption: DVFilterQuickOption, numberOfDays: Long) { + setFilterState(quickOption, numberOfDays) + } + fun onCreateFilterFromSelectedValueClicked(ctx: Id, relation: Id) { val condition = conditionState.value?.condition checkNotNull(condition) @@ -439,7 +474,7 @@ open class FilterViewModel( ctx = ctx, filter = DVFilter( relationKey = relation, - value = selected?.timeInMillis?.toTimeSeconds(), + value = selected?.value?.toDouble(), condition = condition.toDomain() ) ) @@ -574,11 +609,9 @@ open class FilterViewModel( ) } ColumnView.Format.DATE -> { - val value = filterValueListState.value + val date = filterValueListState.value .filterIsInstance() - .filter { it.isSelected } - .map { date -> date.timeInMillis.toTimeSeconds() } - .firstOrNull() + .firstOrNull { it.isSelected } proceedWithUpdatingFilter( ctx = ctx, target = block.id, @@ -587,7 +620,8 @@ open class FilterViewModel( updatedFilter = DVFilter( relationKey = relation, condition = condition.toDomain(), - value = value + quickOption = date?.type ?: DVFilterQuickOption.EXACT_DATE, + value = date?.value?.toDouble() ) ) sendAnalyticsChangeFilterValueEvent( @@ -694,15 +728,30 @@ open class FilterViewModel( } private fun onFilterDateItemClicked(dateItem: CreateFilterView.Date) { - if (dateItem.type == DateDescription.EXACT_DAY) { - viewModelScope.launch { proceedWithDatePickerScreen(dateItem.timeInMillis) } - } else { - filterValueListState.value = updateSelectedState(dateItem) + when (dateItem.type) { + DVFilterQuickOption.EXACT_DATE -> { + viewModelScope.launch { proceedWithDatePickerScreen(dateItem.value) } + } + DVFilterQuickOption.DAYS_AGO, DVFilterQuickOption.DAYS_AHEAD -> { + viewModelScope.launch { + proceedWithNumberPickerScreen( + dateItem.type, + if (dateItem.isSelected) dateItem.value else null + ) + } + } + else -> { + filterValueListState.value = updateSelectedState(dateItem) + } } } - private suspend fun proceedWithDatePickerScreen(timeInMillis: Long) { - commands.emit(Commands.OpenDatePicker(timeInSeconds = timeInMillis / 1000)) + private suspend fun proceedWithDatePickerScreen(timeInSeconds: Long) { + commands.emit(Commands.OpenDatePicker(timeInSeconds)) + } + + private suspend fun proceedWithNumberPickerScreen(option: DVFilterQuickOption, value: Long?) { + commands.emit(Commands.OpenNumberPicker(option, value)) } private suspend fun proceedWithConditionPickerScreen(type: Viewer.Filter.Type, index: Int) { @@ -713,16 +762,13 @@ open class FilterViewModel( selectedItem: CreateFilterView.Date ): List = filterValueListState.value.map { view -> if (view is CreateFilterView.Date) { - if (view.type == DateDescription.EXACT_DAY) { - view.copy( - isSelected = false, - timeInMillis = EMPTY_TIMESTAMP - ) + if (view.type == DVFilterQuickOption.EXACT_DATE) { + view.copy(isSelected = false, value = CreateFilterView.Date.NO_VALUE) } else { if (view.type == selectedItem.type) { view.copy(isSelected = true) } else { - view.copy(isSelected = false) + view.copy(isSelected = false, value = CreateFilterView.Date.NO_VALUE) } } } else { @@ -756,16 +802,17 @@ open class FilterViewModel( } sealed class Commands { - object ShowInput: Commands() - object HideInput: Commands() - object ShowSearchbar: Commands() - object HideSearchbar: Commands() - object ShowCount: Commands() - object HideCount: Commands() + object ShowInput : Commands() + object HideInput : Commands() + object ShowSearchbar : Commands() + object HideSearchbar : Commands() + object ShowCount : Commands() + object HideCount : Commands() data class OpenDatePicker(val timeInSeconds: Long) : Commands() + data class OpenNumberPicker(val option: DVFilterQuickOption, val value: Long?) : Commands() data class OpenConditionPicker(val type: Viewer.Filter.Type, val index: Int) : Commands() - object TagDivider: Commands() - object ObjectDivider: Commands() - object DateDivider: Commands() + object TagDivider : Commands() + object ObjectDivider : Commands() + object DateDivider : Commands() } } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/PickFilterConditionViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/PickFilterConditionViewModel.kt index 0621a43761..0af66d1386 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/PickFilterConditionViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/PickFilterConditionViewModel.kt @@ -23,6 +23,10 @@ class PickFilterConditionViewModel : BaseViewModel() { conditions.addAll(Viewer.Filter.Condition.Number.numberConditions()) conditions[index] } + Viewer.Filter.Type.DATE -> { + conditions.addAll(Viewer.Filter.Condition.Date.dateConditions()) + conditions[index] + } Viewer.Filter.Type.SELECTED -> { conditions.addAll(Viewer.Filter.Condition.Selected.selectConditions()) conditions[index] diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/CellView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/CellView.kt index 9525fac1da..8b3a187909 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/CellView.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/CellView.kt @@ -26,7 +26,7 @@ sealed class CellView { data class Date( override val id: String, override val key: String, - val timeInMillis: Long? = null, + val timeInSecs: Long? = null, override val dateFormat: String, ) : CellView(), DateFormat diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/FilterView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/FilterView.kt index f0a4b4935f..5f8c00a367 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/FilterView.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/FilterView.kt @@ -1,5 +1,6 @@ package com.anytypeio.anytype.presentation.sets.model +import com.anytypeio.anytype.core_models.DVFilterQuickOption import com.anytypeio.anytype.core_utils.ui.ViewType sealed class FilterView : ViewType { @@ -9,6 +10,7 @@ sealed class FilterView : ViewType { abstract val title: String abstract val operator: Viewer.FilterOperator abstract val condition: Viewer.Filter.Condition + open val quickOption: DVFilterQuickOption = DVFilterQuickOption.EXACT_DATE abstract val filterValue: FilterValue abstract val format: ColumnView.Format abstract val isValueRequired: Boolean @@ -122,7 +124,8 @@ sealed class FilterView : ViewType { override val key: String, override val title: String, override val operator: Viewer.FilterOperator, - override val condition: Viewer.Filter.Condition.Number, + override val condition: Viewer.Filter.Condition.Date, + override val quickOption: DVFilterQuickOption, override val filterValue: FilterValue.Date, override val format: ColumnView.Format, override val isValueRequired: Boolean, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/Viewer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/Viewer.kt index bd34da4331..ee6aab3cea 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/Viewer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/Viewer.kt @@ -133,7 +133,7 @@ sealed class Viewer { sealed class Filter { @Parcelize - enum class Type : Parcelable { TEXT, NUMBER, SELECTED, CHECKBOX } + enum class Type : Parcelable { TEXT, NUMBER, DATE, SELECTED, CHECKBOX } sealed class Condition : Filter() { abstract val title: String @@ -252,6 +252,70 @@ sealed class Viewer { } + sealed class Date : Condition() { + + data class None(val name: String = "All") : Date() { + override val title: String + get() = name + } + + data class Equal(val name: String = "Is") : Date() { + override val title: String + get() = name + } + + data class Greater(val name: String = "Is after") : Date() { + override val title: String + get() = name + } + + data class Less(val name: String = "Is before") : Date() { + override val title: String + get() = name + } + + data class GreaterOrEqual(val name: String = "Is on or after") : Date() { + override val title: String + get() = name + } + + data class LessOrEqual(val name: String = "Is on or before") : Date() { + override val title: String + get() = name + } + + data class In(val name: String = "Is within") : Date() { + override val title: String + get() = name + } + + data class Empty(val name: String = "Is empty") : Date() { + override val title: String + get() = name + } + + data class NotEmpty(val name: String = "Is not empty") : Date() { + override val title: String + get() = name + } + + companion object { + fun dateConditions() = + listOf( + None(), + Equal(), + Greater(), + Less(), + GreaterOrEqual(), + LessOrEqual(), + In(), + Empty(), + NotEmpty(), + ) + } + + } + sealed class Selected : Condition() { data class In(val name: String = "Has any of") : Selected() { override val title: String diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/extension/FilterConditionExtensionTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/extension/FilterConditionExtensionTest.kt index 44aefaf0c1..61e2a0da79 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/extension/FilterConditionExtensionTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/extension/FilterConditionExtensionTest.kt @@ -113,6 +113,7 @@ class FilterConditionExtensionTest { val expectedText = Viewer.Filter.Condition.Text.Equal() val expectedNumber = Viewer.Filter.Condition.Number.Equal() + val expectedDate = Viewer.Filter.Condition.Date.None() val expectedSelected = Viewer.Filter.Condition.Selected.In() val expectedCheckbox = Viewer.Filter.Condition.Checkbox.Equal() @@ -148,7 +149,7 @@ class FilterConditionExtensionTest { ) asserter.assertEquals( message = "Condition should be Number Equal", - expected = expectedNumber, + expected = expectedDate, actual = relationDate.toConditionView(condition = null) ) asserter.assertEquals( @@ -219,6 +220,7 @@ class FilterConditionExtensionTest { val expectedText = Viewer.Filter.Condition.Text.Equal() val expectedNumber = Viewer.Filter.Condition.Number.Equal() + val expectedDate = Viewer.Filter.Condition.Date.Equal() val expectedSelected = Viewer.Filter.Condition.Selected.Equal() val expectedCheckbox = Viewer.Filter.Condition.Checkbox.Equal() @@ -254,7 +256,7 @@ class FilterConditionExtensionTest { ) asserter.assertEquals( message = "Condition should be Number Equal", - expected = expectedNumber, + expected = expectedDate, actual = relationDate.toConditionView(condition = DVFilterCondition.EQUAL) ) asserter.assertEquals( @@ -357,11 +359,9 @@ class FilterConditionExtensionTest { expected = expectedNumber, actual = relationNumber.toConditionView(condition = DVFilterCondition.NOT_EQUAL) ) - asserter.assertEquals( - message = "Condition should be Number Not Equal", - expected = expectedNumber, - actual = relationDate.toConditionView(condition = DVFilterCondition.NOT_EQUAL) - ) + assertFails { + relationDate.toConditionView(condition = DVFilterCondition.NOT_EQUAL) + } assertFails { relationTag.toConditionView(condition = DVFilterCondition.NOT_EQUAL) } @@ -423,6 +423,7 @@ class FilterConditionExtensionTest { ) val expectedNumber = Viewer.Filter.Condition.Number.Greater() + val expectedDate = Viewer.Filter.Condition.Date.Greater() assertFails { relationTextLong.toConditionView(condition = DVFilterCondition.GREATER) @@ -446,7 +447,7 @@ class FilterConditionExtensionTest { ) asserter.assertEquals( message = "Condition should be Number Greater", - expected = expectedNumber, + expected = expectedDate, actual = relationDate.toConditionView(condition = DVFilterCondition.GREATER) ) assertFails { @@ -508,6 +509,7 @@ class FilterConditionExtensionTest { ) val expectedNumber = Viewer.Filter.Condition.Number.Less() + val expectedDate = Viewer.Filter.Condition.Date.Less() assertFails { relationTextLong.toConditionView(condition = DVFilterCondition.LESS) @@ -531,7 +533,7 @@ class FilterConditionExtensionTest { ) asserter.assertEquals( message = "Condition should be Number Less", - expected = expectedNumber, + expected = expectedDate, actual = relationDate.toConditionView(condition = DVFilterCondition.LESS) ) assertFails { @@ -593,6 +595,7 @@ class FilterConditionExtensionTest { ) val expectedNumber = Viewer.Filter.Condition.Number.GreaterOrEqual() + val expectedDate = Viewer.Filter.Condition.Date.GreaterOrEqual() assertFails { relationTextLong.toConditionView(condition = DVFilterCondition.GREATER_OR_EQUAL) @@ -616,7 +619,7 @@ class FilterConditionExtensionTest { ) asserter.assertEquals( message = "Condition should be Number Greater or Equal", - expected = expectedNumber, + expected = expectedDate, actual = relationDate.toConditionView(condition = DVFilterCondition.GREATER_OR_EQUAL) ) assertFails { @@ -678,6 +681,7 @@ class FilterConditionExtensionTest { ) val expectedNumber = Viewer.Filter.Condition.Number.LessOrEqual() + val expectedDate = Viewer.Filter.Condition.Date.LessOrEqual() assertFails { relationTextLong.toConditionView(condition = DVFilterCondition.LESS_OR_EQUAL) @@ -701,7 +705,7 @@ class FilterConditionExtensionTest { ) asserter.assertEquals( message = "Condition should be Number Less or Equal", - expected = expectedNumber, + expected = expectedDate, actual = relationDate.toConditionView(condition = DVFilterCondition.LESS_OR_EQUAL) ) assertFails { @@ -903,7 +907,7 @@ class FilterConditionExtensionTest { } @Test - fun `test in condition`() { + fun `relation - should have or should not have in condition`() { val relationTextLong = Relation( key = MockDataFactory.randomUuid(), name = MockDataFactory.randomString(), @@ -966,9 +970,13 @@ class FilterConditionExtensionTest { assertFails { relationNumber.toConditionView(condition = DVFilterCondition.IN) } - assertFails { - relationDate.toConditionView(condition = DVFilterCondition.IN) - } + + asserter.assertEquals( + message = "Condition should be Selected In", + expected = Viewer.Filter.Condition.Date.In(), + actual = relationDate.toConditionView(condition = DVFilterCondition.IN) + ) + asserter.assertEquals( message = "Condition should be Selected In", expected = expectedSelected, @@ -1289,6 +1297,7 @@ class FilterConditionExtensionTest { val expectedText = Viewer.Filter.Condition.Text.Empty() val expectedSelected = Viewer.Filter.Condition.Selected.Empty() val expectedNumber = Viewer.Filter.Condition.Number.Empty() + val expectedDate = Viewer.Filter.Condition.Date.Empty() asserter.assertEquals( message = "Condition should be Text Empty", @@ -1324,7 +1333,7 @@ class FilterConditionExtensionTest { asserter.assertEquals( message = "Condition should be Date Empty", - expected = expectedNumber, + expected = expectedDate, actual = relationDate.toConditionView(condition = DVFilterCondition.EMPTY) ) @@ -1395,6 +1404,7 @@ class FilterConditionExtensionTest { val expectedText = Viewer.Filter.Condition.Text.NotEmpty() val expectedSelected = Viewer.Filter.Condition.Selected.NotEmpty() val expectedNumber = Viewer.Filter.Condition.Number.NotEmpty() + val expectedDate = Viewer.Filter.Condition.Date.NotEmpty() asserter.assertEquals( message = "Condition should be Text Not Empty", @@ -1430,7 +1440,7 @@ class FilterConditionExtensionTest { asserter.assertEquals( message = "Condition should be Date Not Empty", - expected = expectedNumber, + expected = expectedDate, actual = relationDate.toConditionView(condition = DVFilterCondition.NOT_EMPTY) ) @@ -1501,6 +1511,7 @@ class FilterConditionExtensionTest { val expectedText = Viewer.Filter.Condition.Text.Equal() val expectedSelected = Viewer.Filter.Condition.Selected.In() val expectedNumber = Viewer.Filter.Condition.Number.Equal() + val expectedDate = Viewer.Filter.Condition.Date.None() val expectedCheckbox = Viewer.Filter.Condition.Checkbox.Equal() asserter.assertEquals( @@ -1537,7 +1548,7 @@ class FilterConditionExtensionTest { asserter.assertEquals( message = null, - expected = expectedNumber, + expected = expectedDate, actual = relationDate.toConditionView(condition = DVFilterCondition.EXACT_IN) ) @@ -1610,6 +1621,7 @@ class FilterConditionExtensionTest { val expectedText = Viewer.Filter.Condition.Text.Equal() val expectedSelected = Viewer.Filter.Condition.Selected.In() val expectedNumber = Viewer.Filter.Condition.Number.Equal() + val expectedDate = Viewer.Filter.Condition.Date.None() val expectedCheckbox = Viewer.Filter.Condition.Checkbox.Equal() asserter.assertEquals( @@ -1646,7 +1658,7 @@ class FilterConditionExtensionTest { asserter.assertEquals( message = null, - expected = expectedNumber, + expected = expectedDate, actual = relationDate.toConditionView(condition = DVFilterCondition.NOT_EXACT_IN) ) diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/extension/RelationValueExtensionTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/extension/RelationValueExtensionTest.kt index c7e65eaeb2..e818862c5d 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/extension/RelationValueExtensionTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/extension/RelationValueExtensionTest.kt @@ -35,13 +35,13 @@ class RelationValueExtensionTest { } @Test - fun `should return time in millis when Any is numbered string`() { + fun `should return time in secs when Any is numbered string`() { val value: Any = "1621596602" val result: Long? = DateParser.parse(value) - val expected: Long = 1621596602000L + val expected: Long = 1621596602L assertNotNull(result) @@ -52,13 +52,13 @@ class RelationValueExtensionTest { } @Test - fun `should return time in millis when Any is Double`() { + fun `should return time in secs when Any is Double`() { val value: Any = 1621596602.0 val result: Long? = DateParser.parse(value) - val expected: Long = 1621596602000L + val expected: Long = 1621596602L assertNotNull(result) @@ -69,13 +69,13 @@ class RelationValueExtensionTest { } @Test - fun `should return time in millis when Any is Long`() { + fun `should return time in secs when Any is Long`() { val value: Any = 1621596602L val result: Long? = DateParser.parse(value) - val expected: Long = 1621596602000L + val expected: Long = 1621596602L assertNotNull(result)