From 0d3827be37e4635add09ccb8d8ce6c0e9001a764 Mon Sep 17 00:00:00 2001 From: Nazar Sukhovych Date: Sun, 17 Mar 2024 12:33:59 +0100 Subject: [PATCH] REM-809 - Update reminder list item design --- .../core/apps/SelectApplicationActivity.kt | 2 +- .../SpaceBetweenItemDecoration.kt | 23 ++ .../{ => recyclerview}/SpaceItemDecoration.kt | 2 +- .../viewholder/ScheduleBirthdayHolder.kt | 3 +- .../ScheduleReminderAndGTaskViewHolder.kt | 3 +- .../ScheduleReminderAndNoteViewHolder.kt | 3 +- .../viewholder/ScheduleReminderViewHolder.kt | 6 +- .../elementary/tasks/reminder/KoinModule.kt | 10 + .../factory/PlaceFormatterFactory.kt | 12 + .../factory/RadiusFormatterFactory.kt | 18 ++ .../reminder/lists/ReminderActionResolver.kt | 130 +++++++++ .../tasks/reminder/lists/RemindersAdapter.kt | 92 ++++++ .../lists/UiReminderEventsListDiffCallback.kt | 21 ++ .../lists/active/ActiveRemindersViewModel.kt | 15 +- .../lists/active/RemindersFragment.kt | 79 ++---- .../lists/adapter/ArchivedGpsViewHolder.kt | 116 -------- .../adapter/ArchivedReminderViewHolder.kt | 116 -------- .../adapter/ArchivedShoppingViewHolder.kt | 113 -------- .../lists/adapter/DateHeaderViewHolder.kt | 17 -- .../reminder/lists/adapter/GpsViewHolder.kt | 129 --------- .../adapter/UiReminderListDiffCallback.kt | 15 - .../adapter/UiReminderListRecyclerAdapter.kt | 189 ------------- .../reminder/lists/data/UiReminderList.kt | 40 +++ .../lists/data/UiReminderListAdapter.kt | 265 ++++++++++++++++++ .../lists/data/UiReminderListsAdapter.kt | 79 ++++++ .../reminder/lists/removed/ArchiveFragment.kt | 66 ++--- .../removed/ArchiveRemindersViewModel.kt | 7 +- .../todo/ActiveTodoRemindersViewModel.kt | 15 +- .../lists/todo/TodoRemindersFragment.kt | 78 +++--- .../lists/viewholder/HeaderViewHolder.kt | 20 ++ .../lists/viewholder/ReminderViewHolder.kt | 60 ++++ .../main/res/layout/fragment_reminders.xml | 7 +- app/src/main/res/layout/fragment_trash.xml | 11 +- .../res/layout/list_item_reminder_header.xml | 5 +- .../res/layout/list_item_reminder_new.xml | 104 +++++++ app/src/main/res/menu/fragment_reminders.xml | 2 +- app/src/main/res/values/strings.xml | 3 + 37 files changed, 1017 insertions(+), 859 deletions(-) create mode 100644 app/src/main/java/com/elementary/tasks/core/views/recyclerview/SpaceBetweenItemDecoration.kt rename app/src/main/java/com/elementary/tasks/core/views/{ => recyclerview}/SpaceItemDecoration.kt (91%) create mode 100644 app/src/main/java/com/elementary/tasks/reminder/build/formatter/factory/PlaceFormatterFactory.kt create mode 100644 app/src/main/java/com/elementary/tasks/reminder/build/formatter/factory/RadiusFormatterFactory.kt create mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/ReminderActionResolver.kt create mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/RemindersAdapter.kt create mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/UiReminderEventsListDiffCallback.kt delete mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/adapter/ArchivedGpsViewHolder.kt delete mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/adapter/ArchivedReminderViewHolder.kt delete mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/adapter/ArchivedShoppingViewHolder.kt delete mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/adapter/DateHeaderViewHolder.kt delete mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/adapter/GpsViewHolder.kt delete mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/adapter/UiReminderListDiffCallback.kt delete mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/adapter/UiReminderListRecyclerAdapter.kt create mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/data/UiReminderList.kt create mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/data/UiReminderListAdapter.kt create mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/data/UiReminderListsAdapter.kt create mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/viewholder/HeaderViewHolder.kt create mode 100644 app/src/main/java/com/elementary/tasks/reminder/lists/viewholder/ReminderViewHolder.kt create mode 100644 app/src/main/res/layout/list_item_reminder_new.xml diff --git a/app/src/main/java/com/elementary/tasks/core/apps/SelectApplicationActivity.kt b/app/src/main/java/com/elementary/tasks/core/apps/SelectApplicationActivity.kt index 4b474e8e7..e091f3801 100644 --- a/app/src/main/java/com/elementary/tasks/core/apps/SelectApplicationActivity.kt +++ b/app/src/main/java/com/elementary/tasks/core/apps/SelectApplicationActivity.kt @@ -18,7 +18,7 @@ import com.elementary.tasks.core.utils.ui.gone import com.elementary.tasks.core.utils.ui.listenScrollableView import com.elementary.tasks.core.utils.ui.visible import com.elementary.tasks.core.utils.ui.visibleGone -import com.elementary.tasks.core.views.SpaceItemDecoration +import com.elementary.tasks.core.views.recyclerview.SpaceItemDecoration import com.elementary.tasks.databinding.ActivityApplicationListBinding import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.viewModel diff --git a/app/src/main/java/com/elementary/tasks/core/views/recyclerview/SpaceBetweenItemDecoration.kt b/app/src/main/java/com/elementary/tasks/core/views/recyclerview/SpaceBetweenItemDecoration.kt new file mode 100644 index 000000000..57a6d0c21 --- /dev/null +++ b/app/src/main/java/com/elementary/tasks/core/views/recyclerview/SpaceBetweenItemDecoration.kt @@ -0,0 +1,23 @@ +package com.elementary.tasks.core.views.recyclerview + +import android.graphics.Rect +import android.view.View + +import androidx.recyclerview.widget.RecyclerView + +class SpaceBetweenItemDecoration( + private val space: Int +) : RecyclerView.ItemDecoration() { + + override fun getItemOffsets( + outRect: Rect, + view: View, + parent: RecyclerView, + state: RecyclerView.State + ) { + // Add Top space to each next list item + if (parent.getChildAdapterPosition(view) > 0) { + outRect.top = space + } + } +} diff --git a/app/src/main/java/com/elementary/tasks/core/views/SpaceItemDecoration.kt b/app/src/main/java/com/elementary/tasks/core/views/recyclerview/SpaceItemDecoration.kt similarity index 91% rename from app/src/main/java/com/elementary/tasks/core/views/SpaceItemDecoration.kt rename to app/src/main/java/com/elementary/tasks/core/views/recyclerview/SpaceItemDecoration.kt index eaa8e7fd8..16bee5ffc 100644 --- a/app/src/main/java/com/elementary/tasks/core/views/SpaceItemDecoration.kt +++ b/app/src/main/java/com/elementary/tasks/core/views/recyclerview/SpaceItemDecoration.kt @@ -1,4 +1,4 @@ -package com.elementary.tasks.core.views +package com.elementary.tasks.core.views.recyclerview import android.graphics.Rect import android.view.View diff --git a/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleBirthdayHolder.kt b/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleBirthdayHolder.kt index 6df2ad511..e3c2f8e87 100644 --- a/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleBirthdayHolder.kt +++ b/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleBirthdayHolder.kt @@ -1,6 +1,7 @@ package com.elementary.tasks.home.scheduleview.viewholder import android.view.ViewGroup +import com.elementary.tasks.core.binding.HolderBinding import com.elementary.tasks.core.text.applyStyles import com.elementary.tasks.core.utils.ui.gone import com.elementary.tasks.core.utils.ui.inflater @@ -12,7 +13,7 @@ class ScheduleBirthdayHolder( parent: ViewGroup, private val common: ScheduleReminderViewHolderCommon, private val listener: (Int) -> Unit -) : BaseScheduleHolder( +) : HolderBinding( ListItemScheduleBirthdayBinding.inflate(parent.inflater(), parent, false) ) { diff --git a/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleReminderAndGTaskViewHolder.kt b/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleReminderAndGTaskViewHolder.kt index 95baff78b..2b9dab364 100644 --- a/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleReminderAndGTaskViewHolder.kt +++ b/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleReminderAndGTaskViewHolder.kt @@ -1,6 +1,7 @@ package com.elementary.tasks.home.scheduleview.viewholder import android.view.ViewGroup +import com.elementary.tasks.core.binding.HolderBinding import com.elementary.tasks.core.text.applyStyles import com.elementary.tasks.core.utils.ui.gone import com.elementary.tasks.core.utils.ui.inflater @@ -14,7 +15,7 @@ class ScheduleReminderAndGTaskViewHolder( private val googleCommon: ScheduleGoogleViewHolderCommon, private val reminderClickListener: (Int) -> Unit, private val taskClickListener: (Int) -> Unit -) : BaseScheduleHolder( +) : HolderBinding( ListItemScheduleReminderAndGoogleBinding.inflate(parent.inflater(), parent, false) ) { diff --git a/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleReminderAndNoteViewHolder.kt b/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleReminderAndNoteViewHolder.kt index d988a56c5..e35297d77 100644 --- a/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleReminderAndNoteViewHolder.kt +++ b/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleReminderAndNoteViewHolder.kt @@ -1,6 +1,7 @@ package com.elementary.tasks.home.scheduleview.viewholder import android.view.ViewGroup +import com.elementary.tasks.core.binding.HolderBinding import com.elementary.tasks.core.text.applyStyles import com.elementary.tasks.core.utils.ui.gone import com.elementary.tasks.core.utils.ui.inflater @@ -14,7 +15,7 @@ class ScheduleReminderAndNoteViewHolder( private val noteCommon: ScheduleNoteViewHolderCommon, private val reminderClickListener: (Int) -> Unit, private val noteClickListener: (Int) -> Unit -) : BaseScheduleHolder( +) : HolderBinding( ListItemScheduleReminderAndNoteBinding.inflate(parent.inflater(), parent, false) ) { diff --git a/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleReminderViewHolder.kt b/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleReminderViewHolder.kt index 7a454900a..aae210e48 100644 --- a/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleReminderViewHolder.kt +++ b/app/src/main/java/com/elementary/tasks/home/scheduleview/viewholder/ScheduleReminderViewHolder.kt @@ -1,19 +1,19 @@ package com.elementary.tasks.home.scheduleview.viewholder import android.view.ViewGroup +import com.elementary.tasks.core.binding.HolderBinding import com.elementary.tasks.core.text.applyStyles import com.elementary.tasks.core.utils.ui.gone import com.elementary.tasks.core.utils.ui.inflater import com.elementary.tasks.core.utils.ui.visible import com.elementary.tasks.databinding.ListItemScheduleReminderBinding import com.elementary.tasks.home.scheduleview.data.UiReminderScheduleList -import com.elementary.tasks.reminder.lists.adapter.BaseUiReminderListViewHolder class ScheduleReminderViewHolder( parent: ViewGroup, private val common: ScheduleReminderViewHolderCommon, private val listener: (Int) -> Unit -) : BaseUiReminderListViewHolder( +) : HolderBinding( ListItemScheduleReminderBinding.inflate(parent.inflater(), parent, false) ) { @@ -23,7 +23,7 @@ class ScheduleReminderViewHolder( } } - override fun setData(data: UiReminderScheduleList) { + fun setData(data: UiReminderScheduleList) { binding.mainTextView.text = data.mainText.text binding.mainTextView.applyStyles(data.mainText.textFormat) diff --git a/app/src/main/java/com/elementary/tasks/reminder/KoinModule.kt b/app/src/main/java/com/elementary/tasks/reminder/KoinModule.kt index 6145d1914..2ee32f4c3 100644 --- a/app/src/main/java/com/elementary/tasks/reminder/KoinModule.kt +++ b/app/src/main/java/com/elementary/tasks/reminder/KoinModule.kt @@ -10,6 +10,8 @@ import com.elementary.tasks.reminder.build.bi.BiFilter import com.elementary.tasks.reminder.build.bi.CreatorConfigFilter import com.elementary.tasks.reminder.build.bi.LocationFilter import com.elementary.tasks.reminder.build.formatter.ShopItemsFormatter +import com.elementary.tasks.reminder.build.formatter.factory.PlaceFormatterFactory +import com.elementary.tasks.reminder.build.formatter.factory.RadiusFormatterFactory import com.elementary.tasks.reminder.build.logic.BuilderItemBlockedByConstraintCalculator import com.elementary.tasks.reminder.build.logic.BuilderItemMandatoryIfConstraintCalculator import com.elementary.tasks.reminder.build.logic.BuilderItemPermissionConstraintCalculator @@ -65,6 +67,8 @@ import com.elementary.tasks.reminder.create.fragments.recur.preset.PresetViewMod import com.elementary.tasks.reminder.dialog.ReminderViewModel import com.elementary.tasks.reminder.lists.active.ActiveGpsRemindersViewModel import com.elementary.tasks.reminder.lists.active.ActiveRemindersViewModel +import com.elementary.tasks.reminder.lists.data.UiReminderListAdapter +import com.elementary.tasks.reminder.lists.data.UiReminderListsAdapter import com.elementary.tasks.reminder.lists.removed.ArchiveRemindersViewModel import com.elementary.tasks.reminder.lists.todo.ActiveTodoRemindersViewModel import com.elementary.tasks.reminder.preview.AttachmentToUiReminderPreviewAttachment @@ -260,10 +264,16 @@ val reminderModule = module { factory { ShopItemsFormatter(get()) } + single { RadiusFormatterFactory(get(), get()) } + single { PlaceFormatterFactory(get()) } + factory { GoogleTaskToUiReminderPreviewGoogleTask(get(), get(), get(), get()) } factory { NoteToUiReminderPreviewNote(get(), get(), get(), get()) } factory { EventToUiReminderPreview(get(), get(), get(), get()) } factory { AttachmentToUiReminderPreviewAttachment(get(), get(), get(), get()) } factory { UiReminderPreviewDataAdapter(get(), get(), get(), get(), get(), get(), get()) } + + factory { UiReminderListsAdapter(get(), get(), get(), get(), get()) } + factory { UiReminderListAdapter(get(), get(), get(), get(), get(), get(), get(), get(), get()) } } diff --git a/app/src/main/java/com/elementary/tasks/reminder/build/formatter/factory/PlaceFormatterFactory.kt b/app/src/main/java/com/elementary/tasks/reminder/build/formatter/factory/PlaceFormatterFactory.kt new file mode 100644 index 000000000..c126bf0aa --- /dev/null +++ b/app/src/main/java/com/elementary/tasks/reminder/build/formatter/factory/PlaceFormatterFactory.kt @@ -0,0 +1,12 @@ +package com.elementary.tasks.reminder.build.formatter.factory + +import com.elementary.tasks.reminder.build.formatter.PlaceFormatter + +class PlaceFormatterFactory( + private val radiusFormatterFactory: RadiusFormatterFactory +) { + + fun create(): PlaceFormatter { + return PlaceFormatter(radiusFormatterFactory.create()) + } +} diff --git a/app/src/main/java/com/elementary/tasks/reminder/build/formatter/factory/RadiusFormatterFactory.kt b/app/src/main/java/com/elementary/tasks/reminder/build/formatter/factory/RadiusFormatterFactory.kt new file mode 100644 index 000000000..04b43aa56 --- /dev/null +++ b/app/src/main/java/com/elementary/tasks/reminder/build/formatter/factory/RadiusFormatterFactory.kt @@ -0,0 +1,18 @@ +package com.elementary.tasks.reminder.build.formatter.factory + +import android.content.Context +import com.elementary.tasks.core.utils.params.Prefs +import com.elementary.tasks.core.utils.ui.radius.DefaultRadiusFormatter + +class RadiusFormatterFactory( + private val context: Context, + private val prefs: Prefs +) { + + fun create(): DefaultRadiusFormatter { + return DefaultRadiusFormatter( + context = context, + useMetric = prefs.useMetric + ) + } +} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/ReminderActionResolver.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/ReminderActionResolver.kt new file mode 100644 index 000000000..95430283e --- /dev/null +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/ReminderActionResolver.kt @@ -0,0 +1,130 @@ +package com.elementary.tasks.reminder.lists + +import android.content.Context +import android.view.View +import com.elementary.tasks.R +import com.elementary.tasks.core.os.PermissionFlow +import com.elementary.tasks.core.os.Permissions +import com.elementary.tasks.core.os.startActivity +import com.elementary.tasks.core.utils.Constants +import com.elementary.tasks.core.utils.ui.Dialogues +import com.elementary.tasks.reminder.ReminderBuilderLauncher +import com.elementary.tasks.reminder.lists.data.UiReminderListActions +import com.elementary.tasks.reminder.preview.ReminderPreviewActivity + +class ReminderActionResolver( + private val context: Context, + private val dialogues: Dialogues, + private val reminderBuilderLauncher: ReminderBuilderLauncher, + private val permissionFlow: PermissionFlow, + private val deleteAction: (id: String) -> Unit, + private val toggleAction: (id: String) -> Unit, + private val skipAction: (id: String) -> Unit +) { + + fun resolveItemClick( + id: String, + isRemoved: Boolean + ) { + if (isRemoved) { + editReminder(id) + } else { + previewReminder(id) + } + } + + fun resolveItemMore( + view: View, + id: String, + isRemoved: Boolean, + actions: UiReminderListActions + ) { + if (isRemoved) { + showDeletedActionDialog(view, id) + } else { + showActionDialog(view, actions, id) + } + } + + fun resolveItemToggle( + id: String, + isGps: Boolean + ) { + if (isGps) { + permissionFlow.askPermission(Permissions.FOREGROUND_SERVICE) { + toggleAction(id) + } + } else { + toggleAction(id) + } + } + + private fun showDeletedActionDialog(view: View, id: String) { + val items = arrayOf( + context.getString(R.string.open), + context.getString(R.string.edit), + context.getString(R.string.delete) + ) + Dialogues.showPopup(view, { item -> + when (item) { + 0 -> previewReminder(id) + 1 -> editReminder(id) + 2 -> askConfirmation(items[item]) { + if (it) { + deleteAction(id) + } + } + } + }, *items) + } + + private fun showActionDialog( + view: View, + actions: UiReminderListActions, + id: String + ) { + val items = if (actions.canSkip) { + arrayOf( + context.getString(R.string.open), + context.getString(R.string.edit), + context.getString(R.string.move_to_trash), + context.getString(R.string.skip_event) + ) + } else { + arrayOf( + context.getString(R.string.open), + context.getString(R.string.edit), + context.getString(R.string.move_to_trash) + ) + } + Dialogues.showPopup(view, { item -> + when (item) { + 0 -> previewReminder(id) + 1 -> editReminder(id) + 2 -> askConfirmation(items[item]) { + if (it) { + deleteAction(id) + } + } + + 3 -> skipAction(id) + } + }, *items) + } + + private fun askConfirmation(title: String, onAction: (Boolean) -> Unit) { + dialogues.askConfirmation(context, title, onAction) + } + + private fun editReminder(id: String) { + reminderBuilderLauncher.openLogged(context) { + putExtra(Constants.INTENT_ID, id) + } + } + + private fun previewReminder(id: String) { + context.startActivity(ReminderPreviewActivity::class.java) { + putExtra(Constants.INTENT_ID, id) + } + } +} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/RemindersAdapter.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/RemindersAdapter.kt new file mode 100644 index 000000000..3fdb2c329 --- /dev/null +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/RemindersAdapter.kt @@ -0,0 +1,92 @@ +package com.elementary.tasks.reminder.lists + +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.elementary.tasks.home.scheduleview.viewholder.ScheduleReminderViewHolderCommon +import com.elementary.tasks.reminder.lists.data.UiReminderEventsList +import com.elementary.tasks.reminder.lists.data.UiReminderList +import com.elementary.tasks.reminder.lists.data.UiReminderListHeader +import com.elementary.tasks.reminder.lists.viewholder.HeaderViewHolder +import com.elementary.tasks.reminder.lists.viewholder.ReminderViewHolder + +class RemindersAdapter( + private val isEditable: Boolean = true, + private val reminderCommon: ScheduleReminderViewHolderCommon = ScheduleReminderViewHolderCommon(), + private val onItemClicked: (UiReminderList) -> Unit = { }, + private val onToggleClicked: (UiReminderList) -> Unit = { }, + private val onMoreClicked: (View, UiReminderList) -> Unit = { _, _ -> } +) : ListAdapter( + UiReminderEventsListDiffCallback() +) { + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): RecyclerView.ViewHolder { + return when (viewType) { + 1 -> HeaderViewHolder(parent) + + else -> { + ReminderViewHolder( + parent = parent, + editable = isEditable, + showMore = true, + common = reminderCommon, + onItemClicked = { i: Int -> + find(i)?.run { + onItemClicked(this) + } + }, + onToggleClicked = { i: Int -> + find(i)?.run { + onToggleClicked(this) + } + }, + onMoreClicked = { view: View, i: Int -> + find(i)?.run { + onMoreClicked(view, this) + } + } + ) + } + } + } + + private fun find(position: Int): UiReminderList? { + if (position != -1 && position < itemCount) { + return try { + getItem(position).takeIf { it is UiReminderList } + ?.let { it as? UiReminderList } + } catch (e: Throwable) { + null + } + } + return null + } + + override fun onBindViewHolder( + holder: RecyclerView.ViewHolder, + position: Int + ) { + when (holder) { + is ReminderViewHolder -> { + holder.bind(getItem(position) as UiReminderList) + } + + is HeaderViewHolder -> { + holder.bind(getItem(position) as UiReminderListHeader) + } + + else -> { + } + } + } + + override fun getItemViewType(position: Int): Int { + return when (getItem(position)) { + is UiReminderListHeader -> 1 + else -> 0 + } + } +} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/UiReminderEventsListDiffCallback.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/UiReminderEventsListDiffCallback.kt new file mode 100644 index 000000000..11804fc4d --- /dev/null +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/UiReminderEventsListDiffCallback.kt @@ -0,0 +1,21 @@ +package com.elementary.tasks.reminder.lists + +import androidx.recyclerview.widget.DiffUtil +import com.elementary.tasks.reminder.lists.data.UiReminderEventsList + +class UiReminderEventsListDiffCallback : DiffUtil.ItemCallback() { + + override fun areContentsTheSame( + oldItem: UiReminderEventsList, + newItem: UiReminderEventsList + ): Boolean { + return oldItem == newItem + } + + override fun areItemsTheSame( + oldItem: UiReminderEventsList, + newItem: UiReminderEventsList + ): Boolean { + return oldItem.id == newItem.id + } +} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/active/ActiveRemindersViewModel.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/active/ActiveRemindersViewModel.kt index d3eebcfda..61294872e 100644 --- a/app/src/main/java/com/elementary/tasks/reminder/lists/active/ActiveRemindersViewModel.kt +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/active/ActiveRemindersViewModel.kt @@ -5,14 +5,13 @@ import androidx.lifecycle.viewModelScope import com.elementary.tasks.core.arch.BaseProgressViewModel import com.elementary.tasks.core.controller.EventControlFactory import com.elementary.tasks.core.data.Commands -import com.elementary.tasks.core.data.adapter.UiReminderListsAdapter import com.elementary.tasks.core.data.dao.ReminderDao import com.elementary.tasks.core.data.livedata.SearchableLiveData import com.elementary.tasks.core.data.models.Reminder -import com.elementary.tasks.core.data.ui.UiReminderList import com.elementary.tasks.core.utils.Constants import com.elementary.tasks.core.utils.DispatcherProvider import com.elementary.tasks.core.utils.work.WorkerLauncher +import com.elementary.tasks.reminder.lists.data.UiReminderListsAdapter import com.elementary.tasks.reminder.work.ReminderSingleBackupWorker import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -33,9 +32,9 @@ class ActiveRemindersViewModel( reminderData.onNewQuery(query) } - fun skip(reminder: UiReminderList) { + fun skip(id: String) { withResult { - val fromDb = reminderDao.getById(reminder.id) + val fromDb = reminderDao.getById(id) if (fromDb != null) { eventControlFactory.getController(fromDb).skip() workerLauncher.startWork( @@ -50,10 +49,10 @@ class ActiveRemindersViewModel( } } - fun toggleReminder(reminder: UiReminderList) { + fun toggleReminder(id: String) { postInProgress(true) viewModelScope.launch(dispatcherProvider.default()) { - val item = reminderDao.getById(reminder.id) ?: return@launch + val item = reminderDao.getById(id) ?: return@launch if (!eventControlFactory.getController(item).onOff()) { postInProgress(false) postCommand(Commands.OUTDATED) @@ -70,9 +69,9 @@ class ActiveRemindersViewModel( } } - fun moveToTrash(reminder: UiReminderList) { + fun moveToTrash(id: String) { withResult { - reminderDao.getById(reminder.id)?.let { + reminderDao.getById(id)?.let { it.isRemoved = true eventControlFactory.getController(it).disable() reminderDao.insert(it) diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/active/RemindersFragment.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/active/RemindersFragment.kt index ff19556b6..d24752dee 100644 --- a/app/src/main/java/com/elementary/tasks/reminder/lists/active/RemindersFragment.kt +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/active/RemindersFragment.kt @@ -9,24 +9,21 @@ import com.elementary.tasks.R import com.elementary.tasks.core.analytics.Screen import com.elementary.tasks.core.analytics.ScreenUsedEvent import com.elementary.tasks.core.data.Commands -import com.elementary.tasks.core.data.ui.UiReminderList -import com.elementary.tasks.core.data.ui.UiReminderListActiveGps -import com.elementary.tasks.core.data.ui.UiReminderListData -import com.elementary.tasks.core.interfaces.ActionsListener -import com.elementary.tasks.core.os.Permissions import com.elementary.tasks.core.os.SystemServiceProvider +import com.elementary.tasks.core.os.dp2px import com.elementary.tasks.core.os.toast -import com.elementary.tasks.core.utils.ListActions import com.elementary.tasks.core.utils.nonNullObserve import com.elementary.tasks.core.utils.ui.SearchMenuHandler import com.elementary.tasks.core.utils.ui.ViewUtils import com.elementary.tasks.core.utils.ui.visibleGone +import com.elementary.tasks.core.views.recyclerview.SpaceBetweenItemDecoration import com.elementary.tasks.databinding.FragmentRemindersBinding import com.elementary.tasks.home.eventsview.BaseSubEventsFragment import com.elementary.tasks.home.eventsview.HomeEventsFragmentDirections import com.elementary.tasks.reminder.ReminderBuilderLauncher -import com.elementary.tasks.reminder.ReminderResolver -import com.elementary.tasks.reminder.lists.adapter.UiReminderListRecyclerAdapter +import com.elementary.tasks.reminder.lists.ReminderActionResolver +import com.elementary.tasks.reminder.lists.RemindersAdapter +import com.elementary.tasks.reminder.lists.data.UiReminderEventsList import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.viewModel import timber.log.Timber @@ -37,29 +34,32 @@ class RemindersFragment : BaseSubEventsFragment() { private val reminderBuilderLauncher by inject() private val viewModel by viewModel() - private var mPosition: Int = 0 - - private val reminderResolver = ReminderResolver( - dialogAction = { return@ReminderResolver dialogues }, - reminderBuilderLauncher = reminderBuilderLauncher, - toggleAction = { reminder -> - when (reminder) { - is UiReminderListActiveGps -> { - permissionFlow.askPermission(Permissions.FOREGROUND_SERVICE) { - viewModel.toggleReminder(reminder) - } - } + private val reminderResolver by lazy { + ReminderActionResolver( + context = requireContext(), + dialogues = dialogues, + reminderBuilderLauncher = reminderBuilderLauncher, + permissionFlow = permissionFlow, + toggleAction = { viewModel.toggleReminder(it) }, + deleteAction = { viewModel.moveToTrash(it) }, + skipAction = { viewModel.skip(it) } + ) + } - else -> { - viewModel.toggleReminder(reminder) - } - } - }, - deleteAction = { reminder -> viewModel.moveToTrash(reminder) }, - skipAction = { reminder -> viewModel.skip(reminder) } + private val remindersAdapter = RemindersAdapter( + isEditable = true, + onItemClicked = { reminderResolver.resolveItemClick(it.id, it.state.isRemoved) }, + onToggleClicked = { reminderResolver.resolveItemToggle(it.id, it.state.isGps) }, + onMoreClicked = { view, reminder -> + reminderResolver.resolveItemMore( + view = view, + id = reminder.id, + isRemoved = reminder.state.isRemoved, + actions = reminder.actions + ) + } ) - private val remindersAdapter = UiReminderListRecyclerAdapter(true, isEditable = true) private val searchMenuHandler = SearchMenuHandler( systemServiceProvider.provideSearchManager(), R.string.search @@ -115,38 +115,21 @@ class RemindersFragment : BaseSubEventsFragment() { } viewModel.result.nonNullObserve(viewLifecycleOwner) { if (it == Commands.OUTDATED) { - remindersAdapter.notifyItemChanged(mPosition) toast(R.string.reminder_is_outdated) } } } - private fun showData(result: List) { + private fun showData(result: List) { remindersAdapter.submitList(result) binding.recyclerView.smoothScrollToPosition(0) reloadEmptyView(result.size) } private fun initList() { - remindersAdapter.actionsListener = object : ActionsListener { - override fun onAction( - view: View, - position: Int, - t: UiReminderListData?, - actions: ListActions - ) { - if (t != null) { - mPosition = position - reminderResolver.resolveAction(view, t, actions) - } - } - } - if (resources.getBoolean(R.bool.is_tablet)) { - binding.recyclerView.layoutManager = LinearLayoutManager(context) - } else { - binding.recyclerView.layoutManager = LinearLayoutManager(context) - } + binding.recyclerView.layoutManager = LinearLayoutManager(context) binding.recyclerView.adapter = remindersAdapter + binding.recyclerView.addItemDecoration(SpaceBetweenItemDecoration(dp2px(8))) ViewUtils.listenScrollableView(binding.recyclerView) { if (it) { binding.fab.show() diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/ArchivedGpsViewHolder.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/ArchivedGpsViewHolder.kt deleted file mode 100644 index a0c344aa6..000000000 --- a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/ArchivedGpsViewHolder.kt +++ /dev/null @@ -1,116 +0,0 @@ -package com.elementary.tasks.reminder.lists.adapter - -import android.annotation.SuppressLint -import android.view.View -import android.view.ViewGroup -import com.elementary.tasks.core.data.ui.UiReminderListRemovedGps -import com.elementary.tasks.core.data.ui.reminder.UiAppTarget -import com.elementary.tasks.core.data.ui.reminder.UiCallTarget -import com.elementary.tasks.core.data.ui.reminder.UiEmailTarget -import com.elementary.tasks.core.data.ui.reminder.UiLinkTarget -import com.elementary.tasks.core.data.ui.reminder.UiSmsTarget -import com.elementary.tasks.core.utils.ListActions -import com.elementary.tasks.core.utils.ui.gone -import com.elementary.tasks.core.utils.ui.inflater -import com.elementary.tasks.core.utils.ui.visible -import com.elementary.tasks.core.utils.ui.visibleGone -import com.elementary.tasks.databinding.ListItemReminderBinding -import java.util.Locale - -class ArchivedGpsViewHolder( - parent: ViewGroup, - showMore: Boolean = true, - private val listener: ((View, Int, ListActions) -> Unit)? = null -) : BaseUiReminderListViewHolder( - ListItemReminderBinding.inflate(parent.inflater(), parent, false) -) { - - init { - binding.buttonMore.visibleGone(showMore) - binding.todoList.gone() - binding.switchWrapper.gone() - binding.itemCard.setOnClickListener { - listener?.invoke( - it, - bindingAdapterPosition, - ListActions.OPEN - ) - } - binding.buttonMore.setOnClickListener { - listener?.invoke( - it, - bindingAdapterPosition, - ListActions.MORE - ) - } - } - - override fun setData(data: UiReminderListRemovedGps) { - binding.taskText.text = data.summary - loadPlaces(data) - loadContact(data) - binding.badgesView.gone() - loadGroup(data) - } - - @SuppressLint("SetTextI18n") - private fun loadGroup(reminder: UiReminderListRemovedGps) { - val priority = reminder.priority - val typeLabel = reminder.title - val groupName = reminder.group?.title ?: "" - binding.reminderTypeGroup.text = "$typeLabel ($groupName, $priority)" - } - - private fun loadPlaces(reminder: UiReminderListRemovedGps) { - reminder.places.firstOrNull()?.also { - binding.taskDate.text = String.format( - Locale.getDefault(), - "%.5f %.5f (%d)", - it.latitude, - it.longitude, - reminder.places.size - ) - } - } - - @SuppressLint("SetTextI18n") - private fun loadContact(reminder: UiReminderListRemovedGps) { - when (val target = reminder.actionTarget) { - is UiSmsTarget -> { - binding.reminderPhone.visible() - if (target.name == null) { - binding.reminderPhone.text = target.target - } else { - binding.reminderPhone.text = "${target.name}(${target.target})" - } - } - is UiCallTarget -> { - binding.reminderPhone.visible() - if (target.name == null) { - binding.reminderPhone.text = target.target - } else { - binding.reminderPhone.text = "${target.name}(${target.target})" - } - } - is UiAppTarget -> { - binding.reminderPhone.visible() - binding.reminderPhone.text = "${target.name}/${target.target}" - } - is UiEmailTarget -> { - binding.reminderPhone.visible() - if (target.name == null) { - binding.reminderPhone.text = target.target - } else { - binding.reminderPhone.text = "${target.name}(${target.target})" - } - } - is UiLinkTarget -> { - binding.reminderPhone.visible() - binding.reminderPhone.text = target.target - } - else -> { - binding.reminderPhone.gone() - } - } - } -} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/ArchivedReminderViewHolder.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/ArchivedReminderViewHolder.kt deleted file mode 100644 index fd9216b72..000000000 --- a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/ArchivedReminderViewHolder.kt +++ /dev/null @@ -1,116 +0,0 @@ -package com.elementary.tasks.reminder.lists.adapter - -import android.annotation.SuppressLint -import android.view.View -import android.view.ViewGroup -import com.elementary.tasks.core.data.ui.UiReminderListRemoved -import com.elementary.tasks.core.data.ui.reminder.UiAppTarget -import com.elementary.tasks.core.data.ui.reminder.UiCallTarget -import com.elementary.tasks.core.data.ui.reminder.UiEmailTarget -import com.elementary.tasks.core.data.ui.reminder.UiLinkTarget -import com.elementary.tasks.core.data.ui.reminder.UiSmsTarget -import com.elementary.tasks.core.utils.ListActions -import com.elementary.tasks.core.utils.ui.gone -import com.elementary.tasks.core.utils.ui.inflater -import com.elementary.tasks.core.utils.ui.visible -import com.elementary.tasks.core.utils.ui.visibleGone -import com.elementary.tasks.databinding.ListItemReminderBinding - -class ArchivedReminderViewHolder( - parent: ViewGroup, - showMore: Boolean = true, - private val listener: ((View, Int, ListActions) -> Unit)? = null -) : BaseUiReminderListViewHolder( - ListItemReminderBinding.inflate(parent.inflater(), parent, false) -) { - - init { - binding.buttonMore.visibleGone(showMore) - binding.todoList.gone() - binding.switchWrapper.gone() - binding.itemCard.setOnClickListener { - listener?.invoke( - it, - bindingAdapterPosition, - ListActions.OPEN - ) - } - binding.buttonMore.setOnClickListener { - listener?.invoke( - it, - bindingAdapterPosition, - ListActions.MORE - ) - } - } - - override fun setData(data: UiReminderListRemoved) { - binding.taskText.text = data.summary - loadDate(data) - loadContact(data) - loadRepeatLeft(data) - loadGroup(data) - } - - @SuppressLint("SetTextI18n") - private fun loadGroup(reminder: UiReminderListRemoved) { - val priority = reminder.priority - val typeLabel = reminder.title - val groupName = reminder.group?.title ?: "" - binding.reminderTypeGroup.text = "$typeLabel ($groupName, $priority)" - } - - private fun loadRepeatLeft(reminder: UiReminderListRemoved) { - binding.badgesView.visible() - binding.repeatBadge.visible() - binding.timeToBadge.gone() - - binding.repeatBadge.text = reminder.due.repeat - binding.timeToBadge.text = reminder.due.remaining - } - - private fun loadDate(reminder: UiReminderListRemoved) { - binding.taskDate.text = reminder.due.dateTime - } - - @SuppressLint("SetTextI18n") - private fun loadContact(reminder: UiReminderListRemoved) { - when (val target = reminder.actionTarget) { - is UiSmsTarget -> { - binding.reminderPhone.visible() - if (target.name == null) { - binding.reminderPhone.text = target.target - } else { - binding.reminderPhone.text = "${target.name}(${target.target})" - } - } - is UiCallTarget -> { - binding.reminderPhone.visible() - if (target.name == null) { - binding.reminderPhone.text = target.target - } else { - binding.reminderPhone.text = "${target.name}(${target.target})" - } - } - is UiAppTarget -> { - binding.reminderPhone.visible() - binding.reminderPhone.text = "${target.name}/${target.target}" - } - is UiEmailTarget -> { - binding.reminderPhone.visible() - if (target.name == null) { - binding.reminderPhone.text = target.target - } else { - binding.reminderPhone.text = "${target.name}(${target.target})" - } - } - is UiLinkTarget -> { - binding.reminderPhone.visible() - binding.reminderPhone.text = target.target - } - else -> { - binding.reminderPhone.gone() - } - } - } -} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/ArchivedShoppingViewHolder.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/ArchivedShoppingViewHolder.kt deleted file mode 100644 index 67bf0c644..000000000 --- a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/ArchivedShoppingViewHolder.kt +++ /dev/null @@ -1,113 +0,0 @@ -package com.elementary.tasks.reminder.lists.adapter - -import android.annotation.SuppressLint -import android.graphics.Paint -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import com.elementary.tasks.R -import com.elementary.tasks.core.data.models.ShopItem -import com.elementary.tasks.core.data.ui.UiReminderListRemovedShop -import com.elementary.tasks.core.utils.ListActions -import com.elementary.tasks.core.utils.ui.gone -import com.elementary.tasks.core.utils.ui.inflater -import com.elementary.tasks.core.utils.ui.transparent -import com.elementary.tasks.core.utils.ui.visible -import com.elementary.tasks.databinding.ListItemReminderBinding -import com.elementary.tasks.databinding.ListItemShopItemBinding - -class ArchivedShoppingViewHolder( - parent: ViewGroup, - showMore: Boolean = true, - private val isDark: Boolean, - private val listener: ((View, Int, ListActions) -> Unit)? = null -) : BaseUiReminderListViewHolder( - ListItemReminderBinding.inflate(parent.inflater(), parent, false) -) { - - init { - binding.switchWrapper.gone() - binding.reminderPhone.gone() - binding.itemCard.setOnClickListener { - listener?.invoke( - it, - bindingAdapterPosition, - ListActions.OPEN - ) - } - - if (showMore) { - binding.buttonMore.setOnClickListener { - listener?.invoke( - it, - bindingAdapterPosition, - ListActions.MORE - ) - } - binding.buttonMore.visible() - } else { - binding.buttonMore.gone() - } - } - - override fun setData(data: UiReminderListRemovedShop) { - binding.taskText.text = data.summary - loadGroup(data) - loadShoppingDate(data) - loadItems(data.shopList) - } - - @SuppressLint("SetTextI18n") - private fun loadGroup(reminder: UiReminderListRemovedShop) { - val priority = reminder.priority - val typeLabel = reminder.title - val groupName = reminder.group?.title ?: "" - binding.reminderTypeGroup.text = "$typeLabel ($groupName, $priority)" - } - - private fun loadItems(shoppings: List) { - binding.todoList.visible() - binding.todoList.isFocusableInTouchMode = false - binding.todoList.isFocusable = false - binding.todoList.removeAllViewsInLayout() - var count = 0 - for (list in shoppings) { - val bind = ListItemShopItemBinding.inflate( - LayoutInflater.from(binding.todoList.context), - binding.todoList, - false - ) - val checkView = bind.checkView - val textView = bind.shopText - if (list.isChecked) { - checkView.setImageResource(R.drawable.ic_fluent_checkbox_checked) - textView.paintFlags = textView.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG - } else { - checkView.setImageResource(R.drawable.ic_fluent_checkbox_unchecked) - textView.paintFlags = textView.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv() - } - count++ - if (count == 9) { - checkView.transparent() - textView.text = "..." - binding.todoList.addView(bind.root) - break - } else { - checkView.visible() - textView.text = list.summary - binding.todoList.addView(bind.root) - } - } - } - - private fun loadShoppingDate(reminder: UiReminderListRemovedShop) { - val due = reminder.due.dateTime - if (due != null) { - binding.taskDate.text = reminder.due.dateTime - binding.taskDate.visible() - } else { - binding.taskDate.gone() - binding.badgesView.gone() - } - } -} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/DateHeaderViewHolder.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/DateHeaderViewHolder.kt deleted file mode 100644 index c42442f15..000000000 --- a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/DateHeaderViewHolder.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.elementary.tasks.reminder.lists.adapter - -import android.view.ViewGroup -import com.elementary.tasks.core.data.ui.UiReminderListHeader -import com.elementary.tasks.core.utils.ui.inflater -import com.elementary.tasks.databinding.ListItemReminderHeaderBinding - -class DateHeaderViewHolder( - parent: ViewGroup -) : BaseUiReminderListViewHolder( - ListItemReminderHeaderBinding.inflate(parent.inflater(), parent, false) -) { - - override fun setData(data: UiReminderListHeader) { - binding.dateView.text = data.date - } -} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/GpsViewHolder.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/GpsViewHolder.kt deleted file mode 100644 index 6df5d2d43..000000000 --- a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/GpsViewHolder.kt +++ /dev/null @@ -1,129 +0,0 @@ -package com.elementary.tasks.reminder.lists.adapter - -import android.annotation.SuppressLint -import android.view.View -import android.view.ViewGroup -import com.elementary.tasks.core.data.ui.UiReminderListActiveGps -import com.elementary.tasks.core.data.ui.reminder.UiAppTarget -import com.elementary.tasks.core.data.ui.reminder.UiCallTarget -import com.elementary.tasks.core.data.ui.reminder.UiEmailTarget -import com.elementary.tasks.core.data.ui.reminder.UiLinkTarget -import com.elementary.tasks.core.data.ui.reminder.UiSmsTarget -import com.elementary.tasks.core.utils.ListActions -import com.elementary.tasks.core.utils.ui.gone -import com.elementary.tasks.core.utils.ui.inflater -import com.elementary.tasks.core.utils.ui.visible -import com.elementary.tasks.core.utils.ui.visibleGone -import com.elementary.tasks.databinding.ListItemReminderBinding -import java.util.Locale - -class GpsViewHolder( - parent: ViewGroup, - editable: Boolean, - showMore: Boolean = true, - private val listener: ((View, Int, ListActions) -> Unit)? = null -) : BaseUiReminderListViewHolder( - ListItemReminderBinding.inflate(parent.inflater(), parent, false) -) { - - init { - binding.switchWrapper.visibleGone(editable) - binding.buttonMore.visibleGone(showMore) - binding.todoList.gone() - binding.itemCard.setOnClickListener { - listener?.invoke( - it, - bindingAdapterPosition, - ListActions.OPEN - ) - } - binding.switchWrapper.setOnClickListener { - listener?.invoke( - it, - bindingAdapterPosition, - ListActions.SWITCH - ) - } - binding.buttonMore.setOnClickListener { - listener?.invoke( - it, - bindingAdapterPosition, - ListActions.MORE - ) - } - } - - override fun setData(data: UiReminderListActiveGps) { - binding.taskText.text = data.summary - loadPlaces(data) - loadCheck(data) - loadContact(data) - binding.badgesView.gone() - loadGroup(data) - } - - @SuppressLint("SetTextI18n") - private fun loadGroup(reminder: UiReminderListActiveGps) { - val priority = reminder.priority - val typeLabel = reminder.title - val groupName = reminder.group?.title ?: "" - binding.reminderTypeGroup.text = "$typeLabel ($groupName, $priority)" - } - - private fun loadPlaces(reminder: UiReminderListActiveGps) { - reminder.places.firstOrNull()?.also { - binding.taskDate.text = String.format( - Locale.getDefault(), - "%.5f %.5f (%d)", - it.latitude, - it.longitude, - reminder.places.size - ) - } - } - - private fun loadCheck(reminder: UiReminderListActiveGps) { - binding.itemCheck.isChecked = reminder.status.active - } - - @SuppressLint("SetTextI18n") - private fun loadContact(reminder: UiReminderListActiveGps) { - when (val target = reminder.actionTarget) { - is UiSmsTarget -> { - binding.reminderPhone.visible() - if (target.name == null) { - binding.reminderPhone.text = target.target - } else { - binding.reminderPhone.text = "${target.name}(${target.target})" - } - } - is UiCallTarget -> { - binding.reminderPhone.visible() - if (target.name == null) { - binding.reminderPhone.text = target.target - } else { - binding.reminderPhone.text = "${target.name}(${target.target})" - } - } - is UiAppTarget -> { - binding.reminderPhone.visible() - binding.reminderPhone.text = "${target.name}/${target.target}" - } - is UiEmailTarget -> { - binding.reminderPhone.visible() - if (target.name == null) { - binding.reminderPhone.text = target.target - } else { - binding.reminderPhone.text = "${target.name}(${target.target})" - } - } - is UiLinkTarget -> { - binding.reminderPhone.visible() - binding.reminderPhone.text = target.target - } - else -> { - binding.reminderPhone.gone() - } - } - } -} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/UiReminderListDiffCallback.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/UiReminderListDiffCallback.kt deleted file mode 100644 index 186c13bb2..000000000 --- a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/UiReminderListDiffCallback.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.elementary.tasks.reminder.lists.adapter - -import androidx.recyclerview.widget.DiffUtil -import com.elementary.tasks.core.data.ui.UiReminderList - -class UiReminderListDiffCallback : DiffUtil.ItemCallback() { - - override fun areContentsTheSame(oldItem: UiReminderList, newItem: UiReminderList): Boolean { - return oldItem == newItem - } - - override fun areItemsTheSame(oldItem: UiReminderList, newItem: UiReminderList): Boolean { - return oldItem.id == newItem.id - } -} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/UiReminderListRecyclerAdapter.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/UiReminderListRecyclerAdapter.kt deleted file mode 100644 index e1baf634e..000000000 --- a/app/src/main/java/com/elementary/tasks/reminder/lists/adapter/UiReminderListRecyclerAdapter.kt +++ /dev/null @@ -1,189 +0,0 @@ -package com.elementary.tasks.reminder.lists.adapter - -import android.view.View -import android.view.ViewGroup -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView -import com.elementary.tasks.core.data.ui.UiReminderList -import com.elementary.tasks.core.data.ui.UiReminderListActive -import com.elementary.tasks.core.data.ui.UiReminderListActiveGps -import com.elementary.tasks.core.data.ui.UiReminderListActiveShop -import com.elementary.tasks.core.data.ui.UiReminderListData -import com.elementary.tasks.core.data.ui.UiReminderListHeader -import com.elementary.tasks.core.data.ui.UiReminderListRemoved -import com.elementary.tasks.core.data.ui.UiReminderListRemovedGps -import com.elementary.tasks.core.data.ui.UiReminderListRemovedShop -import com.elementary.tasks.core.data.ui.reminder.UiReminderViewType -import com.elementary.tasks.core.interfaces.ActionsListener -import com.elementary.tasks.core.utils.ListActions -import com.elementary.tasks.home.scheduleview.viewholder.ScheduleReminderViewHolderCommon - -class UiReminderListRecyclerAdapter( - private val isDark: Boolean, - private val isEditable: Boolean = true -) : ListAdapter>( - UiReminderListDiffCallback() -) { - - private val reminderCommon = ScheduleReminderViewHolderCommon() - - var actionsListener: ActionsListener? = null - var data = listOf() - private set - - init { - registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { - override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { - super.onItemRangeInserted(positionStart, itemCount) - updateItem(positionStart + 1) - } - - override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) { - super.onItemRangeRemoved(positionStart, itemCount) - updateItem(positionStart) - } - - override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) { - super.onItemRangeMoved(fromPosition, toPosition, itemCount) - updateItem(toPosition) - updateItem(fromPosition) - } - }) - } - - private fun updateItem(position: Int) { - if (itemCount > position) { - notifyItemChanged(position) - updateBefore(position) - updateAfter(position, itemCount) - } - } - - private fun updateBefore(position: Int) { - if (position > 0) { - notifyItemChanged(position - 1) - } - } - - private fun updateAfter(position: Int, count: Int) { - if (position + 1 < count) { - notifyItemChanged(position + 1) - } - } - - override fun submitList(list: List?) { - super.submitList(list) - data = list ?: emptyList() - } - - override fun onCreateViewHolder( - parent: ViewGroup, - viewType: Int - ): BaseUiReminderListViewHolder<*, *> { - val listener: (View, Int, ListActions) -> Unit = { view, i, listActions -> - actionsListener?.onAction(view, i, find(i), listActions) - } - return when (viewType) { - UiReminderViewType.GPS_ACTIVE.value -> { - GpsViewHolder(parent, isEditable, showMore = true, listener) - } - - UiReminderViewType.ACTIVE.value -> { - ReminderViewHolder(parent, isEditable, showMore = true, listener) - } - - UiReminderViewType.SHOPPING_ACTIVE.value -> { - ShoppingViewHolder( - parent = parent, - editable = isEditable, - showMore = true, - isDark = isDark, - scheduleReminderViewHolderCommon = reminderCommon, - listener = listener - ) - } - - UiReminderViewType.GPS_REMOVED.value -> { - ArchivedGpsViewHolder(parent, showMore = true, listener) - } - - UiReminderViewType.SHOPPING_REMOVED.value -> { - ArchivedShoppingViewHolder(parent, showMore = true, isDark = isDark, listener) - } - - UiReminderViewType.REMOVED.value -> { - ArchivedReminderViewHolder(parent, showMore = true, listener) - } - - UiReminderViewType.HEADER.value -> { - DateHeaderViewHolder(parent) - } - - else -> { - ReminderViewHolder(parent, isEditable, showMore = true, listener) - } - } - } - - private fun find(position: Int): UiReminderListData? { - if (position != -1 && position < itemCount) { - return try { - getItem(position).takeIf { it is UiReminderListData }?.let { it as UiReminderListData } - } catch (e: Throwable) { - null - } - } - return null - } - - override fun onBindViewHolder( - holder: BaseUiReminderListViewHolder<*, *>, - position: Int - ) { - val item = getItem(position) - when (holder) { - is GpsViewHolder -> { - holder.setData(item as UiReminderListActiveGps) - } - - is ArchivedGpsViewHolder -> { - holder.setData(item as UiReminderListRemovedGps) - } - - is ShoppingViewHolder -> { - holder.setData(item as UiReminderListActiveShop) - } - - is ArchivedShoppingViewHolder -> { - holder.setData(item as UiReminderListRemovedShop) - } - - is ReminderViewHolder -> { - holder.setData(item as UiReminderListActive) - } - - is ArchivedReminderViewHolder -> { - holder.setData(item as UiReminderListRemoved) - } - - is DateHeaderViewHolder -> { - holder.setData(item as UiReminderListHeader) - } - - else -> { - } - } - } - - override fun getItemViewType(position: Int): Int { - return when (getItem(position)) { - is UiReminderListActive -> UiReminderViewType.ACTIVE - is UiReminderListRemoved -> UiReminderViewType.REMOVED - is UiReminderListRemovedShop -> UiReminderViewType.SHOPPING_REMOVED - is UiReminderListActiveShop -> UiReminderViewType.SHOPPING_ACTIVE - is UiReminderListActiveGps -> UiReminderViewType.GPS_ACTIVE - is UiReminderListRemovedGps -> UiReminderViewType.GPS_REMOVED - is UiReminderListHeader -> UiReminderViewType.HEADER - }.value - } -} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/data/UiReminderList.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/data/UiReminderList.kt new file mode 100644 index 000000000..af9ab437f --- /dev/null +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/data/UiReminderList.kt @@ -0,0 +1,40 @@ +package com.elementary.tasks.reminder.lists.data + +import com.elementary.tasks.core.data.ui.UiTextElement +import org.threeten.bp.LocalDateTime + +sealed class UiReminderEventsList { + abstract val id: String +} + +data class UiReminderListHeader( + val mainText: UiTextElement +) : UiReminderEventsList() { + override val id: String = mainText.text +} + +data class UiReminderList( + override val id: String, + val noteId: String?, + val dueDateTime: LocalDateTime?, + val mainText: UiTextElement, + val secondaryText: UiTextElement?, + val tertiaryText: UiTextElement?, + val tags: List, + val actions: UiReminderListActions, + val state: UiReminderListState +) : UiReminderEventsList() + +data class UiReminderListState( + val isActive: Boolean = false, + val isRemoved: Boolean = false, + val isGps: Boolean = false +) + +data class UiReminderListActions( + val canToggle: Boolean = false, + val canOpen: Boolean = false, + val canEdit: Boolean = false, + val canDelete: Boolean = false, + val canSkip: Boolean = false +) diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/data/UiReminderListAdapter.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/data/UiReminderListAdapter.kt new file mode 100644 index 000000000..86d869bd2 --- /dev/null +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/data/UiReminderListAdapter.kt @@ -0,0 +1,265 @@ +package com.elementary.tasks.reminder.lists.data + +import com.elementary.tasks.R +import com.elementary.tasks.core.data.adapter.UiAdapter +import com.elementary.tasks.core.data.adapter.UiReminderCommonAdapter +import com.elementary.tasks.core.data.adapter.group.UiGroupListAdapter +import com.elementary.tasks.core.data.models.Reminder +import com.elementary.tasks.core.data.ui.UiTextElement +import com.elementary.tasks.core.data.ui.reminder.UiAppTarget +import com.elementary.tasks.core.data.ui.reminder.UiCallTarget +import com.elementary.tasks.core.data.ui.reminder.UiEmailTarget +import com.elementary.tasks.core.data.ui.reminder.UiLinkTarget +import com.elementary.tasks.core.data.ui.reminder.UiReminderDueData +import com.elementary.tasks.core.data.ui.reminder.UiReminderType +import com.elementary.tasks.core.data.ui.reminder.UiSmsTarget +import com.elementary.tasks.core.os.ColorProvider +import com.elementary.tasks.core.os.UnitsConverter +import com.elementary.tasks.core.text.UiTextFormat +import com.elementary.tasks.core.text.UiTextStyle +import com.elementary.tasks.core.utils.TextProvider +import com.elementary.tasks.core.utils.adjustAlpha +import com.elementary.tasks.core.utils.datetime.DateTimeManager +import com.elementary.tasks.core.utils.datetime.RecurEventManager +import com.elementary.tasks.reminder.build.formatter.PlaceFormatter +import com.elementary.tasks.reminder.build.formatter.ShopItemsFormatter +import com.elementary.tasks.reminder.build.formatter.factory.PlaceFormatterFactory + +class UiReminderListAdapter( + private val uiReminderCommonAdapter: UiReminderCommonAdapter, + private val unitsConverter: UnitsConverter, + private val colorProvider: ColorProvider, + private val textProvider: TextProvider, + private val shopItemsFormatter: ShopItemsFormatter, + private val uiGroupListAdapter: UiGroupListAdapter, + private val dateTimeManager: DateTimeManager, + private val recurEventManager: RecurEventManager, + private val placeFormatterFactory: PlaceFormatterFactory +) : UiAdapter { + + private val placeFormatter: PlaceFormatter by lazy { placeFormatterFactory.create() } + + override fun create(data: Reminder): UiReminderList { + val type = UiReminderType(data.type) + val due = uiReminderCommonAdapter.getDue(data, type) + val canSkip = !type.isGpsType() && ( + data.repeatInterval > 0L || type.isByWeekday() || + type.isMonthly() || type.isYearly() || (type.isRecur() && hasNextRecur(data)) + ) + + return UiReminderList( + id = data.uuId, + noteId = data.noteId.takeIf { it.isNotEmpty() }, + dueDateTime = due.localDateTime, + mainText = createMainText(type, data), + secondaryText = createSecondaryText(due, type, data), + tertiaryText = createTertiaryText(type, data), + tags = listOfNotNull( + createRepeatBadge(due), + createRemainingBadge(due), + createGroupBadge(data) + ), + actions = UiReminderListActions( + canSkip = data.isActive && !data.isRemoved && canSkip, + canDelete = !data.isRemoved, + canToggle = true, + canEdit = true, + canOpen = !data.isRemoved + ), + state = UiReminderListState( + isActive = data.isActive, + isRemoved = data.isRemoved, + isGps = type.isGpsType() + ) + ) + } + + private fun createGroupBadge( + reminder: Reminder + ): UiTextElement { + return uiGroupListAdapter.convert( + reminder.groupUuId, + reminder.groupColor, + reminder.groupTitle + ).let { + UiTextElement( + text = it.title, + textFormat = UiTextFormat( + fontSize = unitsConverter.spToPx(12f), + textStyle = UiTextStyle.BOLD, + textColor = colorProvider.getColorOnSecondaryContainer() + ) + ) + } + } + + private fun createRepeatBadge( + dueData: UiReminderDueData? + ): UiTextElement? { + if (dueData?.localDateTime == null) { + return null + } + return UiTextElement( + text = dueData.repeat, + textFormat = UiTextFormat( + fontSize = unitsConverter.spToPx(12f), + textStyle = UiTextStyle.BOLD, + textColor = colorProvider.getColorOnSecondaryContainer() + ) + ) + } + + private fun createRemainingBadge( + dueData: UiReminderDueData? + ): UiTextElement? { + if (dueData?.localDateTime == null) { + return null + } + return dueData.remaining?.let { + UiTextElement( + text = it, + textFormat = UiTextFormat( + fontSize = unitsConverter.spToPx(12f), + textStyle = UiTextStyle.BOLD, + textColor = colorProvider.getColorOnSecondaryContainer() + ) + ) + } + } + + private fun createTertiaryText( + type: UiReminderType, + reminder: Reminder + ): UiTextElement? { + return if (type.isSubTasks()) { + UiTextElement( + text = formatSubTasks(reminder), + textFormat = UiTextFormat( + fontSize = unitsConverter.spToPx(14f), + textStyle = UiTextStyle.NORMAL, + textColor = colorProvider.getColorOnSurface() + ) + ) + } else { + getTargetFromType(type, reminder)?.let { + UiTextElement( + text = it, + textFormat = UiTextFormat( + fontSize = unitsConverter.spToPx(14f), + textStyle = UiTextStyle.NORMAL, + textColor = colorProvider.getColorOnSurface() + ) + ) + } + } + } + + private fun formatSubTasks(reminder: Reminder): String { + val itemsToShow = reminder.shoppings.filter { !it.isChecked && !it.isDeleted } + return if (itemsToShow.size > 5) { + shopItemsFormatter.format(itemsToShow.take(5)) + "\n..." + } else { + shopItemsFormatter.format(itemsToShow) + } + } + + private fun createSecondaryText( + dueData: UiReminderDueData?, + type: UiReminderType, + data: Reminder + ): UiTextElement? { + return if (type.isGpsType()) { + val place = data.places.firstOrNull() ?: return null + UiTextElement( + text = placeFormatter.format(place), + textFormat = UiTextFormat( + fontSize = unitsConverter.spToPx(14f), + textStyle = UiTextStyle.NORMAL, + textColor = colorProvider.getColorOnSurface() + ) + ) + } else { + if (dueData?.localDateTime == null) { + return null + } + UiTextElement( + text = dueData.formattedDateTime ?: "", + textFormat = UiTextFormat( + fontSize = unitsConverter.spToPx(14f), + textStyle = UiTextStyle.NORMAL, + textColor = colorProvider.getColorOnSurface() + ) + ) + } + } + + private fun createMainText( + type: UiReminderType, + reminder: Reminder + ): UiTextElement { + val summary = reminder.summary + return if (summary.isEmpty()) { + val text = reminder.description ?: getTextFromType(type) + UiTextElement( + text = "($text)", + textFormat = UiTextFormat( + fontSize = unitsConverter.spToPx(16f), + textStyle = UiTextStyle.ITALIC, + textColor = colorProvider.getColorOnSurface().adjustAlpha(75) + ) + ) + } else { + UiTextElement( + text = summary, + textFormat = UiTextFormat( + fontSize = unitsConverter.spToPx(16f), + textStyle = UiTextStyle.NORMAL, + textColor = colorProvider.getColorOnSurface() + ) + ) + } + } + + private fun getTextFromType( + type: UiReminderType + ): String { + return when { + type.isSubTasks() -> textProvider.getText(R.string.builder_sub_tasks) + type.isApp() -> textProvider.getText(R.string.open_app) + type.isLink() -> textProvider.getText(R.string.open_link) + type.isEmail() -> textProvider.getText(R.string.e_mail) + type.isSms() -> textProvider.getText(R.string.send_sms) + type.isCall() -> textProvider.getText(R.string.make_call) + type.isYearly() -> textProvider.getText(R.string.yearly) + type.isByWeekday() -> textProvider.getText(R.string.alarm) + type.isMonthly() -> textProvider.getText(R.string.day_of_month) + type.isTimer() -> textProvider.getText(R.string.timer) + else -> textProvider.getText(R.string.schedule_empty_summary) + } + } + + private fun getTargetFromType( + type: UiReminderType, + reminder: Reminder + ): String? { + return when (val target = uiReminderCommonAdapter.getTarget(reminder, type)) { + is UiSmsTarget -> target.target + is UiCallTarget -> target.target + is UiAppTarget -> target.name ?: target.target + is UiLinkTarget -> target.target + is UiEmailTarget -> { + target.target + "\n" + target.subject + } + + else -> null + } + } + + private fun hasNextRecur(reminder: Reminder): Boolean { + val currentEventTime = dateTimeManager.fromGmtToLocal(reminder.eventTime) + return recurEventManager.getNextAfterDateTime( + currentEventTime, + reminder.recurDataObject + ) != null + } +} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/data/UiReminderListsAdapter.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/data/UiReminderListsAdapter.kt new file mode 100644 index 000000000..e796de605 --- /dev/null +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/data/UiReminderListsAdapter.kt @@ -0,0 +1,79 @@ +package com.elementary.tasks.reminder.lists.data + +import com.elementary.tasks.R +import com.elementary.tasks.core.data.models.Reminder +import com.elementary.tasks.core.data.ui.UiTextElement +import com.elementary.tasks.core.os.ColorProvider +import com.elementary.tasks.core.os.UnitsConverter +import com.elementary.tasks.core.text.UiTextFormat +import com.elementary.tasks.core.text.UiTextStyle +import com.elementary.tasks.core.utils.TextProvider +import com.elementary.tasks.core.utils.datetime.DateTimeManager +import org.threeten.bp.LocalDate +import org.threeten.bp.LocalDateTime + +class UiReminderListsAdapter( + private val uiReminderListAdapter: UiReminderListAdapter, + private val dateTimeManager: DateTimeManager, + private val textProvider: TextProvider, + private val unitsConverter: UnitsConverter, + private val colorProvider: ColorProvider +) { + + fun convert(data: List): List { + val result = mutableListOf() + + val todayDate = dateTimeManager.getHeaderDateFormatted(LocalDate.now()) + val tomorrowDate = dateTimeManager.getHeaderDateFormatted(LocalDate.now().plusDays(1)) + + var previousHeader: String? = null + + data.map { uiReminderListAdapter.create(it) }.forEach { current -> + val header = getHeaderText( + dueDate = current.dueDateTime, + isActive = current.state.isActive, + today = todayDate, + tomorrow = tomorrowDate + ) + if (header != previousHeader) { + result.add(createHeader(header)) + } + result.add(current) + previousHeader = header + } + return result + } + + private fun createHeader(text: String): UiReminderListHeader { + return UiReminderListHeader( + mainText = UiTextElement( + text = text, + textFormat = UiTextFormat( + fontSize = unitsConverter.spToPx(18f), + textStyle = UiTextStyle.BOLD, + textColor = colorProvider.getColorOnBackground() + ) + ) + ) + } + + private fun getHeaderText( + dueDate: LocalDateTime?, + isActive: Boolean, + today: String, + tomorrow: String + ): String { + val date = dueDate?.toLocalDate() + return when { + date != null && isActive -> { + when (val formattedDate = dateTimeManager.getHeaderDateFormatted(date)) { + today -> textProvider.getText(R.string.today) + tomorrow -> textProvider.getText(R.string.tomorrow) + else -> formattedDate + } + } + isActive -> textProvider.getText(R.string.permanent) + else -> textProvider.getText(R.string.disabled) + } + } +} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/removed/ArchiveFragment.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/removed/ArchiveFragment.kt index cef49613e..6a7468f34 100644 --- a/app/src/main/java/com/elementary/tasks/reminder/lists/removed/ArchiveFragment.kt +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/removed/ArchiveFragment.kt @@ -8,19 +8,18 @@ import android.widget.Toast import androidx.recyclerview.widget.LinearLayoutManager import com.elementary.tasks.R import com.elementary.tasks.core.data.Commands -import com.elementary.tasks.core.data.ui.UiReminderList -import com.elementary.tasks.core.data.ui.UiReminderListData -import com.elementary.tasks.core.interfaces.ActionsListener import com.elementary.tasks.core.os.SystemServiceProvider -import com.elementary.tasks.core.utils.ListActions +import com.elementary.tasks.core.os.dp2px import com.elementary.tasks.core.utils.nonNullObserve import com.elementary.tasks.core.utils.ui.SearchMenuHandler import com.elementary.tasks.core.utils.ui.visibleGone +import com.elementary.tasks.core.views.recyclerview.SpaceBetweenItemDecoration import com.elementary.tasks.databinding.FragmentTrashBinding import com.elementary.tasks.navigation.toolbarfragment.BaseToolbarFragment import com.elementary.tasks.reminder.ReminderBuilderLauncher -import com.elementary.tasks.reminder.ReminderResolver -import com.elementary.tasks.reminder.lists.adapter.UiReminderListRecyclerAdapter +import com.elementary.tasks.reminder.lists.ReminderActionResolver +import com.elementary.tasks.reminder.lists.RemindersAdapter +import com.elementary.tasks.reminder.lists.data.UiReminderEventsList import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.viewModel @@ -30,15 +29,31 @@ class ArchiveFragment : BaseToolbarFragment() { private val systemServiceProvider by inject() private val reminderBuilderLauncher by inject() - private val reminderResolver = ReminderResolver( - dialogAction = { return@ReminderResolver dialogues }, - reminderBuilderLauncher = reminderBuilderLauncher, - toggleAction = { }, - deleteAction = { reminder -> viewModel.deleteReminder(reminder) }, - skipAction = { } + private val reminderResolver by lazy { + ReminderActionResolver( + context = requireContext(), + dialogues = dialogues, + reminderBuilderLauncher = reminderBuilderLauncher, + permissionFlow = permissionFlow, + toggleAction = { }, + deleteAction = { viewModel.deleteReminder(it) }, + skipAction = { } + ) + } + + private val remindersAdapter = RemindersAdapter( + isEditable = false, + onItemClicked = { reminderResolver.resolveItemClick(it.id, it.state.isRemoved) }, + onMoreClicked = { view, reminder -> + reminderResolver.resolveItemMore( + view = view, + id = reminder.id, + isRemoved = reminder.state.isRemoved, + actions = reminder.actions + ) + } ) - private var remindersAdapter = UiReminderListRecyclerAdapter(isDark, isEditable = false) private val searchMenuHandler = SearchMenuHandler( systemServiceProvider.provideSearchManager(), R.string.search @@ -75,7 +90,7 @@ class ArchiveFragment : BaseToolbarFragment() { when (it) { Commands.DELETED -> Toast.makeText( requireContext(), - R.string.trash_cleared, + R.string.archive_was_emptied, Toast.LENGTH_SHORT ).show() @@ -85,9 +100,9 @@ class ArchiveFragment : BaseToolbarFragment() { } } - override fun getTitle(): String = getString(R.string.trash) + override fun getTitle(): String = getString(R.string.reminders_archive) - private fun showData(result: List) { + private fun showData(result: List) { remindersAdapter.submitList(result) binding.recyclerView.smoothScrollToPosition(0) reloadView(result.size) @@ -97,24 +112,9 @@ class ArchiveFragment : BaseToolbarFragment() { } private fun initList() { - remindersAdapter.actionsListener = object : ActionsListener { - override fun onAction( - view: View, - position: Int, - t: UiReminderListData?, - actions: ListActions - ) { - if (t != null) { - reminderResolver.resolveAction(view, t, actions) - } - } - } - if (resources.getBoolean(R.bool.is_tablet)) { - binding.recyclerView.layoutManager = LinearLayoutManager(context) - } else { - binding.recyclerView.layoutManager = LinearLayoutManager(context) - } + binding.recyclerView.layoutManager = LinearLayoutManager(context) binding.recyclerView.adapter = remindersAdapter + binding.recyclerView.addItemDecoration(SpaceBetweenItemDecoration(dp2px(8))) reloadView(0) } diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/removed/ArchiveRemindersViewModel.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/removed/ArchiveRemindersViewModel.kt index 53e12a9e8..36ecb62c2 100644 --- a/app/src/main/java/com/elementary/tasks/reminder/lists/removed/ArchiveRemindersViewModel.kt +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/removed/ArchiveRemindersViewModel.kt @@ -5,15 +5,14 @@ import androidx.lifecycle.viewModelScope import com.elementary.tasks.core.arch.BaseProgressViewModel import com.elementary.tasks.core.controller.EventControlFactory import com.elementary.tasks.core.data.Commands -import com.elementary.tasks.core.data.adapter.UiReminderListAdapter import com.elementary.tasks.core.data.dao.ReminderDao import com.elementary.tasks.core.data.livedata.SearchableLiveData import com.elementary.tasks.core.data.models.Reminder -import com.elementary.tasks.core.data.ui.UiReminderListData import com.elementary.tasks.core.utils.Constants import com.elementary.tasks.core.utils.DispatcherProvider import com.elementary.tasks.core.utils.GoogleCalendarUtils import com.elementary.tasks.core.utils.work.WorkerLauncher +import com.elementary.tasks.reminder.lists.data.UiReminderListAdapter import com.elementary.tasks.reminder.work.ReminderDeleteBackupWorker import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -41,9 +40,9 @@ class ArchiveRemindersViewModel( return events.value?.isNotEmpty() ?: false } - fun deleteReminder(reminder: UiReminderListData) { + fun deleteReminder(id: String) { withResult { - reminderDao.getById(reminder.id)?.let { + reminderDao.getById(id)?.let { eventControlFactory.getController(it).disable() reminderDao.delete(it) googleCalendarUtils.deleteEvents(it.uuId) diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/todo/ActiveTodoRemindersViewModel.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/todo/ActiveTodoRemindersViewModel.kt index ac6d9105e..1815b6de6 100644 --- a/app/src/main/java/com/elementary/tasks/reminder/lists/todo/ActiveTodoRemindersViewModel.kt +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/todo/ActiveTodoRemindersViewModel.kt @@ -5,14 +5,13 @@ import androidx.lifecycle.viewModelScope import com.elementary.tasks.core.arch.BaseProgressViewModel import com.elementary.tasks.core.controller.EventControlFactory import com.elementary.tasks.core.data.Commands -import com.elementary.tasks.core.data.adapter.UiReminderListsAdapter import com.elementary.tasks.core.data.dao.ReminderDao import com.elementary.tasks.core.data.livedata.SearchableLiveData import com.elementary.tasks.core.data.models.Reminder -import com.elementary.tasks.core.data.ui.UiReminderList import com.elementary.tasks.core.utils.Constants import com.elementary.tasks.core.utils.DispatcherProvider import com.elementary.tasks.core.utils.work.WorkerLauncher +import com.elementary.tasks.reminder.lists.data.UiReminderListsAdapter import com.elementary.tasks.reminder.work.ReminderSingleBackupWorker import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -37,9 +36,9 @@ class ActiveTodoRemindersViewModel( reminderData.onNewQuery(query) } - fun skip(reminder: UiReminderList) { + fun skip(id: String) { withResult { - val fromDb = reminderDao.getById(reminder.id) + val fromDb = reminderDao.getById(id) if (fromDb != null) { eventControlFactory.getController(fromDb).skip() workerLauncher.startWork( @@ -54,10 +53,10 @@ class ActiveTodoRemindersViewModel( } } - fun toggleReminder(reminder: UiReminderList) { + fun toggleReminder(id: String) { postInProgress(true) viewModelScope.launch(dispatcherProvider.default()) { - val item = reminderDao.getById(reminder.id) ?: return@launch + val item = reminderDao.getById(id) ?: return@launch if (!eventControlFactory.getController(item).onOff()) { postInProgress(false) postCommand(Commands.OUTDATED) @@ -74,9 +73,9 @@ class ActiveTodoRemindersViewModel( } } - fun moveToTrash(reminder: UiReminderList) { + fun moveToTrash(id: String) { withResult { - reminderDao.getById(reminder.id)?.let { + reminderDao.getById(id)?.let { it.isRemoved = true eventControlFactory.getController(it).disable() reminderDao.insert(it) diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/todo/TodoRemindersFragment.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/todo/TodoRemindersFragment.kt index 3bdb02fc9..255ecbc76 100644 --- a/app/src/main/java/com/elementary/tasks/reminder/lists/todo/TodoRemindersFragment.kt +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/todo/TodoRemindersFragment.kt @@ -9,23 +9,20 @@ import com.elementary.tasks.R import com.elementary.tasks.core.analytics.Screen import com.elementary.tasks.core.analytics.ScreenUsedEvent import com.elementary.tasks.core.data.Commands -import com.elementary.tasks.core.data.ui.UiReminderList -import com.elementary.tasks.core.data.ui.UiReminderListActiveGps -import com.elementary.tasks.core.data.ui.UiReminderListData -import com.elementary.tasks.core.interfaces.ActionsListener -import com.elementary.tasks.core.os.Permissions import com.elementary.tasks.core.os.SystemServiceProvider +import com.elementary.tasks.core.os.dp2px import com.elementary.tasks.core.os.toast -import com.elementary.tasks.core.utils.ListActions import com.elementary.tasks.core.utils.nonNullObserve import com.elementary.tasks.core.utils.ui.SearchMenuHandler import com.elementary.tasks.core.utils.ui.ViewUtils import com.elementary.tasks.core.utils.ui.visibleGone +import com.elementary.tasks.core.views.recyclerview.SpaceBetweenItemDecoration import com.elementary.tasks.databinding.FragmentRemindersBinding import com.elementary.tasks.home.eventsview.BaseSubEventsFragment import com.elementary.tasks.reminder.ReminderBuilderLauncher -import com.elementary.tasks.reminder.ReminderResolver -import com.elementary.tasks.reminder.lists.adapter.UiReminderListRecyclerAdapter +import com.elementary.tasks.reminder.lists.ReminderActionResolver +import com.elementary.tasks.reminder.lists.RemindersAdapter +import com.elementary.tasks.reminder.lists.data.UiReminderEventsList import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.viewModel import timber.log.Timber @@ -38,27 +35,32 @@ class TodoRemindersFragment : BaseSubEventsFragment() private var mPosition: Int = 0 - private val reminderResolver = ReminderResolver( - dialogAction = { return@ReminderResolver dialogues }, - reminderBuilderLauncher = reminderBuilderLauncher, - toggleAction = { reminder -> - when (reminder) { - is UiReminderListActiveGps -> { - permissionFlow.askPermission(Permissions.FOREGROUND_SERVICE) { - viewModel.toggleReminder(reminder) - } - } - - else -> { - viewModel.toggleReminder(reminder) - } - } - }, - deleteAction = { reminder -> viewModel.moveToTrash(reminder) }, - skipAction = { reminder -> viewModel.skip(reminder) } + private val reminderResolver by lazy { + ReminderActionResolver( + context = requireContext(), + dialogues = dialogues, + reminderBuilderLauncher = reminderBuilderLauncher, + permissionFlow = permissionFlow, + toggleAction = { viewModel.toggleReminder(it) }, + deleteAction = { viewModel.moveToTrash(it) }, + skipAction = { viewModel.skip(it) } + ) + } + + private val remindersAdapter = RemindersAdapter( + isEditable = true, + onItemClicked = { reminderResolver.resolveItemClick(it.id, it.state.isRemoved) }, + onToggleClicked = { reminderResolver.resolveItemToggle(it.id, it.state.isGps) }, + onMoreClicked = { view, reminder -> + reminderResolver.resolveItemMore( + view = view, + id = reminder.id, + isRemoved = reminder.state.isRemoved, + actions = reminder.actions + ) + } ) - private val remindersAdapter = UiReminderListRecyclerAdapter(true, isEditable = true) private val searchMenuHandler = SearchMenuHandler( systemServiceProvider.provideSearchManager(), R.string.search @@ -102,32 +104,16 @@ class TodoRemindersFragment : BaseSubEventsFragment() } } - private fun showData(result: List) { + private fun showData(result: List) { remindersAdapter.submitList(result) binding.recyclerView.smoothScrollToPosition(0) reloadEmptyView(result.size) } private fun initList() { - remindersAdapter.actionsListener = object : ActionsListener { - override fun onAction( - view: View, - position: Int, - t: UiReminderListData?, - actions: ListActions - ) { - if (t != null) { - mPosition = position - reminderResolver.resolveAction(view, t, actions) - } - } - } - if (resources.getBoolean(R.bool.is_tablet)) { - binding.recyclerView.layoutManager = LinearLayoutManager(context) - } else { - binding.recyclerView.layoutManager = LinearLayoutManager(context) - } + binding.recyclerView.layoutManager = LinearLayoutManager(context) binding.recyclerView.adapter = remindersAdapter + binding.recyclerView.addItemDecoration(SpaceBetweenItemDecoration(dp2px(8))) ViewUtils.listenScrollableView(binding.recyclerView) { if (it) { binding.fab.show() diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/viewholder/HeaderViewHolder.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/viewholder/HeaderViewHolder.kt new file mode 100644 index 000000000..0afe03940 --- /dev/null +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/viewholder/HeaderViewHolder.kt @@ -0,0 +1,20 @@ +package com.elementary.tasks.reminder.lists.viewholder + +import android.view.ViewGroup +import com.elementary.tasks.core.binding.HolderBinding +import com.elementary.tasks.core.text.applyStyles +import com.elementary.tasks.core.utils.ui.inflater +import com.elementary.tasks.databinding.ListItemReminderHeaderBinding +import com.elementary.tasks.reminder.lists.data.UiReminderListHeader + +class HeaderViewHolder( + parent: ViewGroup +) : HolderBinding( + ListItemReminderHeaderBinding.inflate(parent.inflater(), parent, false) +) { + + fun bind(data: UiReminderListHeader) { + binding.dateView.text = data.mainText.text + binding.dateView.applyStyles(data.mainText.textFormat) + } +} diff --git a/app/src/main/java/com/elementary/tasks/reminder/lists/viewholder/ReminderViewHolder.kt b/app/src/main/java/com/elementary/tasks/reminder/lists/viewholder/ReminderViewHolder.kt new file mode 100644 index 000000000..9cdb00e61 --- /dev/null +++ b/app/src/main/java/com/elementary/tasks/reminder/lists/viewholder/ReminderViewHolder.kt @@ -0,0 +1,60 @@ +package com.elementary.tasks.reminder.lists.viewholder + +import android.view.View +import android.view.ViewGroup +import com.elementary.tasks.core.binding.HolderBinding +import com.elementary.tasks.core.text.applyStyles +import com.elementary.tasks.core.utils.ui.gone +import com.elementary.tasks.core.utils.ui.inflater +import com.elementary.tasks.core.utils.ui.visible +import com.elementary.tasks.core.utils.ui.visibleGone +import com.elementary.tasks.databinding.ListItemReminderNewBinding +import com.elementary.tasks.home.scheduleview.viewholder.ScheduleReminderViewHolderCommon +import com.elementary.tasks.reminder.lists.data.UiReminderList + +class ReminderViewHolder( + parent: ViewGroup, + editable: Boolean = true, + showMore: Boolean = true, + private val common: ScheduleReminderViewHolderCommon, + private val onItemClicked: (Int) -> Unit = { }, + private val onToggleClicked: (Int) -> Unit = { }, + private val onMoreClicked: (View, Int) -> Unit = { _, _ -> } +) : HolderBinding( + ListItemReminderNewBinding.inflate(parent.inflater(), parent, false) +) { + + init { + binding.switchWrapper.visibleGone(editable) + binding.buttonMore.visibleGone(showMore) + + binding.itemCard.setOnClickListener { onItemClicked(bindingAdapterPosition) } + binding.switchWrapper.setOnClickListener { onToggleClicked(bindingAdapterPosition) } + binding.buttonMore.setOnClickListener { onMoreClicked(it, bindingAdapterPosition) } + } + + fun bind(data: UiReminderList) { + binding.itemCheck.isChecked = data.state.isActive + + binding.firstLineTextView.text = data.mainText.text + binding.firstLineTextView.applyStyles(data.mainText.textFormat) + + data.secondaryText?.run { + binding.secondLineTextView.visible() + binding.secondLineTextView.text = this.text + binding.secondLineTextView.applyStyles(this.textFormat) + } ?: run { + binding.secondLineTextView.gone() + } + + data.tertiaryText?.run { + binding.thirdLineTextView.visible() + binding.thirdLineTextView.text = this.text + binding.thirdLineTextView.applyStyles(this.textFormat) + } ?: run { + binding.thirdLineTextView.gone() + } + + common.addChips(binding.chipGroup, data.tags) + } +} diff --git a/app/src/main/res/layout/fragment_reminders.xml b/app/src/main/res/layout/fragment_reminders.xml index 27db06b6c..e5f67f803 100644 --- a/app/src/main/res/layout/fragment_reminders.xml +++ b/app/src/main/res/layout/fragment_reminders.xml @@ -48,10 +48,13 @@ android:layout_marginStart="@dimen/list_margin" android:layout_marginEnd="@dimen/list_margin" android:clipToPadding="false" - android:paddingBottom="96dp" + android:paddingStart="16dp" + android:paddingTop="8dp" + android:paddingEnd="16dp" + android:paddingBottom="160dp" android:visibility="visible" tools:itemCount="5" - tools:listitem="@layout/list_item_reminder" /> + tools:listitem="@layout/list_item_reminder_new" /> diff --git a/app/src/main/res/layout/fragment_trash.xml b/app/src/main/res/layout/fragment_trash.xml index 4b40bf1ea..546d8bafb 100644 --- a/app/src/main/res/layout/fragment_trash.xml +++ b/app/src/main/res/layout/fragment_trash.xml @@ -14,7 +14,12 @@ android:layout_marginStart="@dimen/list_margin" android:layout_marginEnd="@dimen/list_margin" tools:itemCount="5" - tools:listitem="@layout/list_item_reminder" /> + android:clipToPadding="false" + android:paddingStart="16dp" + android:paddingTop="8dp" + android:paddingEnd="16dp" + android:paddingBottom="8dp" + tools:listitem="@layout/list_item_reminder_new" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/list_item_reminder_header.xml b/app/src/main/res/layout/list_item_reminder_header.xml index f03c2873a..47ddf3911 100644 --- a/app/src/main/res/layout/list_item_reminder_header.xml +++ b/app/src/main/res/layout/list_item_reminder_header.xml @@ -4,9 +4,8 @@ android:id="@+id/dateView" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="24dp" - android:layout_marginEnd="24dp" - android:layout_marginTop="8dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" android:maxLines="1" android:textAppearance="?textAppearanceTitleMedium" tools:text="21 January 2023" /> diff --git a/app/src/main/res/layout/list_item_reminder_new.xml b/app/src/main/res/layout/list_item_reminder_new.xml new file mode 100644 index 000000000..7710dd61a --- /dev/null +++ b/app/src/main/res/layout/list_item_reminder_new.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/fragment_reminders.xml b/app/src/main/res/menu/fragment_reminders.xml index 20e27c539..7d15c30bf 100644 --- a/app/src/main/res/menu/fragment_reminders.xml +++ b/app/src/main/res/menu/fragment_reminders.xml @@ -20,7 +20,7 @@ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 176500e1f..7fa2341b5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -859,5 +859,8 @@ How many days before the birthday should the notification appear Birthday notification priority Select the time at which the notification should appear + Archive + Archive is empty + Archive was emptied