From 78be89ab744c3c403fa7c9409ae9498e1964eb82 Mon Sep 17 00:00:00 2001 From: ronniedroid Date: Sun, 21 Apr 2024 12:56:58 +0300 Subject: [PATCH 1/9] Added sorting dialog to the timer tab --- .../fossify/clock/activities/MainActivity.kt | 8 +++- .../clock/adapters/ViewPagerAdapter.kt | 4 ++ .../clock/dialogs/ChangeTimerSortDialog.kt | 39 +++++++++++++++++++ .../fossify/clock/fragments/TimerFragment.kt | 18 ++++++++- .../org/fossify/clock/helpers/Config.kt | 4 ++ .../org/fossify/clock/helpers/Constants.kt | 4 +- .../res/layout/dialog_change_timer_sort.xml | 33 ++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 8 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 app/src/main/kotlin/org/fossify/clock/dialogs/ChangeTimerSortDialog.kt create mode 100644 app/src/main/res/layout/dialog_change_timer_sort.xml diff --git a/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt b/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt index 6f33aa8d..1bf8da14 100644 --- a/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt +++ b/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt @@ -129,7 +129,11 @@ class MainActivity : SimpleActivity() { private fun setupOptionsMenu() { binding.mainToolbar.setOnMenuItemClickListener { menuItem -> when (menuItem.itemId) { - R.id.sort -> getViewPagerAdapter()?.showAlarmSortDialog() + R.id.sort -> when (binding.viewPager.currentItem) { + TAB_ALARM -> getViewPagerAdapter()?.showAlarmSortDialog() + TAB_TIMER -> getViewPagerAdapter()?.showTimerSortDialog() + } + R.id.more_apps_from_us -> launchMoreAppsFromUsIntent() R.id.settings -> launchSettings() R.id.about -> launchAbout() @@ -141,7 +145,7 @@ class MainActivity : SimpleActivity() { private fun refreshMenuItems() { binding.mainToolbar.menu.apply { - findItem(R.id.sort).isVisible = binding.viewPager.currentItem == TAB_ALARM + findItem(R.id.sort).isVisible = binding.viewPager.currentItem == TAB_ALARM || binding.viewPager.currentItem == TAB_TIMER findItem(R.id.more_apps_from_us).isVisible = !resources.getBoolean(org.fossify.commons.R.bool.hide_google_relations) } } diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt index 17c8a0f8..5aaad6c6 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt @@ -45,6 +45,10 @@ class ViewPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { (fragments[TAB_ALARM] as? AlarmFragment)?.showSortingDialog() } + fun showTimerSortDialog() { + (fragments[TAB_TIMER] as? TimerFragment)?.showSortingDialog() + } + fun updateClockTabAlarm() { (fragments[TAB_CLOCK] as? ClockFragment)?.updateAlarm() } diff --git a/app/src/main/kotlin/org/fossify/clock/dialogs/ChangeTimerSortDialog.kt b/app/src/main/kotlin/org/fossify/clock/dialogs/ChangeTimerSortDialog.kt new file mode 100644 index 00000000..59d67112 --- /dev/null +++ b/app/src/main/kotlin/org/fossify/clock/dialogs/ChangeTimerSortDialog.kt @@ -0,0 +1,39 @@ +package org.fossify.clock.dialogs + +import org.fossify.clock.R +import org.fossify.clock.databinding.DialogChangeTimerSortBinding +import org.fossify.clock.extensions.config +import org.fossify.clock.helpers.SORT_BY_CREATION_ORDER +import org.fossify.clock.helpers.SORT_BY_TIMER_DURATION +import org.fossify.commons.activities.BaseSimpleActivity +import org.fossify.commons.extensions.getAlertDialogBuilder +import org.fossify.commons.extensions.setupDialogStuff + +class ChangeTimerSortDialog(val activity: BaseSimpleActivity, val callback: () -> Unit) { + private val binding = DialogChangeTimerSortBinding.inflate(activity.layoutInflater).apply { + val activeRadioButton = when (activity.config.timerSort) { + SORT_BY_TIMER_DURATION -> sortingDialogRadioTimerDuration + else -> sortingDialogRadioCreationOrder + } + activeRadioButton.isChecked = true + } + + init { + activity.getAlertDialogBuilder() + .setPositiveButton(org.fossify.commons.R.string.ok) { _, _ -> dialogConfirmed() } + .setNegativeButton(org.fossify.commons.R.string.cancel, null) + .apply { + activity.setupDialogStuff(binding.root, this, org.fossify.commons.R.string.sort_by) + } + } + + private fun dialogConfirmed() { + val sort = when (binding.sortingDialogRadioSorting.checkedRadioButtonId) { + R.id.sorting_dialog_radio_timer_duration -> SORT_BY_TIMER_DURATION + else -> SORT_BY_CREATION_ORDER + } + + activity.config.timerSort = sort + callback() + } +} diff --git a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt index 7c449b7b..4f905b22 100644 --- a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt +++ b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt @@ -10,17 +10,20 @@ import androidx.fragment.app.Fragment import org.fossify.clock.activities.SimpleActivity import org.fossify.clock.adapters.TimerAdapter import org.fossify.clock.databinding.FragmentTimerBinding +import org.fossify.clock.dialogs.ChangeTimerSortDialog import org.fossify.clock.dialogs.EditTimerDialog import org.fossify.clock.extensions.config import org.fossify.clock.extensions.createNewTimer import org.fossify.clock.extensions.timerHelper import org.fossify.clock.helpers.DisabledItemChangeAnimator +import org.fossify.clock.helpers.SORT_BY_TIMER_DURATION import org.fossify.clock.models.Timer import org.fossify.clock.models.TimerEvent import org.fossify.commons.extensions.getProperBackgroundColor import org.fossify.commons.extensions.getProperTextColor import org.fossify.commons.extensions.hideKeyboard import org.fossify.commons.extensions.updateTextColors +import org.fossify.commons.helpers.SORT_BY_DATE_CREATED import org.fossify.commons.models.AlarmSound import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe @@ -85,16 +88,27 @@ class TimerFragment : Fragment() { refreshTimers() } + fun showSortingDialog() { + ChangeTimerSortDialog(activity as SimpleActivity) { + refreshTimers() + } + } + private fun refreshTimers(scrollToLatest: Boolean = false) { activity?.timerHelper?.getTimers { timers -> + var sortedTimers: List = timers + when (requireContext().config.timerSort) { + SORT_BY_TIMER_DURATION -> sortedTimers = timers.sortedBy { it.seconds } + SORT_BY_DATE_CREATED -> sortedTimers = timers.sortedBy { it.id } + } activity?.runOnUiThread { - timerAdapter.submitList(timers) { + timerAdapter.submitList(sortedTimers) { view?.post { if (timerPositionToScrollTo != INVALID_POSITION && timerAdapter.itemCount > timerPositionToScrollTo) { binding.timersList.scrollToPosition(timerPositionToScrollTo) timerPositionToScrollTo = INVALID_POSITION } else if (scrollToLatest) { - binding.timersList.scrollToPosition(timers.lastIndex) + binding.timersList.scrollToPosition(sortedTimers.lastIndex) } } } diff --git a/app/src/main/kotlin/org/fossify/clock/helpers/Config.kt b/app/src/main/kotlin/org/fossify/clock/helpers/Config.kt index 2dbf8cdc..722abf5f 100644 --- a/app/src/main/kotlin/org/fossify/clock/helpers/Config.kt +++ b/app/src/main/kotlin/org/fossify/clock/helpers/Config.kt @@ -57,6 +57,10 @@ class Config(context: Context) : BaseConfig(context) { get() = prefs.getInt(ALARMS_SORT_BY, SORT_BY_CREATION_ORDER) set(alarmSort) = prefs.edit().putInt(ALARMS_SORT_BY, alarmSort).apply() + var timerSort: Int + get() = prefs.getInt(TIMERS_SORT_BY, SORT_BY_CREATION_ORDER) + set(timerSort) = prefs.edit().putInt(TIMERS_SORT_BY, timerSort).apply() + var alarmMaxReminderSecs: Int get() = prefs.getInt(ALARM_MAX_REMINDER_SECS, DEFAULT_MAX_ALARM_REMINDER_SECS) set(alarmMaxReminderSecs) = prefs.edit().putInt(ALARM_MAX_REMINDER_SECS, alarmMaxReminderSecs).apply() diff --git a/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt b/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt index 99fd99c4..7b19bcc5 100644 --- a/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt +++ b/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt @@ -24,6 +24,7 @@ const val ALARM_LAST_CONFIG = "alarm_last_config" const val TIMER_LAST_CONFIG = "timer_last_config" const val INCREASE_VOLUME_GRADUALLY = "increase_volume_gradually" const val ALARMS_SORT_BY = "alarms_sort_by" +const val TIMERS_SORT_BY = "timers_sort_by" const val STOPWATCH_LAPS_SORT_BY = "stopwatch_laps_sort_by" const val WAS_INITIAL_WIDGET_SET_UP = "was_initial_widget_set_up" @@ -62,10 +63,11 @@ const val SORT_BY_LAP = 1 const val SORT_BY_LAP_TIME = 2 const val SORT_BY_TOTAL_TIME = 4 -// alarm sorting +// alarm and timer sorting const val SORT_BY_CREATION_ORDER = 0 const val SORT_BY_ALARM_TIME = 1 const val SORT_BY_DATE_AND_TIME = 2 +const val SORT_BY_TIMER_DURATION = 3 const val TODAY_BIT = -1 const val TOMORROW_BIT = -2 diff --git a/app/src/main/res/layout/dialog_change_timer_sort.xml b/app/src/main/res/layout/dialog_change_timer_sort.xml new file mode 100644 index 00000000..1b6b3ac0 --- /dev/null +++ b/app/src/main/res/layout/dialog_change_timer_sort.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1bcde8ab..aac66a3e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -18,6 +18,7 @@ Swipe right to Dismiss, or left to Snooze. Creation order Alarm time + Timer duration Day and Alarm time Analogue clock Digital clock From c3dda5f5a7db4512bff6174c749f4226e574c0c5 Mon Sep 17 00:00:00 2001 From: ronniedroid Date: Sun, 28 Apr 2024 11:32:35 +0300 Subject: [PATCH 2/9] moved MyRecyclerViewListAdapter to MyRecyclerViewAdapter for consistency --- .../fossify/clock/activities/MainActivity.kt | 8 -- .../fossify/clock/adapters/TimerAdapter.kt | 67 +++++----- .../clock/adapters/ViewPagerAdapter.kt | 4 - .../fossify/clock/fragments/TimerFragment.kt | 67 +++------- .../org/fossify/clock/helpers/TimerHelper.kt | 4 +- app/src/main/res/layout/fragment_timer.xml | 39 +++--- app/src/main/res/layout/item_timer.xml | 122 +++++++++--------- 7 files changed, 128 insertions(+), 183 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt b/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt index 1bf8da14..dd656215 100644 --- a/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt +++ b/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt @@ -154,10 +154,6 @@ class MainActivity : SimpleActivity() { if (intent.extras?.containsKey(OPEN_TAB) == true) { val tabToOpen = intent.getIntExtra(OPEN_TAB, TAB_CLOCK) binding.viewPager.setCurrentItem(tabToOpen, false) - if (tabToOpen == TAB_TIMER) { - val timerId = intent.getIntExtra(TIMER_ID, INVALID_TIMER_ID) - (binding.viewPager.adapter as ViewPagerAdapter).updateTimerPosition(timerId) - } if (tabToOpen == TAB_STOPWATCH) { if (intent.getBooleanExtra(TOGGLE_STOPWATCH, false)) { (binding.viewPager.adapter as ViewPagerAdapter).startStopWatch() @@ -205,10 +201,6 @@ class MainActivity : SimpleActivity() { val tabToOpen = intent.getIntExtra(OPEN_TAB, config.lastUsedViewPagerPage) intent.removeExtra(OPEN_TAB) - if (tabToOpen == TAB_TIMER) { - val timerId = intent.getIntExtra(TIMER_ID, INVALID_TIMER_ID) - viewPagerAdapter.updateTimerPosition(timerId) - } if (tabToOpen == TAB_STOPWATCH) { config.toggleStopwatch = intent.getBooleanExtra(TOGGLE_STOPWATCH, false) diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt index 3c76a798..bbfeb518 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt @@ -3,7 +3,6 @@ package org.fossify.clock.adapters import android.view.Menu import android.view.View import android.view.ViewGroup -import androidx.recyclerview.widget.DiffUtil import me.grantland.widget.AutofitHelper import org.fossify.clock.R import org.fossify.clock.activities.SimpleActivity @@ -14,30 +13,18 @@ import org.fossify.clock.extensions.secondsToMillis import org.fossify.clock.models.Timer import org.fossify.clock.models.TimerEvent import org.fossify.clock.models.TimerState -import org.fossify.commons.adapters.MyRecyclerViewListAdapter +import org.fossify.commons.adapters.MyRecyclerViewAdapter import org.fossify.commons.dialogs.PermissionRequiredDialog import org.fossify.commons.extensions.* import org.fossify.commons.views.MyRecyclerView import org.greenrobot.eventbus.EventBus class TimerAdapter( - private val simpleActivity: SimpleActivity, + activity: SimpleActivity, + var timers: ArrayList, recyclerView: MyRecyclerView, - onRefresh: () -> Unit, - onItemClick: (Timer) -> Unit, -) : MyRecyclerViewListAdapter(simpleActivity, recyclerView, diffUtil, onItemClick, onRefresh) { - - companion object { - private val diffUtil = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: Timer, newItem: Timer): Boolean { - return oldItem.id == newItem.id - } - - override fun areContentsTheSame(oldItem: Timer, newItem: Timer): Boolean { - return oldItem == newItem - } - } - } + itemClick: (Any) -> Unit, +) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) { init { setupDragListener(true) @@ -57,22 +44,13 @@ class TimerAdapter( } } - override fun getSelectableItemCount() = itemCount + override fun getSelectableItemCount() = timers.size override fun getIsItemSelectable(position: Int) = true - override fun getItemSelectionKey(position: Int) = getItem(position).id + override fun getItemSelectionKey(position: Int) = timers.getOrNull(position)?.id - override fun getItemKeyPosition(key: Int): Int { - var position = -1 - for (i in 0 until itemCount) { - if (key == getItem(i).id) { - position = i - break - } - } - return position - } + override fun getItemKeyPosition(key: Int) = timers.indexOfFirst { it.id == key } override fun onActionModeCreated() {} @@ -83,25 +61,38 @@ class TimerAdapter( } override fun onBindViewHolder(holder: ViewHolder, position: Int) { - holder.bindView(getItem(position), true, true) { itemView, _ -> - setupView(itemView, getItem(position)) + val timer = timers[position] + holder.bindView(timer, true, true) { itemView, _ -> + setupView(itemView, timer) } bindViewHolder(holder) } + override fun getItemCount() = timers.size + + fun updateItems(newItems: ArrayList) { + timers = newItems + notifyDataSetChanged() + finishActMode() + } + private fun deleteItems() { + val timersToRemove = ArrayList() val positions = getSelectedItemPositions() - val timersToRemove = positions.map { position -> - getItem(position) + getSelectedItems().forEach { + timersToRemove.add(it) } + timers.removeAll(timersToRemove) removeSelectedItems(positions) timersToRemove.forEach(::deleteTimer) } + private fun getSelectedItems() = timers.filter { selectedKeys.contains(it.id) } as ArrayList + private fun setupView(view: View, timer: Timer) { ItemTimerBinding.bind(view).apply { val isSelected = selectedKeys.contains(timer.id) - timerFrame.isSelected = isSelected + timerHolder.isSelected = isSelected timerLabel.setTextColor(textColor) timerLabel.setHintTextColor(textColor.adjustAlpha(0.7f)) @@ -148,17 +139,17 @@ class TimerAdapter( } else { org.fossify.commons.R.drawable.ic_play_vector } - timerPlayPause.setImageDrawable(simpleActivity.resources.getColoredDrawableWithColor(drawableId, textColor)) + timerPlayPause.setImageDrawable(activity.resources.getColoredDrawableWithColor(drawableId, textColor)) } } private fun resetTimer(timer: Timer) { EventBus.getDefault().post(TimerEvent.Reset(timer.id!!)) - simpleActivity.hideTimerNotification(timer.id!!) + activity.hideTimerNotification(timer.id!!) } private fun deleteTimer(timer: Timer) { EventBus.getDefault().post(TimerEvent.Delete(timer.id!!)) - simpleActivity.hideTimerNotification(timer.id!!) + activity.hideTimerNotification(timer.id!!) } } diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt index 5aaad6c6..02f2f692 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt @@ -61,10 +61,6 @@ class ViewPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { (fragments[TAB_TIMER] as? TimerFragment)?.updateAlarmSound(alarmSound) } - fun updateTimerPosition(timerId: Int) { - (fragments[TAB_TIMER] as? TimerFragment)?.updatePosition(timerId) - } - fun startStopWatch() { (fragments[TAB_STOPWATCH] as? StopwatchFragment)?.startStopWatch() } diff --git a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt index 4f905b22..177bcd40 100644 --- a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt +++ b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt @@ -15,7 +15,6 @@ import org.fossify.clock.dialogs.EditTimerDialog import org.fossify.clock.extensions.config import org.fossify.clock.extensions.createNewTimer import org.fossify.clock.extensions.timerHelper -import org.fossify.clock.helpers.DisabledItemChangeAnimator import org.fossify.clock.helpers.SORT_BY_TIMER_DURATION import org.fossify.clock.models.Timer import org.fossify.clock.models.TimerEvent @@ -30,10 +29,8 @@ import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode class TimerFragment : Fragment() { - private val INVALID_POSITION = -1 + private var timers = ArrayList() private lateinit var binding: FragmentTimerBinding - private lateinit var timerAdapter: TimerAdapter - private var timerPositionToScrollTo = INVALID_POSITION private var currentEditAlarmDialog: EditTimerDialog? = null override fun onCreate(savedInstanceState: Bundle?) { @@ -48,7 +45,7 @@ class TimerFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { binding = FragmentTimerBinding.inflate(inflater, container, false).apply { - timersList.itemAnimator = DisabledItemChangeAnimator() + requireContext().updateTextColors(timerFragment) timerAdd.setOnClickListener { activity?.run { hideKeyboard() @@ -57,7 +54,6 @@ class TimerFragment : Fragment() { } } - initOrUpdateAdapter() refreshTimers() // the initial timer is created asynchronously at first launch, make sure we show it once created @@ -70,21 +66,8 @@ class TimerFragment : Fragment() { return binding.root } - private fun initOrUpdateAdapter() { - if (this::timerAdapter.isInitialized) { - timerAdapter.updatePrimaryColor() - timerAdapter.updateBackgroundColor(requireContext().getProperBackgroundColor()) - timerAdapter.updateTextColor(requireContext().getProperTextColor()) - } else { - timerAdapter = TimerAdapter(requireActivity() as SimpleActivity, binding.timersList, ::refreshTimers, ::openEditTimer) - binding.timersList.adapter = timerAdapter - } - } - override fun onResume() { super.onResume() - requireContext().updateTextColors(binding.root) - initOrUpdateAdapter() refreshTimers() } @@ -94,22 +77,27 @@ class TimerFragment : Fragment() { } } - private fun refreshTimers(scrollToLatest: Boolean = false) { - activity?.timerHelper?.getTimers { timers -> - var sortedTimers: List = timers + private fun refreshTimers() { + activity?.timerHelper?.getTimers { timersFromDB -> + timers = timersFromDB when (requireContext().config.timerSort) { - SORT_BY_TIMER_DURATION -> sortedTimers = timers.sortedBy { it.seconds } - SORT_BY_DATE_CREATED -> sortedTimers = timers.sortedBy { it.id } + SORT_BY_TIMER_DURATION -> timers.sortBy { it.seconds } + SORT_BY_DATE_CREATED -> timers.sortBy { it.id } } activity?.runOnUiThread { - timerAdapter.submitList(sortedTimers) { - view?.post { - if (timerPositionToScrollTo != INVALID_POSITION && timerAdapter.itemCount > timerPositionToScrollTo) { - binding.timersList.scrollToPosition(timerPositionToScrollTo) - timerPositionToScrollTo = INVALID_POSITION - } else if (scrollToLatest) { - binding.timersList.scrollToPosition(sortedTimers.lastIndex) - } + val currAdapter = binding.timersList.adapter + if (currAdapter == null) { + TimerAdapter(activity as SimpleActivity, timers, binding.timersList) { + openEditTimer(it as Timer) + }.apply { + binding.timersList.adapter = this + } + } else { + (currAdapter as TimerAdapter).apply { + updatePrimaryColor() + updateBackgroundColor(requireContext().getProperBackgroundColor()) + updateTextColor(requireContext().getProperTextColor()) + updateItems(this@TimerFragment.timers) } } } @@ -125,21 +113,6 @@ class TimerFragment : Fragment() { currentEditAlarmDialog?.updateAlarmSound(alarmSound) } - fun updatePosition(timerId: Int) { - activity?.timerHelper?.getTimers { timers -> - val position = timers.indexOfFirst { it.id == timerId } - if (position != INVALID_POSITION) { - activity?.runOnUiThread { - if (timerAdapter.itemCount > position) { - binding.timersList.scrollToPosition(position) - } else { - timerPositionToScrollTo = position - } - } - } - } - } - private fun openEditTimer(timer: Timer) { currentEditAlarmDialog = EditTimerDialog(activity as SimpleActivity, timer) { currentEditAlarmDialog = null diff --git a/app/src/main/kotlin/org/fossify/clock/helpers/TimerHelper.kt b/app/src/main/kotlin/org/fossify/clock/helpers/TimerHelper.kt index de7c4353..5882a739 100644 --- a/app/src/main/kotlin/org/fossify/clock/helpers/TimerHelper.kt +++ b/app/src/main/kotlin/org/fossify/clock/helpers/TimerHelper.kt @@ -8,9 +8,9 @@ import org.fossify.commons.helpers.ensureBackgroundThread class TimerHelper(val context: Context) { private val timerDao = context.timerDb - fun getTimers(callback: (timers: List) -> Unit) { + fun getTimers(callback: (timers: ArrayList) -> Unit) { ensureBackgroundThread { - callback.invoke(timerDao.getTimers()) + callback.invoke(timerDao.getTimers() as ArrayList) } } diff --git a/app/src/main/res/layout/fragment_timer.xml b/app/src/main/res/layout/fragment_timer.xml index 664a8a9a..03efda1b 100644 --- a/app/src/main/res/layout/fragment_timer.xml +++ b/app/src/main/res/layout/fragment_timer.xml @@ -1,24 +1,28 @@ - - + android:layout_height="match_parent"> + + + + + android:src="@drawable/ic_plus_vector" /> - + diff --git a/app/src/main/res/layout/item_timer.xml b/app/src/main/res/layout/item_timer.xml index e2b3c5d5..ccc35afb 100644 --- a/app/src/main/res/layout/item_timer.xml +++ b/app/src/main/res/layout/item_timer.xml @@ -1,77 +1,71 @@ - + android:foreground="@drawable/selector" + android:paddingHorizontal="@dimen/activity_margin" + android:paddingVertical="@dimen/medium_margin"> - + android:includeFontPadding="false" + android:maxLines="1" + android:textSize="@dimen/alarm_text_size" + app:layout_constraintEnd_toStartOf="@id/timer_reset" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="00:00" /> - - - + - + - + - - + From 0db49da312302d2c0a11f457b6d6e85c99a7f880 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Sun, 9 Feb 2025 00:56:35 +0530 Subject: [PATCH 3/9] Revert "moved MyRecyclerViewListAdapter to MyRecyclerViewAdapter for consistency" This reverts commit c3dda5f5a7db4512bff6174c749f4226e574c0c5. Originally done to address https://github.com/FossifyOrg/Clock/pull/67#issuecomment-2068748102, reverted for https://github.com/FossifyOrg/Clock/pull/67#issuecomment-2645910511 --- .../fossify/clock/activities/MainActivity.kt | 13 +- .../fossify/clock/adapters/TimerAdapter.kt | 67 +++++----- .../clock/adapters/ViewPagerAdapter.kt | 4 + .../fossify/clock/fragments/TimerFragment.kt | 67 +++++++--- .../org/fossify/clock/helpers/TimerHelper.kt | 4 +- app/src/main/res/layout/fragment_timer.xml | 39 +++--- app/src/main/res/layout/item_timer.xml | 122 +++++++++--------- 7 files changed, 187 insertions(+), 129 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt b/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt index 50570838..5910ff77 100644 --- a/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt +++ b/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt @@ -13,7 +13,10 @@ import org.fossify.clock.BuildConfig import org.fossify.clock.R import org.fossify.clock.adapters.ViewPagerAdapter import org.fossify.clock.databinding.ActivityMainBinding -import org.fossify.clock.extensions.* +import org.fossify.clock.extensions.config +import org.fossify.clock.extensions.getEnabledAlarms +import org.fossify.clock.extensions.rescheduleEnabledAlarms +import org.fossify.clock.extensions.updateWidgets import org.fossify.clock.helpers.* import org.fossify.commons.databinding.BottomTablayoutItemBinding import org.fossify.commons.extensions.* @@ -152,6 +155,10 @@ class MainActivity : SimpleActivity() { if (intent.extras?.containsKey(OPEN_TAB) == true) { val tabToOpen = intent.getIntExtra(OPEN_TAB, TAB_CLOCK) binding.viewPager.setCurrentItem(getTabIndex(tabToOpen), false) + if (tabToOpen == TAB_TIMER) { + val timerId = intent.getIntExtra(TIMER_ID, INVALID_TIMER_ID) + (binding.viewPager.adapter as ViewPagerAdapter).updateTimerPosition(timerId) + } if (tabToOpen == TAB_STOPWATCH) { if (intent.getBooleanExtra(TOGGLE_STOPWATCH, false)) { (binding.viewPager.adapter as ViewPagerAdapter).startStopWatch() @@ -201,6 +208,10 @@ class MainActivity : SimpleActivity() { val tabToOpen = intent.getIntExtra(OPEN_TAB, config.defaultTab) intent.removeExtra(OPEN_TAB) + if (tabToOpen == TAB_TIMER) { + val timerId = intent.getIntExtra(TIMER_ID, INVALID_TIMER_ID) + viewPagerAdapter.updateTimerPosition(timerId) + } if (tabToOpen == TAB_STOPWATCH) { config.toggleStopwatch = intent.getBooleanExtra(TOGGLE_STOPWATCH, false) diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt index bbfeb518..3c76a798 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt @@ -3,6 +3,7 @@ package org.fossify.clock.adapters import android.view.Menu import android.view.View import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil import me.grantland.widget.AutofitHelper import org.fossify.clock.R import org.fossify.clock.activities.SimpleActivity @@ -13,18 +14,30 @@ import org.fossify.clock.extensions.secondsToMillis import org.fossify.clock.models.Timer import org.fossify.clock.models.TimerEvent import org.fossify.clock.models.TimerState -import org.fossify.commons.adapters.MyRecyclerViewAdapter +import org.fossify.commons.adapters.MyRecyclerViewListAdapter import org.fossify.commons.dialogs.PermissionRequiredDialog import org.fossify.commons.extensions.* import org.fossify.commons.views.MyRecyclerView import org.greenrobot.eventbus.EventBus class TimerAdapter( - activity: SimpleActivity, - var timers: ArrayList, + private val simpleActivity: SimpleActivity, recyclerView: MyRecyclerView, - itemClick: (Any) -> Unit, -) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) { + onRefresh: () -> Unit, + onItemClick: (Timer) -> Unit, +) : MyRecyclerViewListAdapter(simpleActivity, recyclerView, diffUtil, onItemClick, onRefresh) { + + companion object { + private val diffUtil = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Timer, newItem: Timer): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: Timer, newItem: Timer): Boolean { + return oldItem == newItem + } + } + } init { setupDragListener(true) @@ -44,13 +57,22 @@ class TimerAdapter( } } - override fun getSelectableItemCount() = timers.size + override fun getSelectableItemCount() = itemCount override fun getIsItemSelectable(position: Int) = true - override fun getItemSelectionKey(position: Int) = timers.getOrNull(position)?.id + override fun getItemSelectionKey(position: Int) = getItem(position).id - override fun getItemKeyPosition(key: Int) = timers.indexOfFirst { it.id == key } + override fun getItemKeyPosition(key: Int): Int { + var position = -1 + for (i in 0 until itemCount) { + if (key == getItem(i).id) { + position = i + break + } + } + return position + } override fun onActionModeCreated() {} @@ -61,38 +83,25 @@ class TimerAdapter( } override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val timer = timers[position] - holder.bindView(timer, true, true) { itemView, _ -> - setupView(itemView, timer) + holder.bindView(getItem(position), true, true) { itemView, _ -> + setupView(itemView, getItem(position)) } bindViewHolder(holder) } - override fun getItemCount() = timers.size - - fun updateItems(newItems: ArrayList) { - timers = newItems - notifyDataSetChanged() - finishActMode() - } - private fun deleteItems() { - val timersToRemove = ArrayList() val positions = getSelectedItemPositions() - getSelectedItems().forEach { - timersToRemove.add(it) + val timersToRemove = positions.map { position -> + getItem(position) } - timers.removeAll(timersToRemove) removeSelectedItems(positions) timersToRemove.forEach(::deleteTimer) } - private fun getSelectedItems() = timers.filter { selectedKeys.contains(it.id) } as ArrayList - private fun setupView(view: View, timer: Timer) { ItemTimerBinding.bind(view).apply { val isSelected = selectedKeys.contains(timer.id) - timerHolder.isSelected = isSelected + timerFrame.isSelected = isSelected timerLabel.setTextColor(textColor) timerLabel.setHintTextColor(textColor.adjustAlpha(0.7f)) @@ -139,17 +148,17 @@ class TimerAdapter( } else { org.fossify.commons.R.drawable.ic_play_vector } - timerPlayPause.setImageDrawable(activity.resources.getColoredDrawableWithColor(drawableId, textColor)) + timerPlayPause.setImageDrawable(simpleActivity.resources.getColoredDrawableWithColor(drawableId, textColor)) } } private fun resetTimer(timer: Timer) { EventBus.getDefault().post(TimerEvent.Reset(timer.id!!)) - activity.hideTimerNotification(timer.id!!) + simpleActivity.hideTimerNotification(timer.id!!) } private fun deleteTimer(timer: Timer) { EventBus.getDefault().post(TimerEvent.Delete(timer.id!!)) - activity.hideTimerNotification(timer.id!!) + simpleActivity.hideTimerNotification(timer.id!!) } } diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt index 78bdc99c..99e6ac66 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt @@ -61,6 +61,10 @@ class ViewPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { (fragments[TAB_TIMER_INDEX] as? TimerFragment)?.updateAlarmSound(alarmSound) } + fun updateTimerPosition(timerId: Int) { + (fragments[TAB_TIMER] as? TimerFragment)?.updatePosition(timerId) + } + fun startStopWatch() { (fragments[TAB_STOPWATCH_INDEX] as? StopwatchFragment)?.startStopWatch() } diff --git a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt index 177bcd40..4f905b22 100644 --- a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt +++ b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt @@ -15,6 +15,7 @@ import org.fossify.clock.dialogs.EditTimerDialog import org.fossify.clock.extensions.config import org.fossify.clock.extensions.createNewTimer import org.fossify.clock.extensions.timerHelper +import org.fossify.clock.helpers.DisabledItemChangeAnimator import org.fossify.clock.helpers.SORT_BY_TIMER_DURATION import org.fossify.clock.models.Timer import org.fossify.clock.models.TimerEvent @@ -29,8 +30,10 @@ import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode class TimerFragment : Fragment() { - private var timers = ArrayList() + private val INVALID_POSITION = -1 private lateinit var binding: FragmentTimerBinding + private lateinit var timerAdapter: TimerAdapter + private var timerPositionToScrollTo = INVALID_POSITION private var currentEditAlarmDialog: EditTimerDialog? = null override fun onCreate(savedInstanceState: Bundle?) { @@ -45,7 +48,7 @@ class TimerFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { binding = FragmentTimerBinding.inflate(inflater, container, false).apply { - requireContext().updateTextColors(timerFragment) + timersList.itemAnimator = DisabledItemChangeAnimator() timerAdd.setOnClickListener { activity?.run { hideKeyboard() @@ -54,6 +57,7 @@ class TimerFragment : Fragment() { } } + initOrUpdateAdapter() refreshTimers() // the initial timer is created asynchronously at first launch, make sure we show it once created @@ -66,8 +70,21 @@ class TimerFragment : Fragment() { return binding.root } + private fun initOrUpdateAdapter() { + if (this::timerAdapter.isInitialized) { + timerAdapter.updatePrimaryColor() + timerAdapter.updateBackgroundColor(requireContext().getProperBackgroundColor()) + timerAdapter.updateTextColor(requireContext().getProperTextColor()) + } else { + timerAdapter = TimerAdapter(requireActivity() as SimpleActivity, binding.timersList, ::refreshTimers, ::openEditTimer) + binding.timersList.adapter = timerAdapter + } + } + override fun onResume() { super.onResume() + requireContext().updateTextColors(binding.root) + initOrUpdateAdapter() refreshTimers() } @@ -77,27 +94,22 @@ class TimerFragment : Fragment() { } } - private fun refreshTimers() { - activity?.timerHelper?.getTimers { timersFromDB -> - timers = timersFromDB + private fun refreshTimers(scrollToLatest: Boolean = false) { + activity?.timerHelper?.getTimers { timers -> + var sortedTimers: List = timers when (requireContext().config.timerSort) { - SORT_BY_TIMER_DURATION -> timers.sortBy { it.seconds } - SORT_BY_DATE_CREATED -> timers.sortBy { it.id } + SORT_BY_TIMER_DURATION -> sortedTimers = timers.sortedBy { it.seconds } + SORT_BY_DATE_CREATED -> sortedTimers = timers.sortedBy { it.id } } activity?.runOnUiThread { - val currAdapter = binding.timersList.adapter - if (currAdapter == null) { - TimerAdapter(activity as SimpleActivity, timers, binding.timersList) { - openEditTimer(it as Timer) - }.apply { - binding.timersList.adapter = this - } - } else { - (currAdapter as TimerAdapter).apply { - updatePrimaryColor() - updateBackgroundColor(requireContext().getProperBackgroundColor()) - updateTextColor(requireContext().getProperTextColor()) - updateItems(this@TimerFragment.timers) + timerAdapter.submitList(sortedTimers) { + view?.post { + if (timerPositionToScrollTo != INVALID_POSITION && timerAdapter.itemCount > timerPositionToScrollTo) { + binding.timersList.scrollToPosition(timerPositionToScrollTo) + timerPositionToScrollTo = INVALID_POSITION + } else if (scrollToLatest) { + binding.timersList.scrollToPosition(sortedTimers.lastIndex) + } } } } @@ -113,6 +125,21 @@ class TimerFragment : Fragment() { currentEditAlarmDialog?.updateAlarmSound(alarmSound) } + fun updatePosition(timerId: Int) { + activity?.timerHelper?.getTimers { timers -> + val position = timers.indexOfFirst { it.id == timerId } + if (position != INVALID_POSITION) { + activity?.runOnUiThread { + if (timerAdapter.itemCount > position) { + binding.timersList.scrollToPosition(position) + } else { + timerPositionToScrollTo = position + } + } + } + } + } + private fun openEditTimer(timer: Timer) { currentEditAlarmDialog = EditTimerDialog(activity as SimpleActivity, timer) { currentEditAlarmDialog = null diff --git a/app/src/main/kotlin/org/fossify/clock/helpers/TimerHelper.kt b/app/src/main/kotlin/org/fossify/clock/helpers/TimerHelper.kt index 5882a739..de7c4353 100644 --- a/app/src/main/kotlin/org/fossify/clock/helpers/TimerHelper.kt +++ b/app/src/main/kotlin/org/fossify/clock/helpers/TimerHelper.kt @@ -8,9 +8,9 @@ import org.fossify.commons.helpers.ensureBackgroundThread class TimerHelper(val context: Context) { private val timerDao = context.timerDb - fun getTimers(callback: (timers: ArrayList) -> Unit) { + fun getTimers(callback: (timers: List) -> Unit) { ensureBackgroundThread { - callback.invoke(timerDao.getTimers() as ArrayList) + callback.invoke(timerDao.getTimers()) } } diff --git a/app/src/main/res/layout/fragment_timer.xml b/app/src/main/res/layout/fragment_timer.xml index 03efda1b..664a8a9a 100644 --- a/app/src/main/res/layout/fragment_timer.xml +++ b/app/src/main/res/layout/fragment_timer.xml @@ -1,28 +1,24 @@ - - - - - - + android:layout_height="match_parent" + android:clipToPadding="false" + android:paddingBottom="@dimen/fab_list_bottom_padding" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:itemCount="3" + tools:listitem="@layout/item_timer" /> + android:contentDescription="@string/new_timer" + android:src="@drawable/ic_plus_vector" + app:backgroundTint="@color/color_primary" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:rippleColor="@color/pressed_item_foreground" /> - + diff --git a/app/src/main/res/layout/item_timer.xml b/app/src/main/res/layout/item_timer.xml index ccc35afb..e2b3c5d5 100644 --- a/app/src/main/res/layout/item_timer.xml +++ b/app/src/main/res/layout/item_timer.xml @@ -1,71 +1,77 @@ - + android:foreground="@drawable/selector"> - + android:paddingStart="@dimen/activity_margin" + android:paddingTop="@dimen/medium_margin" + android:paddingBottom="@dimen/activity_margin"> - + + + - + - + - + + From ad2702c5eea9c0a88418f96d94202591a8a38260 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Sun, 9 Feb 2025 01:01:37 +0530 Subject: [PATCH 4/9] Use new constants for tabs --- .../main/kotlin/org/fossify/clock/activities/MainActivity.kt | 4 ++-- .../kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt b/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt index 5910ff77..10a6c12a 100644 --- a/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt +++ b/app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt @@ -131,8 +131,8 @@ class MainActivity : SimpleActivity() { binding.mainToolbar.setOnMenuItemClickListener { menuItem -> when (menuItem.itemId) { R.id.sort -> when (binding.viewPager.currentItem) { - TAB_ALARM -> getViewPagerAdapter()?.showAlarmSortDialog() - TAB_TIMER -> getViewPagerAdapter()?.showTimerSortDialog() + TAB_ALARM_INDEX -> getViewPagerAdapter()?.showAlarmSortDialog() + TAB_TIMER_INDEX -> getViewPagerAdapter()?.showTimerSortDialog() } R.id.more_apps_from_us -> launchMoreAppsFromUsIntent() diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt index 99e6ac66..81e5c3dc 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt @@ -46,7 +46,7 @@ class ViewPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { } fun showTimerSortDialog() { - (fragments[TAB_TIMER] as? TimerFragment)?.showSortingDialog() + (fragments[TAB_TIMER_INDEX] as? TimerFragment)?.showSortingDialog() } fun updateClockTabAlarm() { From 02e6c885a9f04292e63bc6dd6a05698d9f3bce79 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Wed, 26 Feb 2025 15:26:34 +0530 Subject: [PATCH 5/9] Minor code improvement --- .../fossify/clock/fragments/TimerFragment.kt | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt index 4f905b22..c258cc39 100644 --- a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt +++ b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt @@ -30,7 +30,6 @@ import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode class TimerFragment : Fragment() { - private val INVALID_POSITION = -1 private lateinit var binding: FragmentTimerBinding private lateinit var timerAdapter: TimerAdapter private var timerPositionToScrollTo = INVALID_POSITION @@ -46,7 +45,11 @@ class TimerFragment : Fragment() { super.onDestroy() } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { binding = FragmentTimerBinding.inflate(inflater, container, false).apply { timersList.itemAnimator = DisabledItemChangeAnimator() timerAdd.setOnClickListener { @@ -76,7 +79,12 @@ class TimerFragment : Fragment() { timerAdapter.updateBackgroundColor(requireContext().getProperBackgroundColor()) timerAdapter.updateTextColor(requireContext().getProperTextColor()) } else { - timerAdapter = TimerAdapter(requireActivity() as SimpleActivity, binding.timersList, ::refreshTimers, ::openEditTimer) + timerAdapter = TimerAdapter( + simpleActivity = requireActivity() as SimpleActivity, + recyclerView = binding.timersList, + onRefresh = ::refreshTimers, + onItemClick = ::openEditTimer + ) binding.timersList.adapter = timerAdapter } } @@ -96,11 +104,12 @@ class TimerFragment : Fragment() { private fun refreshTimers(scrollToLatest: Boolean = false) { activity?.timerHelper?.getTimers { timers -> - var sortedTimers: List = timers - when (requireContext().config.timerSort) { - SORT_BY_TIMER_DURATION -> sortedTimers = timers.sortedBy { it.seconds } - SORT_BY_DATE_CREATED -> sortedTimers = timers.sortedBy { it.id } + val sortedTimers = when (requireContext().config.timerSort) { + SORT_BY_TIMER_DURATION -> timers.sortedBy { it.seconds } + SORT_BY_DATE_CREATED -> timers.sortedBy { it.id } + else -> timers } + activity?.runOnUiThread { timerAdapter.submitList(sortedTimers) { view?.post { @@ -147,3 +156,5 @@ class TimerFragment : Fragment() { } } } + +private const val INVALID_POSITION = -1 From 0b6d5c6139c4deaeed84f0a3f84a1ca30bc80aa4 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Fri, 28 Feb 2025 14:58:26 +0530 Subject: [PATCH 6/9] Use proper index for updating position --- .../main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt index 81e5c3dc..80547d80 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt @@ -62,7 +62,7 @@ class ViewPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { } fun updateTimerPosition(timerId: Int) { - (fragments[TAB_TIMER] as? TimerFragment)?.updatePosition(timerId) + (fragments[TAB_TIMER_INDEX] as? TimerFragment)?.updatePosition(timerId) } fun startStopWatch() { From f35767c06d44a5e04e48f6a5cd1ce1e261a576da Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Fri, 28 Feb 2025 15:01:03 +0530 Subject: [PATCH 7/9] Apply sorting before fetching position --- .../fossify/clock/fragments/TimerFragment.kt | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt index c258cc39..f67fda9c 100644 --- a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt +++ b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt @@ -102,7 +102,7 @@ class TimerFragment : Fragment() { } } - private fun refreshTimers(scrollToLatest: Boolean = false) { + private fun getSortedTimers(callback: (List) -> Unit) { activity?.timerHelper?.getTimers { timers -> val sortedTimers = when (requireContext().config.timerSort) { SORT_BY_TIMER_DURATION -> timers.sortedBy { it.seconds } @@ -111,14 +111,21 @@ class TimerFragment : Fragment() { } activity?.runOnUiThread { - timerAdapter.submitList(sortedTimers) { - view?.post { - if (timerPositionToScrollTo != INVALID_POSITION && timerAdapter.itemCount > timerPositionToScrollTo) { - binding.timersList.scrollToPosition(timerPositionToScrollTo) - timerPositionToScrollTo = INVALID_POSITION - } else if (scrollToLatest) { - binding.timersList.scrollToPosition(sortedTimers.lastIndex) - } + callback(sortedTimers) + } + } + } + + private fun refreshTimers() { + getSortedTimers { timers -> + timerAdapter.submitList(timers.toMutableList()) { + view?.post { + if ( + timerPositionToScrollTo != INVALID_POSITION && + timerAdapter.itemCount > timerPositionToScrollTo + ) { + binding.timersList.smoothScrollToPosition(timerPositionToScrollTo) + timerPositionToScrollTo = INVALID_POSITION } } } @@ -135,15 +142,13 @@ class TimerFragment : Fragment() { } fun updatePosition(timerId: Int) { - activity?.timerHelper?.getTimers { timers -> + getSortedTimers { timers -> val position = timers.indexOfFirst { it.id == timerId } if (position != INVALID_POSITION) { - activity?.runOnUiThread { - if (timerAdapter.itemCount > position) { - binding.timersList.scrollToPosition(position) - } else { - timerPositionToScrollTo = position - } + if (timerAdapter.itemCount > position) { + binding.timersList.smoothScrollToPosition(position) + } else { + timerPositionToScrollTo = position } } } From de176e8e4538cdc6c2fcbdac7f9c6ea44ceb2536 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Fri, 28 Feb 2025 17:13:25 +0530 Subject: [PATCH 8/9] Avoid jumping around when items are sorted --- .../fossify/clock/adapters/TimerAdapter.kt | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt index 3c76a798..33113738 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt @@ -16,7 +16,12 @@ import org.fossify.clock.models.TimerEvent import org.fossify.clock.models.TimerState import org.fossify.commons.adapters.MyRecyclerViewListAdapter import org.fossify.commons.dialogs.PermissionRequiredDialog -import org.fossify.commons.extensions.* +import org.fossify.commons.extensions.adjustAlpha +import org.fossify.commons.extensions.applyColorFilter +import org.fossify.commons.extensions.beInvisibleIf +import org.fossify.commons.extensions.getColoredDrawableWithColor +import org.fossify.commons.extensions.getFormattedDuration +import org.fossify.commons.extensions.openNotificationSettings import org.fossify.commons.views.MyRecyclerView import org.greenrobot.eventbus.EventBus @@ -41,6 +46,24 @@ class TimerAdapter( init { setupDragListener(true) + setHasStableIds(true) + } + + override fun getItemId(position: Int): Long { + return getItem(position).id!!.toLong() + } + + override fun submitList(list: MutableList?, commitCallback: Runnable?) { + val layoutManager = recyclerView.layoutManager!! + val recyclerViewState = layoutManager.onSaveInstanceState() + super.submitList(list) { + layoutManager.onRestoreInstanceState(recyclerViewState) + commitCallback?.run() + } + } + + override fun submitList(list: MutableList?) { + submitList(list, null) } override fun getActionMenuId() = R.menu.cab_alarms From cb73377da19115b377816653e39e4ba1a15b67be Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Fri, 28 Feb 2025 17:30:56 +0530 Subject: [PATCH 9/9] Disable sorting animations for now It requires more polishing and animations need to be added in other lists before it can be enabled. --- .../fossify/clock/fragments/TimerFragment.kt | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt index f67fda9c..8f719746 100644 --- a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt +++ b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt @@ -98,7 +98,9 @@ class TimerFragment : Fragment() { fun showSortingDialog() { ChangeTimerSortDialog(activity as SimpleActivity) { - refreshTimers() + refreshTimers( + animate = false // disable sorting animations for now. + ) } } @@ -116,16 +118,26 @@ class TimerFragment : Fragment() { } } - private fun refreshTimers() { + private fun refreshTimers(animate: Boolean = true) { getSortedTimers { timers -> - timerAdapter.submitList(timers.toMutableList()) { - view?.post { - if ( - timerPositionToScrollTo != INVALID_POSITION && - timerAdapter.itemCount > timerPositionToScrollTo - ) { - binding.timersList.smoothScrollToPosition(timerPositionToScrollTo) - timerPositionToScrollTo = INVALID_POSITION + with(binding.timersList) { + val originalAnimator = itemAnimator + if (!animate) { + itemAnimator = null + } + + timerAdapter.submitList(timers.toMutableList()) { + view?.post { + if (timerPositionToScrollTo != INVALID_POSITION && + timerAdapter.itemCount > timerPositionToScrollTo + ) { + smoothScrollToPosition(timerPositionToScrollTo) + timerPositionToScrollTo = INVALID_POSITION + } + + if (!animate) { + itemAnimator = originalAnimator + } } } }