From 78be89ab744c3c403fa7c9409ae9498e1964eb82 Mon Sep 17 00:00:00 2001 From: ronniedroid Date: Sun, 21 Apr 2024 12:56:58 +0300 Subject: [PATCH 01/27] 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 ab2b8463f60128cd899b01eb6b08435cae788e33 Mon Sep 17 00:00:00 2001 From: ronniedroid Date: Thu, 25 Apr 2024 12:26:49 +0300 Subject: [PATCH 02/27] added manual sorting to the alarms tab --- .../fossify/clock/adapters/AlarmsAdapter.kt | 53 +++++++++++++++++-- .../clock/dialogs/ChangeAlarmSortDialog.kt | 3 ++ .../fossify/clock/extensions/MutableList.kt | 7 +++ .../fossify/clock/fragments/AlarmFragment.kt | 21 ++++++++ .../org/fossify/clock/helpers/Config.kt | 4 ++ .../org/fossify/clock/helpers/Constants.kt | 1 + .../res/layout/dialog_change_alarm_sort.xml | 8 +++ app/src/main/res/layout/item_alarm.xml | 19 +++++-- app/src/main/res/values/dimens.xml | 1 + app/src/main/res/values/strings.xml | 1 + 10 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 app/src/main/kotlin/org/fossify/clock/extensions/MutableList.kt diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt index 49d85ae7..7fcf1737 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt @@ -1,8 +1,13 @@ package org.fossify.clock.adapters +import android.annotation.SuppressLint +import android.util.Log import android.view.Menu +import android.view.MotionEvent import android.view.View import android.view.ViewGroup +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView import org.fossify.clock.R import org.fossify.clock.activities.SimpleActivity import org.fossify.clock.databinding.ItemAlarmBinding @@ -14,17 +19,32 @@ import org.fossify.clock.interfaces.ToggleAlarmInterface import org.fossify.clock.models.Alarm import org.fossify.commons.adapters.MyRecyclerViewAdapter import org.fossify.commons.dialogs.ConfirmationDialog +import org.fossify.commons.extensions.applyColorFilter import org.fossify.commons.extensions.beVisibleIf import org.fossify.commons.extensions.toast +import org.fossify.commons.helpers.SORT_BY_CUSTOM +import org.fossify.commons.interfaces.ItemMoveCallback +import org.fossify.commons.interfaces.ItemTouchHelperContract +import org.fossify.commons.interfaces.StartReorderDragListener import org.fossify.commons.views.MyRecyclerView class AlarmsAdapter( activity: SimpleActivity, var alarms: ArrayList, val toggleAlarmInterface: ToggleAlarmInterface, recyclerView: MyRecyclerView, itemClick: (Any) -> Unit, -) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) { +) : MyRecyclerViewAdapter(activity, recyclerView, itemClick), ItemTouchHelperContract { + private var startReorderDragListener: StartReorderDragListener init { setupDragListener(true) + + val touchHelper = ItemTouchHelper(ItemMoveCallback(this)) + touchHelper.attachToRecyclerView(recyclerView) + + startReorderDragListener = object : StartReorderDragListener { + override fun requestDrag(viewHolder: RecyclerView.ViewHolder) { + touchHelper.startDrag(viewHolder) + } + } } override fun getActionMenuId() = R.menu.cab_alarms @@ -53,14 +73,18 @@ class AlarmsAdapter( override fun onActionModeDestroyed() {} + override fun onRowClear(myViewHolder: ViewHolder?) {} + + override fun onRowSelected(myViewHolder: ViewHolder?) {} + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return createViewHolder(ItemAlarmBinding.inflate(layoutInflater, parent, false).root) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val alarm = alarms[position] - holder.bindView(alarm, true, true) { itemView, layoutPosition -> - setupView(itemView, alarm) + holder.bindView(alarm, true, true) { itemView, _ -> + setupView(itemView, alarm, holder) } bindViewHolder(holder) } @@ -87,10 +111,19 @@ class AlarmsAdapter( private fun getSelectedItems() = alarms.filter { selectedKeys.contains(it.id) } as ArrayList - private fun setupView(view: View, alarm: Alarm) { + @SuppressLint("ClickableViewAccessibility") + private fun setupView(view: View, alarm: Alarm, holder: ViewHolder) { val isSelected = selectedKeys.contains(alarm.id) ItemAlarmBinding.bind(view).apply { alarmHolder.isSelected = isSelected + alarmDragHandle.beVisibleIf(activity.config.alarmSort == SORT_BY_CUSTOM) + alarmDragHandle.applyColorFilter(textColor) + alarmDragHandle.setOnTouchListener { _, event -> + if (event.action == MotionEvent.ACTION_DOWN) { + startReorderDragListener.requestDrag(holder) + } + false + } alarmTime.text = activity.getFormattedTime(alarm.timeInMinutes * 60, false, true) alarmTime.setTextColor(textColor) @@ -137,4 +170,16 @@ class AlarmsAdapter( } } } + + override fun onRowMoved(fromPosition: Int, toPosition: Int) { + alarms.swap(fromPosition, toPosition) + notifyItemMoved(fromPosition, toPosition) + saveAlarmsCustomOrder(alarms) + } + + private fun saveAlarmsCustomOrder(alarms: ArrayList) { + val alarmsCustomSortingIds = alarms.map { it.id } + + activity.config.alarmsCustomSorting = alarmsCustomSortingIds.joinToString { it.toString() } + } } diff --git a/app/src/main/kotlin/org/fossify/clock/dialogs/ChangeAlarmSortDialog.kt b/app/src/main/kotlin/org/fossify/clock/dialogs/ChangeAlarmSortDialog.kt index 073d00e3..efd25852 100644 --- a/app/src/main/kotlin/org/fossify/clock/dialogs/ChangeAlarmSortDialog.kt +++ b/app/src/main/kotlin/org/fossify/clock/dialogs/ChangeAlarmSortDialog.kt @@ -9,12 +9,14 @@ import org.fossify.clock.helpers.SORT_BY_DATE_AND_TIME import org.fossify.commons.activities.BaseSimpleActivity import org.fossify.commons.extensions.getAlertDialogBuilder import org.fossify.commons.extensions.setupDialogStuff +import org.fossify.commons.helpers.SORT_BY_CUSTOM class ChangeAlarmSortDialog(val activity: BaseSimpleActivity, val callback: () -> Unit) { private val binding = DialogChangeAlarmSortBinding.inflate(activity.layoutInflater).apply { val activeRadioButton = when (activity.config.alarmSort) { SORT_BY_ALARM_TIME -> sortingDialogRadioAlarmTime SORT_BY_DATE_AND_TIME -> sortingDialogRadioDayAndTime + SORT_BY_CUSTOM -> sortingDialogRadioCustom else -> sortingDialogRadioCreationOrder } activeRadioButton.isChecked = true @@ -33,6 +35,7 @@ class ChangeAlarmSortDialog(val activity: BaseSimpleActivity, val callback: () - val sort = when (binding.sortingDialogRadioSorting.checkedRadioButtonId) { R.id.sorting_dialog_radio_alarm_time -> SORT_BY_ALARM_TIME R.id.sorting_dialog_radio_day_and_time -> SORT_BY_DATE_AND_TIME + R.id.sorting_dialog_radio_custom -> SORT_BY_CUSTOM else -> SORT_BY_CREATION_ORDER } diff --git a/app/src/main/kotlin/org/fossify/clock/extensions/MutableList.kt b/app/src/main/kotlin/org/fossify/clock/extensions/MutableList.kt new file mode 100644 index 00000000..9ca4e24f --- /dev/null +++ b/app/src/main/kotlin/org/fossify/clock/extensions/MutableList.kt @@ -0,0 +1,7 @@ +package org.fossify.clock.extensions + +fun MutableList.swap(index1: Int, index2: Int) { + this[index1] = this[index2].also { + this[index2] = this[index1] + } +} diff --git a/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt b/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt index de83517e..6c58af47 100644 --- a/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt +++ b/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt @@ -1,6 +1,7 @@ package org.fossify.clock.fragments import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -20,6 +21,7 @@ import org.fossify.commons.extensions.getProperBackgroundColor import org.fossify.commons.extensions.getProperTextColor import org.fossify.commons.extensions.toast import org.fossify.commons.extensions.updateTextColors +import org.fossify.commons.helpers.SORT_BY_CUSTOM import org.fossify.commons.helpers.SORT_BY_DATE_CREATED import org.fossify.commons.helpers.ensureBackgroundThread import org.fossify.commons.models.AlarmSound @@ -84,6 +86,25 @@ class AlarmFragment : Fragment(), ToggleAlarmInterface { }.thenBy { it.timeInMinutes }) + + SORT_BY_CUSTOM -> { + val customAlarmsSortOrderString = activity?.config?.alarmsCustomSorting + if (customAlarmsSortOrderString == "") { + alarms.sortBy { it.id } + } else { + val customAlarmsSortOrder: List = customAlarmsSortOrderString?.split(", ")?.map { it.toInt() }!! + val alarmsIdValueMap = alarms.associateBy { it.id } + + val sortedAlarms: ArrayList = ArrayList() + customAlarmsSortOrder.map { id -> + if (alarmsIdValueMap[id] != null) { + sortedAlarms.add(alarmsIdValueMap[id] as Alarm) + } + } + + alarms = (sortedAlarms + alarms.filter { it !in sortedAlarms }) as ArrayList + } + } } context?.getEnabledAlarms { enabledAlarms -> if (enabledAlarms.isNullOrEmpty()) { 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 722abf5f..dfc21c2a 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 alarmsCustomSorting: String + get() = prefs.getString(ALARMS_CUSTOM_SORTING, "")!! + set(alarmsCustomSorting) = prefs.edit().putString(ALARMS_CUSTOM_SORTING, alarmsCustomSorting).apply() + var timerSort: Int get() = prefs.getInt(TIMERS_SORT_BY, SORT_BY_CREATION_ORDER) set(timerSort) = prefs.edit().putInt(TIMERS_SORT_BY, timerSort).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 7b19bcc5..8264da30 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 ALARMS_CUSTOM_SORTING = "alarms_custom_sorting" 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" diff --git a/app/src/main/res/layout/dialog_change_alarm_sort.xml b/app/src/main/res/layout/dialog_change_alarm_sort.xml index 41d9db1d..f4cce66d 100644 --- a/app/src/main/res/layout/dialog_change_alarm_sort.xml +++ b/app/src/main/res/layout/dialog_change_alarm_sort.xml @@ -37,5 +37,13 @@ android:paddingBottom="@dimen/medium_margin" android:text="@string/sort_by_day_and_alarm_time" /> + + diff --git a/app/src/main/res/layout/item_alarm.xml b/app/src/main/res/layout/item_alarm.xml index 9edabf0e..c1fb26ec 100644 --- a/app/src/main/res/layout/item_alarm.xml +++ b/app/src/main/res/layout/item_alarm.xml @@ -12,6 +12,19 @@ android:paddingHorizontal="@dimen/activity_margin" android:paddingVertical="@dimen/medium_margin"> + + @@ -35,7 +48,7 @@ android:paddingHorizontal="@dimen/tiny_margin" android:textSize="@dimen/bigger_text_size" app:layout_constraintEnd_toStartOf="@id/alarm_switch" - app:layout_constraintStart_toStartOf="parent" + app:layout_constraintStart_toEndOf="@id/alarm_drag_handle" app:layout_constraintTop_toBottomOf="@id/alarm_time" tools:text="Mon, Tue, Wed, Thu, Fri" /> @@ -49,7 +62,7 @@ android:paddingHorizontal="@dimen/tiny_margin" android:textSize="@dimen/bigger_text_size" app:layout_constraintEnd_toStartOf="@id/alarm_switch" - app:layout_constraintStart_toStartOf="parent" + app:layout_constraintStart_toEndOf="@id/alarm_drag_handle" app:layout_constraintTop_toBottomOf="@id/alarm_days" tools:text="Good morning!" /> diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index a6255c42..d700694b 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -11,6 +11,7 @@ 50dp 56dp 24dp + 40dp 70sp 60sp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index aac66a3e..21cc9d9d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,6 +33,7 @@ Add timer Upcoming alarm Early alarm dismissal + Reorder items by dragging Timers are running From c3dda5f5a7db4512bff6174c749f4226e574c0c5 Mon Sep 17 00:00:00 2001 From: ronniedroid Date: Sun, 28 Apr 2024 11:32:35 +0300 Subject: [PATCH 03/27] 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 601125ac2ea3916303f7154ef76a0000550e19a5 Mon Sep 17 00:00:00 2001 From: ronniedroid Date: Sun, 28 Apr 2024 12:04:02 +0300 Subject: [PATCH 04/27] added manual sorting to the timers tab --- .../fossify/clock/adapters/TimerAdapter.kt | 55 ++++++++++++++++--- .../clock/dialogs/ChangeTimerSortDialog.kt | 3 + .../fossify/clock/fragments/AlarmFragment.kt | 1 - .../fossify/clock/fragments/TimerFragment.kt | 19 +++++++ .../org/fossify/clock/helpers/Config.kt | 4 ++ .../org/fossify/clock/helpers/Constants.kt | 1 + .../res/layout/dialog_change_timer_sort.xml | 8 +++ app/src/main/res/layout/item_timer.xml | 17 +++++- 8 files changed, 98 insertions(+), 10 deletions(-) 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..4e53c6ed 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt @@ -1,21 +1,27 @@ package org.fossify.clock.adapters +import android.annotation.SuppressLint import android.view.Menu +import android.view.MotionEvent import android.view.View import android.view.ViewGroup +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView import me.grantland.widget.AutofitHelper import org.fossify.clock.R import org.fossify.clock.activities.SimpleActivity import org.fossify.clock.databinding.ItemTimerBinding -import org.fossify.clock.extensions.getFormattedDuration -import org.fossify.clock.extensions.hideTimerNotification -import org.fossify.clock.extensions.secondsToMillis +import org.fossify.clock.extensions.* 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.dialogs.PermissionRequiredDialog import org.fossify.commons.extensions.* +import org.fossify.commons.helpers.SORT_BY_CUSTOM +import org.fossify.commons.interfaces.ItemMoveCallback +import org.fossify.commons.interfaces.ItemTouchHelperContract +import org.fossify.commons.interfaces.StartReorderDragListener import org.fossify.commons.views.MyRecyclerView import org.greenrobot.eventbus.EventBus @@ -24,10 +30,21 @@ class TimerAdapter( var timers: ArrayList, recyclerView: MyRecyclerView, itemClick: (Any) -> Unit, -) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) { +) : MyRecyclerViewAdapter(activity, recyclerView, itemClick), ItemTouchHelperContract { + + private var startReorderDragListener: StartReorderDragListener init { setupDragListener(true) + + val touchHelper = ItemTouchHelper(ItemMoveCallback(this)) + touchHelper.attachToRecyclerView(recyclerView) + + startReorderDragListener = object : StartReorderDragListener { + override fun requestDrag(viewHolder: RecyclerView.ViewHolder) { + touchHelper.startDrag(viewHolder) + } + } } override fun getActionMenuId() = R.menu.cab_alarms @@ -56,6 +73,10 @@ class TimerAdapter( override fun onActionModeDestroyed() {} + override fun onRowClear(myViewHolder: ViewHolder?) {} + + override fun onRowSelected(myViewHolder: ViewHolder?) {} + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return createViewHolder(ItemTimerBinding.inflate(layoutInflater, parent, false).root) } @@ -63,7 +84,7 @@ class TimerAdapter( override fun onBindViewHolder(holder: ViewHolder, position: Int) { val timer = timers[position] holder.bindView(timer, true, true) { itemView, _ -> - setupView(itemView, timer) + setupView(itemView, timer, holder) } bindViewHolder(holder) } @@ -89,11 +110,19 @@ class TimerAdapter( private fun getSelectedItems() = timers.filter { selectedKeys.contains(it.id) } as ArrayList - private fun setupView(view: View, timer: Timer) { + @SuppressLint("ClickableViewAccessibility") + private fun setupView(view: View, timer: Timer, holder: ViewHolder) { ItemTimerBinding.bind(view).apply { val isSelected = selectedKeys.contains(timer.id) timerHolder.isSelected = isSelected - + timerDragHandle.beVisibleIf(activity.config.timerSort == SORT_BY_CUSTOM) + timerDragHandle.applyColorFilter(textColor) + timerDragHandle.setOnTouchListener { _, event -> + if (event.action == MotionEvent.ACTION_DOWN) { + startReorderDragListener.requestDrag(holder) + } + false + } timerLabel.setTextColor(textColor) timerLabel.setHintTextColor(textColor.adjustAlpha(0.7f)) timerLabel.text = timer.label @@ -152,4 +181,16 @@ class TimerAdapter( EventBus.getDefault().post(TimerEvent.Delete(timer.id!!)) activity.hideTimerNotification(timer.id!!) } + + override fun onRowMoved(fromPosition: Int, toPosition: Int) { + timers.swap(fromPosition, toPosition) + notifyItemMoved(fromPosition, toPosition) + saveAlarmsCustomOrder(timers) + } + + private fun saveAlarmsCustomOrder(alarms: ArrayList) { + val timersCustomSortingIds = alarms.map { it.id } + + activity.config.timersCustomSorting = timersCustomSortingIds.joinToString { it.toString() } + } } diff --git a/app/src/main/kotlin/org/fossify/clock/dialogs/ChangeTimerSortDialog.kt b/app/src/main/kotlin/org/fossify/clock/dialogs/ChangeTimerSortDialog.kt index 59d67112..6d81bd01 100644 --- a/app/src/main/kotlin/org/fossify/clock/dialogs/ChangeTimerSortDialog.kt +++ b/app/src/main/kotlin/org/fossify/clock/dialogs/ChangeTimerSortDialog.kt @@ -8,11 +8,13 @@ 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 +import org.fossify.commons.helpers.SORT_BY_CUSTOM 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 + SORT_BY_CUSTOM -> sortingDialogRadioCustom else -> sortingDialogRadioCreationOrder } activeRadioButton.isChecked = true @@ -30,6 +32,7 @@ class ChangeTimerSortDialog(val activity: BaseSimpleActivity, val callback: () - private fun dialogConfirmed() { val sort = when (binding.sortingDialogRadioSorting.checkedRadioButtonId) { R.id.sorting_dialog_radio_timer_duration -> SORT_BY_TIMER_DURATION + R.id.sorting_dialog_radio_custom -> SORT_BY_CUSTOM else -> SORT_BY_CREATION_ORDER } diff --git a/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt b/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt index 6c58af47..6b8c516d 100644 --- a/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt +++ b/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt @@ -1,7 +1,6 @@ package org.fossify.clock.fragments import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup 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..ae8b4976 100644 --- a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt +++ b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt @@ -22,6 +22,7 @@ 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_CUSTOM import org.fossify.commons.helpers.SORT_BY_DATE_CREATED import org.fossify.commons.models.AlarmSound import org.greenrobot.eventbus.EventBus @@ -83,6 +84,24 @@ class TimerFragment : Fragment() { when (requireContext().config.timerSort) { SORT_BY_TIMER_DURATION -> timers.sortBy { it.seconds } SORT_BY_DATE_CREATED -> timers.sortBy { it.id } + SORT_BY_CUSTOM -> { + val customTimersSortOrderString = activity?.config?.timersCustomSorting + if (customTimersSortOrderString == "") { + timers.sortBy { it.id } + } else { + val customTimersSortOrder: List = customTimersSortOrderString?.split(", ")?.map { it.toInt() }!! + val timersIdValueMap = timers.associateBy { it.id } + + val sortedTimers: ArrayList = ArrayList() + customTimersSortOrder.map { id -> + if (timersIdValueMap[id] != null) { + sortedTimers.add(timersIdValueMap[id] as Timer) + } + } + + timers = (sortedTimers + timers.filter { it !in sortedTimers }) as ArrayList + } + } } activity?.runOnUiThread { val currAdapter = binding.timersList.adapter 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 dfc21c2a..912a5c0a 100644 --- a/app/src/main/kotlin/org/fossify/clock/helpers/Config.kt +++ b/app/src/main/kotlin/org/fossify/clock/helpers/Config.kt @@ -65,6 +65,10 @@ class Config(context: Context) : BaseConfig(context) { get() = prefs.getInt(TIMERS_SORT_BY, SORT_BY_CREATION_ORDER) set(timerSort) = prefs.edit().putInt(TIMERS_SORT_BY, timerSort).apply() + var timersCustomSorting: String + get() = prefs.getString(TIMERS_CUSTOM_SORTING, "")!! + set(timersCustomSorting) = prefs.edit().putString(TIMERS_CUSTOM_SORTING, timersCustomSorting).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 8264da30..15f3f5c2 100644 --- a/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt +++ b/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt @@ -26,6 +26,7 @@ const val INCREASE_VOLUME_GRADUALLY = "increase_volume_gradually" const val ALARMS_SORT_BY = "alarms_sort_by" const val ALARMS_CUSTOM_SORTING = "alarms_custom_sorting" const val TIMERS_SORT_BY = "timers_sort_by" +const val TIMERS_CUSTOM_SORTING = "timers_custom_sorting" const val STOPWATCH_LAPS_SORT_BY = "stopwatch_laps_sort_by" const val WAS_INITIAL_WIDGET_SET_UP = "was_initial_widget_set_up" diff --git a/app/src/main/res/layout/dialog_change_timer_sort.xml b/app/src/main/res/layout/dialog_change_timer_sort.xml index 1b6b3ac0..9be36fa5 100644 --- a/app/src/main/res/layout/dialog_change_timer_sort.xml +++ b/app/src/main/res/layout/dialog_change_timer_sort.xml @@ -29,5 +29,13 @@ android:paddingBottom="@dimen/medium_margin" android:text="@string/sort_by_timer_duration" /> + + diff --git a/app/src/main/res/layout/item_timer.xml b/app/src/main/res/layout/item_timer.xml index ccc35afb..9fe01a80 100644 --- a/app/src/main/res/layout/item_timer.xml +++ b/app/src/main/res/layout/item_timer.xml @@ -12,6 +12,19 @@ android:paddingHorizontal="@dimen/activity_margin" android:paddingVertical="@dimen/medium_margin"> + + @@ -33,7 +46,7 @@ android:maxLines="1" android:textSize="@dimen/bigger_text_size" app:layout_constraintEnd_toEndOf="@id/timer_time" - app:layout_constraintStart_toStartOf="parent" + app:layout_constraintStart_toEndOf="@id/timer_drag_handle" app:layout_constraintTop_toBottomOf="@id/timer_time" tools:text="Cook rice" /> From 3e70d7b4a09187681c63d750d23e6c049d1f6e7c Mon Sep 17 00:00:00 2001 From: ronniedroid Date: Mon, 29 Apr 2024 10:11:21 +0300 Subject: [PATCH 05/27] implemented long press to show drag handle on timers and alarms tabs --- .../fossify/clock/adapters/AlarmsAdapter.kt | 16 +++++--- .../fossify/clock/adapters/TimerAdapter.kt | 13 +++++-- app/src/main/res/layout/item_alarm.xml | 37 ++++++++++--------- app/src/main/res/layout/item_timer.xml | 32 ++++++++-------- 4 files changed, 56 insertions(+), 42 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt index 7fcf1737..78cd4f09 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt @@ -1,7 +1,6 @@ package org.fossify.clock.adapters import android.annotation.SuppressLint -import android.util.Log import android.view.Menu import android.view.MotionEvent import android.view.View @@ -34,9 +33,9 @@ class AlarmsAdapter( ) : MyRecyclerViewAdapter(activity, recyclerView, itemClick), ItemTouchHelperContract { private var startReorderDragListener: StartReorderDragListener + init { setupDragListener(true) - val touchHelper = ItemTouchHelper(ItemMoveCallback(this)) touchHelper.attachToRecyclerView(recyclerView) @@ -69,9 +68,13 @@ class AlarmsAdapter( override fun getItemKeyPosition(key: Int) = alarms.indexOfFirst { it.id == key } - override fun onActionModeCreated() {} + override fun onActionModeCreated() { + notifyDataSetChanged() + } - override fun onActionModeDestroyed() {} + override fun onActionModeDestroyed() { + notifyDataSetChanged() + } override fun onRowClear(myViewHolder: ViewHolder?) {} @@ -116,7 +119,7 @@ class AlarmsAdapter( val isSelected = selectedKeys.contains(alarm.id) ItemAlarmBinding.bind(view).apply { alarmHolder.isSelected = isSelected - alarmDragHandle.beVisibleIf(activity.config.alarmSort == SORT_BY_CUSTOM) + alarmDragHandle.beVisibleIf(selectedKeys.isNotEmpty()) alarmDragHandle.applyColorFilter(textColor) alarmDragHandle.setOnTouchListener { _, event -> if (event.action == MotionEvent.ACTION_DOWN) { @@ -175,6 +178,9 @@ class AlarmsAdapter( alarms.swap(fromPosition, toPosition) notifyItemMoved(fromPosition, toPosition) saveAlarmsCustomOrder(alarms) + if (activity.config.alarmSort != SORT_BY_CUSTOM) { + activity.config.alarmSort = SORT_BY_CUSTOM + } } private fun saveAlarmsCustomOrder(alarms: ArrayList) { 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 4e53c6ed..4d688b64 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt @@ -69,9 +69,13 @@ class TimerAdapter( override fun getItemKeyPosition(key: Int) = timers.indexOfFirst { it.id == key } - override fun onActionModeCreated() {} + override fun onActionModeCreated() { + notifyDataSetChanged() + } - override fun onActionModeDestroyed() {} + override fun onActionModeDestroyed() { + notifyDataSetChanged() + } override fun onRowClear(myViewHolder: ViewHolder?) {} @@ -115,7 +119,7 @@ class TimerAdapter( ItemTimerBinding.bind(view).apply { val isSelected = selectedKeys.contains(timer.id) timerHolder.isSelected = isSelected - timerDragHandle.beVisibleIf(activity.config.timerSort == SORT_BY_CUSTOM) + timerDragHandle.beVisibleIf(selectedKeys.isNotEmpty()) timerDragHandle.applyColorFilter(textColor) timerDragHandle.setOnTouchListener { _, event -> if (event.action == MotionEvent.ACTION_DOWN) { @@ -186,6 +190,9 @@ class TimerAdapter( timers.swap(fromPosition, toPosition) notifyItemMoved(fromPosition, toPosition) saveAlarmsCustomOrder(timers) + if (activity.config.timerSort != SORT_BY_CUSTOM) { + activity.config.timerSort = SORT_BY_CUSTOM + } } private fun saveAlarmsCustomOrder(alarms: ArrayList) { diff --git a/app/src/main/res/layout/item_alarm.xml b/app/src/main/res/layout/item_alarm.xml index c1fb26ec..e416bdd5 100644 --- a/app/src/main/res/layout/item_alarm.xml +++ b/app/src/main/res/layout/item_alarm.xml @@ -12,19 +12,6 @@ android:paddingHorizontal="@dimen/activity_margin" android:paddingVertical="@dimen/medium_margin"> - - @@ -47,8 +34,8 @@ android:maxLines="1" android:paddingHorizontal="@dimen/tiny_margin" android:textSize="@dimen/bigger_text_size" - app:layout_constraintEnd_toStartOf="@id/alarm_switch" - app:layout_constraintStart_toEndOf="@id/alarm_drag_handle" + app:layout_constraintEnd_toEndOf="@id/alarm_switch" + app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/alarm_time" tools:text="Mon, Tue, Wed, Thu, Fri" /> @@ -61,8 +48,8 @@ android:maxLines="1" android:paddingHorizontal="@dimen/tiny_margin" android:textSize="@dimen/bigger_text_size" - app:layout_constraintEnd_toStartOf="@id/alarm_switch" - app:layout_constraintStart_toEndOf="@id/alarm_drag_handle" + app:layout_constraintEnd_toEndOf="@id/alarm_switch" + app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/alarm_days" tools:text="Good morning!" /> @@ -72,7 +59,21 @@ android:layout_height="wrap_content" android:paddingHorizontal="@dimen/normal_margin" app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toStartOf="@id/alarm_drag_handle" + app:layout_constraintStart_toEndOf="@id/alarm_time" + app:layout_constraintTop_toTopOf="parent" /> + + diff --git a/app/src/main/res/layout/item_timer.xml b/app/src/main/res/layout/item_timer.xml index 9fe01a80..cb4c7b5a 100644 --- a/app/src/main/res/layout/item_timer.xml +++ b/app/src/main/res/layout/item_timer.xml @@ -12,19 +12,6 @@ android:paddingHorizontal="@dimen/activity_margin" android:paddingVertical="@dimen/medium_margin"> - - @@ -46,7 +33,7 @@ android:maxLines="1" android:textSize="@dimen/bigger_text_size" app:layout_constraintEnd_toEndOf="@id/timer_time" - app:layout_constraintStart_toEndOf="@id/timer_drag_handle" + app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/timer_time" tools:text="Cook rice" /> @@ -77,8 +64,21 @@ android:padding="@dimen/activity_margin" android:src="@drawable/ic_play_vector" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintEnd_toEndOf="@id/timer_drag_handle" app:layout_constraintStart_toEndOf="@id/timer_reset" app:layout_constraintTop_toTopOf="parent" /> + + From 10f99f60aea50a3a44a97c455bf22ebd7fd234d9 Mon Sep 17 00:00:00 2001 From: ronniedroid Date: Tue, 30 Apr 2024 09:03:34 +0300 Subject: [PATCH 06/27] Changed timer text size --- app/src/main/res/layout/item_timer.xml | 14 +++++++------- app/src/main/res/values/dimens.xml | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/layout/item_timer.xml b/app/src/main/res/layout/item_timer.xml index cb4c7b5a..61a74f70 100644 --- a/app/src/main/res/layout/item_timer.xml +++ b/app/src/main/res/layout/item_timer.xml @@ -18,11 +18,11 @@ android:layout_height="wrap_content" android:includeFontPadding="false" android:maxLines="1" - android:textSize="@dimen/alarm_text_size" + android:textSize="@dimen/timer_text_size" app:layout_constraintEnd_toStartOf="@id/timer_reset" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - tools:text="00:00" /> + tools:text="00:00:00" /> @@ -63,10 +63,10 @@ android:background="?attr/selectableItemBackgroundBorderless" android:padding="@dimen/activity_margin" android:src="@drawable/ic_play_vector" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="@id/timer_drag_handle" + app:layout_constraintBottom_toBottomOf="@id/timer_drag_handle" + app:layout_constraintEnd_toStartOf="@id/timer_drag_handle" app:layout_constraintStart_toEndOf="@id/timer_reset" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="@id/timer_drag_handle" /> 70sp 60sp 60sp + 48sp 80sp 48sp 14sp From 46a628a0a89d4f2b1ee701e02fded6043ded802c Mon Sep 17 00:00:00 2001 From: ronniedroid Date: Tue, 30 Apr 2024 13:38:37 +0300 Subject: [PATCH 07/27] removed AutofitHelper from the timerTime --- app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt | 2 -- 1 file changed, 2 deletions(-) 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 4d688b64..32a9ff52 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt @@ -7,7 +7,6 @@ import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView -import me.grantland.widget.AutofitHelper import org.fossify.clock.R import org.fossify.clock.activities.SimpleActivity import org.fossify.clock.databinding.ItemTimerBinding @@ -131,7 +130,6 @@ class TimerAdapter( timerLabel.setHintTextColor(textColor.adjustAlpha(0.7f)) timerLabel.text = timer.label - AutofitHelper.create(timerTime) timerTime.setTextColor(textColor) timerTime.text = when (timer.state) { is TimerState.Finished -> 0.getFormattedDuration() From 138ba2913fc3cb7683883ea3d1627170be038152 Mon Sep 17 00:00:00 2001 From: Agnieszka C <85929121+Aga-C@users.noreply.github.com> Date: Thu, 15 Aug 2024 08:31:07 +0200 Subject: [PATCH 08/27] Added London time zone (#86) --- .../org/fossify/clock/helpers/Constants.kt | 119 +++++++++--------- 1 file changed, 60 insertions(+), 59 deletions(-) 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..fa7406c8 100644 --- a/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt +++ b/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt @@ -161,65 +161,66 @@ fun getAllTimeZones() = arrayListOf( MyTimeZone(28, "GMT-01:00 Cape Verde", "Atlantic/Cape_Verde"), MyTimeZone(29, "GMT+00:00 Casablanca", "Africa/Casablanca"), MyTimeZone(30, "GMT+00:00 Greenwich Mean Time", "Etc/Greenwich"), - MyTimeZone(31, "GMT+01:00 Amsterdam", "Europe/Amsterdam"), - MyTimeZone(32, "GMT+01:00 Belgrade", "Europe/Belgrade"), - MyTimeZone(33, "GMT+01:00 Brussels", "Europe/Brussels"), - MyTimeZone(34, "GMT+01:00 Madrid", "Europe/Madrid"), - MyTimeZone(35, "GMT+01:00 Sarajevo", "Europe/Sarajevo"), - MyTimeZone(36, "GMT+01:00 Brazzaville", "Africa/Brazzaville"), - MyTimeZone(37, "GMT+02:00 Windhoek", "Africa/Windhoek"), - MyTimeZone(38, "GMT+02:00 Amman", "Asia/Amman"), - MyTimeZone(39, "GMT+02:00 Athens", "Europe/Athens"), - MyTimeZone(40, "GMT+02:00 Istanbul", "Europe/Istanbul"), - MyTimeZone(41, "GMT+02:00 Beirut", "Asia/Beirut"), - MyTimeZone(42, "GMT+02:00 Cairo", "Africa/Cairo"), - MyTimeZone(43, "GMT+02:00 Helsinki", "Europe/Helsinki"), - MyTimeZone(44, "GMT+02:00 Jerusalem", "Asia/Jerusalem"), - MyTimeZone(45, "GMT+02:00 Harare", "Africa/Harare"), - MyTimeZone(46, "GMT+03:00 Minsk", "Europe/Minsk"), - MyTimeZone(47, "GMT+03:00 Baghdad", "Asia/Baghdad"), - MyTimeZone(48, "GMT+03:00 Moscow", "Europe/Moscow"), - MyTimeZone(49, "GMT+03:00 Kuwait", "Asia/Kuwait"), - MyTimeZone(50, "GMT+03:00 Nairobi", "Africa/Nairobi"), - MyTimeZone(51, "GMT+03:30 Tehran", "Asia/Tehran"), - MyTimeZone(52, "GMT+04:00 Baku", "Asia/Baku"), - MyTimeZone(53, "GMT+04:00 Tbilisi", "Asia/Tbilisi"), - MyTimeZone(54, "GMT+04:00 Yerevan", "Asia/Yerevan"), - MyTimeZone(55, "GMT+04:00 Dubai", "Asia/Dubai"), - MyTimeZone(56, "GMT+04:30 Kabul", "Asia/Kabul"), - MyTimeZone(57, "GMT+05:00 Karachi", "Asia/Karachi"), - MyTimeZone(58, "GMT+05:00 Oral", "Asia/Oral"), - MyTimeZone(59, "GMT+05:00 Yekaterinburg", "Asia/Yekaterinburg"), - MyTimeZone(60, "GMT+05:30 Kolkata", "Asia/Kolkata"), - MyTimeZone(61, "GMT+05:30 Colombo", "Asia/Colombo"), - MyTimeZone(62, "GMT+05:45 Kathmandu", "Asia/Kathmandu"), - MyTimeZone(63, "GMT+06:00 Almaty", "Asia/Almaty"), - MyTimeZone(64, "GMT+06:30 Rangoon", "Asia/Rangoon"), - MyTimeZone(65, "GMT+07:00 Krasnoyarsk", "Asia/Krasnoyarsk"), - MyTimeZone(66, "GMT+07:00 Bangkok", "Asia/Bangkok"), - MyTimeZone(67, "GMT+07:00 Jakarta", "Asia/Jakarta"), - MyTimeZone(68, "GMT+08:00 Shanghai", "Asia/Shanghai"), - MyTimeZone(69, "GMT+08:00 Hong Kong", "Asia/Hong_Kong"), - MyTimeZone(70, "GMT+08:00 Irkutsk", "Asia/Irkutsk"), - MyTimeZone(71, "GMT+08:00 Kuala Lumpur", "Asia/Kuala_Lumpur"), - MyTimeZone(72, "GMT+08:00 Perth", "Australia/Perth"), - MyTimeZone(73, "GMT+08:00 Taipei", "Asia/Taipei"), - MyTimeZone(74, "GMT+09:00 Seoul", "Asia/Seoul"), - MyTimeZone(75, "GMT+09:00 Tokyo", "Asia/Tokyo"), - MyTimeZone(76, "GMT+09:00 Yakutsk", "Asia/Yakutsk"), - MyTimeZone(77, "GMT+09:30 Darwin", "Australia/Darwin"), - MyTimeZone(78, "GMT+10:00 Brisbane", "Australia/Brisbane"), - MyTimeZone(79, "GMT+10:00 Vladivostok", "Asia/Vladivostok"), - MyTimeZone(80, "GMT+10:00 Guam", "Pacific/Guam"), - MyTimeZone(81, "GMT+10:00 Magadan", "Asia/Magadan"), - MyTimeZone(82, "GMT+10:30 Adelaide", "Australia/Adelaide"), - MyTimeZone(83, "GMT+11:00 Hobart", "Australia/Hobart"), - MyTimeZone(84, "GMT+11:00 Sydney", "Australia/Sydney"), - MyTimeZone(85, "GMT+11:00 Noumea", "Pacific/Noumea"), - MyTimeZone(86, "GMT+12:00 Majuro", "Pacific/Majuro"), - MyTimeZone(87, "GMT+12:00 Fiji", "Pacific/Fiji"), - MyTimeZone(88, "GMT+13:00 Auckland", "Pacific/Auckland"), - MyTimeZone(89, "GMT+13:00 Tongatapu", "Pacific/Tongatapu") + MyTimeZone(31, "GMT+00:00 London", "Europe/London"), + MyTimeZone(32, "GMT+01:00 Amsterdam", "Europe/Amsterdam"), + MyTimeZone(33, "GMT+01:00 Belgrade", "Europe/Belgrade"), + MyTimeZone(34, "GMT+01:00 Brussels", "Europe/Brussels"), + MyTimeZone(35, "GMT+01:00 Madrid", "Europe/Madrid"), + MyTimeZone(36, "GMT+01:00 Sarajevo", "Europe/Sarajevo"), + MyTimeZone(37, "GMT+01:00 Brazzaville", "Africa/Brazzaville"), + MyTimeZone(38, "GMT+02:00 Windhoek", "Africa/Windhoek"), + MyTimeZone(39, "GMT+02:00 Amman", "Asia/Amman"), + MyTimeZone(40, "GMT+02:00 Athens", "Europe/Athens"), + MyTimeZone(41, "GMT+02:00 Istanbul", "Europe/Istanbul"), + MyTimeZone(42, "GMT+02:00 Beirut", "Asia/Beirut"), + MyTimeZone(43, "GMT+02:00 Cairo", "Africa/Cairo"), + MyTimeZone(44, "GMT+02:00 Helsinki", "Europe/Helsinki"), + MyTimeZone(45, "GMT+02:00 Jerusalem", "Asia/Jerusalem"), + MyTimeZone(46, "GMT+02:00 Harare", "Africa/Harare"), + MyTimeZone(47, "GMT+03:00 Minsk", "Europe/Minsk"), + MyTimeZone(48, "GMT+03:00 Baghdad", "Asia/Baghdad"), + MyTimeZone(49, "GMT+03:00 Moscow", "Europe/Moscow"), + MyTimeZone(50, "GMT+03:00 Kuwait", "Asia/Kuwait"), + MyTimeZone(51, "GMT+03:00 Nairobi", "Africa/Nairobi"), + MyTimeZone(52, "GMT+03:30 Tehran", "Asia/Tehran"), + MyTimeZone(53, "GMT+04:00 Baku", "Asia/Baku"), + MyTimeZone(54, "GMT+04:00 Tbilisi", "Asia/Tbilisi"), + MyTimeZone(55, "GMT+04:00 Yerevan", "Asia/Yerevan"), + MyTimeZone(56, "GMT+04:00 Dubai", "Asia/Dubai"), + MyTimeZone(57, "GMT+04:30 Kabul", "Asia/Kabul"), + MyTimeZone(58, "GMT+05:00 Karachi", "Asia/Karachi"), + MyTimeZone(59, "GMT+05:00 Oral", "Asia/Oral"), + MyTimeZone(60, "GMT+05:00 Yekaterinburg", "Asia/Yekaterinburg"), + MyTimeZone(61, "GMT+05:30 Kolkata", "Asia/Kolkata"), + MyTimeZone(62, "GMT+05:30 Colombo", "Asia/Colombo"), + MyTimeZone(63, "GMT+05:45 Kathmandu", "Asia/Kathmandu"), + MyTimeZone(64, "GMT+06:00 Almaty", "Asia/Almaty"), + MyTimeZone(65, "GMT+06:30 Rangoon", "Asia/Rangoon"), + MyTimeZone(66, "GMT+07:00 Krasnoyarsk", "Asia/Krasnoyarsk"), + MyTimeZone(67, "GMT+07:00 Bangkok", "Asia/Bangkok"), + MyTimeZone(68, "GMT+07:00 Jakarta", "Asia/Jakarta"), + MyTimeZone(69, "GMT+08:00 Shanghai", "Asia/Shanghai"), + MyTimeZone(70, "GMT+08:00 Hong Kong", "Asia/Hong_Kong"), + MyTimeZone(71, "GMT+08:00 Irkutsk", "Asia/Irkutsk"), + MyTimeZone(72, "GMT+08:00 Kuala Lumpur", "Asia/Kuala_Lumpur"), + MyTimeZone(73, "GMT+08:00 Perth", "Australia/Perth"), + MyTimeZone(74, "GMT+08:00 Taipei", "Asia/Taipei"), + MyTimeZone(75, "GMT+09:00 Seoul", "Asia/Seoul"), + MyTimeZone(76, "GMT+09:00 Tokyo", "Asia/Tokyo"), + MyTimeZone(77, "GMT+09:00 Yakutsk", "Asia/Yakutsk"), + MyTimeZone(78, "GMT+09:30 Darwin", "Australia/Darwin"), + MyTimeZone(79, "GMT+10:00 Brisbane", "Australia/Brisbane"), + MyTimeZone(80, "GMT+10:00 Vladivostok", "Asia/Vladivostok"), + MyTimeZone(81, "GMT+10:00 Guam", "Pacific/Guam"), + MyTimeZone(82, "GMT+10:00 Magadan", "Asia/Magadan"), + MyTimeZone(83, "GMT+10:30 Adelaide", "Australia/Adelaide"), + MyTimeZone(84, "GMT+11:00 Hobart", "Australia/Hobart"), + MyTimeZone(85, "GMT+11:00 Sydney", "Australia/Sydney"), + MyTimeZone(86, "GMT+11:00 Noumea", "Pacific/Noumea"), + MyTimeZone(87, "GMT+12:00 Majuro", "Pacific/Majuro"), + MyTimeZone(88, "GMT+12:00 Fiji", "Pacific/Fiji"), + MyTimeZone(89, "GMT+13:00 Auckland", "Pacific/Auckland"), + MyTimeZone(90, "GMT+13:00 Tongatapu", "Pacific/Tongatapu") ) fun getTimeUntilNextAlarm(alarmTimeInMinutes: Int, days: Int): Int? { From 262a971ee6bbad936ed7d4c1ef5f9ef8fe9d1406 Mon Sep 17 00:00:00 2001 From: Agnieszka C <85929121+Aga-C@users.noreply.github.com> Date: Thu, 26 Dec 2024 00:03:23 +0100 Subject: [PATCH 09/27] Fixed timezone ids --- .../org/fossify/clock/helpers/Constants.kt | 120 +++++++++--------- 1 file changed, 60 insertions(+), 60 deletions(-) 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 fa7406c8..38c1874e 100644 --- a/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt +++ b/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt @@ -161,66 +161,66 @@ fun getAllTimeZones() = arrayListOf( MyTimeZone(28, "GMT-01:00 Cape Verde", "Atlantic/Cape_Verde"), MyTimeZone(29, "GMT+00:00 Casablanca", "Africa/Casablanca"), MyTimeZone(30, "GMT+00:00 Greenwich Mean Time", "Etc/Greenwich"), - MyTimeZone(31, "GMT+00:00 London", "Europe/London"), - MyTimeZone(32, "GMT+01:00 Amsterdam", "Europe/Amsterdam"), - MyTimeZone(33, "GMT+01:00 Belgrade", "Europe/Belgrade"), - MyTimeZone(34, "GMT+01:00 Brussels", "Europe/Brussels"), - MyTimeZone(35, "GMT+01:00 Madrid", "Europe/Madrid"), - MyTimeZone(36, "GMT+01:00 Sarajevo", "Europe/Sarajevo"), - MyTimeZone(37, "GMT+01:00 Brazzaville", "Africa/Brazzaville"), - MyTimeZone(38, "GMT+02:00 Windhoek", "Africa/Windhoek"), - MyTimeZone(39, "GMT+02:00 Amman", "Asia/Amman"), - MyTimeZone(40, "GMT+02:00 Athens", "Europe/Athens"), - MyTimeZone(41, "GMT+02:00 Istanbul", "Europe/Istanbul"), - MyTimeZone(42, "GMT+02:00 Beirut", "Asia/Beirut"), - MyTimeZone(43, "GMT+02:00 Cairo", "Africa/Cairo"), - MyTimeZone(44, "GMT+02:00 Helsinki", "Europe/Helsinki"), - MyTimeZone(45, "GMT+02:00 Jerusalem", "Asia/Jerusalem"), - MyTimeZone(46, "GMT+02:00 Harare", "Africa/Harare"), - MyTimeZone(47, "GMT+03:00 Minsk", "Europe/Minsk"), - MyTimeZone(48, "GMT+03:00 Baghdad", "Asia/Baghdad"), - MyTimeZone(49, "GMT+03:00 Moscow", "Europe/Moscow"), - MyTimeZone(50, "GMT+03:00 Kuwait", "Asia/Kuwait"), - MyTimeZone(51, "GMT+03:00 Nairobi", "Africa/Nairobi"), - MyTimeZone(52, "GMT+03:30 Tehran", "Asia/Tehran"), - MyTimeZone(53, "GMT+04:00 Baku", "Asia/Baku"), - MyTimeZone(54, "GMT+04:00 Tbilisi", "Asia/Tbilisi"), - MyTimeZone(55, "GMT+04:00 Yerevan", "Asia/Yerevan"), - MyTimeZone(56, "GMT+04:00 Dubai", "Asia/Dubai"), - MyTimeZone(57, "GMT+04:30 Kabul", "Asia/Kabul"), - MyTimeZone(58, "GMT+05:00 Karachi", "Asia/Karachi"), - MyTimeZone(59, "GMT+05:00 Oral", "Asia/Oral"), - MyTimeZone(60, "GMT+05:00 Yekaterinburg", "Asia/Yekaterinburg"), - MyTimeZone(61, "GMT+05:30 Kolkata", "Asia/Kolkata"), - MyTimeZone(62, "GMT+05:30 Colombo", "Asia/Colombo"), - MyTimeZone(63, "GMT+05:45 Kathmandu", "Asia/Kathmandu"), - MyTimeZone(64, "GMT+06:00 Almaty", "Asia/Almaty"), - MyTimeZone(65, "GMT+06:30 Rangoon", "Asia/Rangoon"), - MyTimeZone(66, "GMT+07:00 Krasnoyarsk", "Asia/Krasnoyarsk"), - MyTimeZone(67, "GMT+07:00 Bangkok", "Asia/Bangkok"), - MyTimeZone(68, "GMT+07:00 Jakarta", "Asia/Jakarta"), - MyTimeZone(69, "GMT+08:00 Shanghai", "Asia/Shanghai"), - MyTimeZone(70, "GMT+08:00 Hong Kong", "Asia/Hong_Kong"), - MyTimeZone(71, "GMT+08:00 Irkutsk", "Asia/Irkutsk"), - MyTimeZone(72, "GMT+08:00 Kuala Lumpur", "Asia/Kuala_Lumpur"), - MyTimeZone(73, "GMT+08:00 Perth", "Australia/Perth"), - MyTimeZone(74, "GMT+08:00 Taipei", "Asia/Taipei"), - MyTimeZone(75, "GMT+09:00 Seoul", "Asia/Seoul"), - MyTimeZone(76, "GMT+09:00 Tokyo", "Asia/Tokyo"), - MyTimeZone(77, "GMT+09:00 Yakutsk", "Asia/Yakutsk"), - MyTimeZone(78, "GMT+09:30 Darwin", "Australia/Darwin"), - MyTimeZone(79, "GMT+10:00 Brisbane", "Australia/Brisbane"), - MyTimeZone(80, "GMT+10:00 Vladivostok", "Asia/Vladivostok"), - MyTimeZone(81, "GMT+10:00 Guam", "Pacific/Guam"), - MyTimeZone(82, "GMT+10:00 Magadan", "Asia/Magadan"), - MyTimeZone(83, "GMT+10:30 Adelaide", "Australia/Adelaide"), - MyTimeZone(84, "GMT+11:00 Hobart", "Australia/Hobart"), - MyTimeZone(85, "GMT+11:00 Sydney", "Australia/Sydney"), - MyTimeZone(86, "GMT+11:00 Noumea", "Pacific/Noumea"), - MyTimeZone(87, "GMT+12:00 Majuro", "Pacific/Majuro"), - MyTimeZone(88, "GMT+12:00 Fiji", "Pacific/Fiji"), - MyTimeZone(89, "GMT+13:00 Auckland", "Pacific/Auckland"), - MyTimeZone(90, "GMT+13:00 Tongatapu", "Pacific/Tongatapu") + MyTimeZone(90, "GMT+00:00 London", "Europe/London"), + MyTimeZone(31, "GMT+01:00 Amsterdam", "Europe/Amsterdam"), + MyTimeZone(32, "GMT+01:00 Belgrade", "Europe/Belgrade"), + MyTimeZone(33, "GMT+01:00 Brussels", "Europe/Brussels"), + MyTimeZone(34, "GMT+01:00 Madrid", "Europe/Madrid"), + MyTimeZone(35, "GMT+01:00 Sarajevo", "Europe/Sarajevo"), + MyTimeZone(36, "GMT+01:00 Brazzaville", "Africa/Brazzaville"), + MyTimeZone(37, "GMT+02:00 Windhoek", "Africa/Windhoek"), + MyTimeZone(38, "GMT+02:00 Amman", "Asia/Amman"), + MyTimeZone(39, "GMT+02:00 Athens", "Europe/Athens"), + MyTimeZone(40, "GMT+02:00 Istanbul", "Europe/Istanbul"), + MyTimeZone(41, "GMT+02:00 Beirut", "Asia/Beirut"), + MyTimeZone(42, "GMT+02:00 Cairo", "Africa/Cairo"), + MyTimeZone(43, "GMT+02:00 Helsinki", "Europe/Helsinki"), + MyTimeZone(44, "GMT+02:00 Jerusalem", "Asia/Jerusalem"), + MyTimeZone(45, "GMT+02:00 Harare", "Africa/Harare"), + MyTimeZone(46, "GMT+03:00 Minsk", "Europe/Minsk"), + MyTimeZone(47, "GMT+03:00 Baghdad", "Asia/Baghdad"), + MyTimeZone(48, "GMT+03:00 Moscow", "Europe/Moscow"), + MyTimeZone(49, "GMT+03:00 Kuwait", "Asia/Kuwait"), + MyTimeZone(50, "GMT+03:00 Nairobi", "Africa/Nairobi"), + MyTimeZone(51, "GMT+03:30 Tehran", "Asia/Tehran"), + MyTimeZone(52, "GMT+04:00 Baku", "Asia/Baku"), + MyTimeZone(53, "GMT+04:00 Tbilisi", "Asia/Tbilisi"), + MyTimeZone(54, "GMT+04:00 Yerevan", "Asia/Yerevan"), + MyTimeZone(55, "GMT+04:00 Dubai", "Asia/Dubai"), + MyTimeZone(56, "GMT+04:30 Kabul", "Asia/Kabul"), + MyTimeZone(57, "GMT+05:00 Karachi", "Asia/Karachi"), + MyTimeZone(58, "GMT+05:00 Oral", "Asia/Oral"), + MyTimeZone(59, "GMT+05:00 Yekaterinburg", "Asia/Yekaterinburg"), + MyTimeZone(60, "GMT+05:30 Kolkata", "Asia/Kolkata"), + MyTimeZone(61, "GMT+05:30 Colombo", "Asia/Colombo"), + MyTimeZone(62, "GMT+05:45 Kathmandu", "Asia/Kathmandu"), + MyTimeZone(63, "GMT+06:00 Almaty", "Asia/Almaty"), + MyTimeZone(64, "GMT+06:30 Rangoon", "Asia/Rangoon"), + MyTimeZone(65, "GMT+07:00 Krasnoyarsk", "Asia/Krasnoyarsk"), + MyTimeZone(66, "GMT+07:00 Bangkok", "Asia/Bangkok"), + MyTimeZone(67, "GMT+07:00 Jakarta", "Asia/Jakarta"), + MyTimeZone(68, "GMT+08:00 Shanghai", "Asia/Shanghai"), + MyTimeZone(69, "GMT+08:00 Hong Kong", "Asia/Hong_Kong"), + MyTimeZone(70, "GMT+08:00 Irkutsk", "Asia/Irkutsk"), + MyTimeZone(71, "GMT+08:00 Kuala Lumpur", "Asia/Kuala_Lumpur"), + MyTimeZone(72, "GMT+08:00 Perth", "Australia/Perth"), + MyTimeZone(73, "GMT+08:00 Taipei", "Asia/Taipei"), + MyTimeZone(74, "GMT+09:00 Seoul", "Asia/Seoul"), + MyTimeZone(75, "GMT+09:00 Tokyo", "Asia/Tokyo"), + MyTimeZone(76, "GMT+09:00 Yakutsk", "Asia/Yakutsk"), + MyTimeZone(77, "GMT+09:30 Darwin", "Australia/Darwin"), + MyTimeZone(78, "GMT+10:00 Brisbane", "Australia/Brisbane"), + MyTimeZone(79, "GMT+10:00 Vladivostok", "Asia/Vladivostok"), + MyTimeZone(80, "GMT+10:00 Guam", "Pacific/Guam"), + MyTimeZone(81, "GMT+10:00 Magadan", "Asia/Magadan"), + MyTimeZone(82, "GMT+10:30 Adelaide", "Australia/Adelaide"), + MyTimeZone(83, "GMT+11:00 Hobart", "Australia/Hobart"), + MyTimeZone(84, "GMT+11:00 Sydney", "Australia/Sydney"), + MyTimeZone(85, "GMT+11:00 Noumea", "Pacific/Noumea"), + MyTimeZone(86, "GMT+12:00 Majuro", "Pacific/Majuro"), + MyTimeZone(87, "GMT+12:00 Fiji", "Pacific/Fiji"), + MyTimeZone(88, "GMT+13:00 Auckland", "Pacific/Auckland"), + MyTimeZone(89, "GMT+13:00 Tongatapu", "Pacific/Tongatapu") ) fun getTimeUntilNextAlarm(alarmTimeInMinutes: Int, days: Int): Int? { From 0db49da312302d2c0a11f457b6d6e85c99a7f880 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Sun, 9 Feb 2025 00:56:35 +0530 Subject: [PATCH 10/27] 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 11/27] 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 12/27] 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 13/27] 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 14/27] 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 15/27] 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 16/27] 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 + } } } } From b2e73c5e3b6631f9dd383be3592a8d47059eef73 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Sat, 1 Mar 2025 20:48:01 +0530 Subject: [PATCH 17/27] Deprecate `swap` extension It doesn't perform a "move" operation which is more appropriate here. --- .../kotlin/org/fossify/clock/extensions/MutableList.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/kotlin/org/fossify/clock/extensions/MutableList.kt b/app/src/main/kotlin/org/fossify/clock/extensions/MutableList.kt index 9ca4e24f..3937e0d4 100644 --- a/app/src/main/kotlin/org/fossify/clock/extensions/MutableList.kt +++ b/app/src/main/kotlin/org/fossify/clock/extensions/MutableList.kt @@ -1,5 +1,12 @@ package org.fossify.clock.extensions +@Deprecated( + message = "Use the `move` extension function from commons", + replaceWith = ReplaceWith( + expression = "this.move(index1, index2)", + imports = ["org.fossify.commons.extensions.move"] + ) +) fun MutableList.swap(index1: Int, index2: Int) { this[index1] = this[index2].also { this[index2] = this[index1] From 51c9f66b8608b3189df12ad6ecbb1bfd8539f90e Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Sun, 2 Mar 2025 00:55:04 +0530 Subject: [PATCH 18/27] Suppress "NotifyDataSetChanged" errors --- .../main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt | 3 +++ .../main/kotlin/org/fossify/clock/adapters/StopwatchAdapter.kt | 2 ++ .../main/kotlin/org/fossify/clock/adapters/TimeZonesAdapter.kt | 3 +++ 3 files changed, 8 insertions(+) diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt index 78cd4f09..5b0cb5f9 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt @@ -68,10 +68,12 @@ class AlarmsAdapter( override fun getItemKeyPosition(key: Int) = alarms.indexOfFirst { it.id == key } + @SuppressLint("NotifyDataSetChanged") override fun onActionModeCreated() { notifyDataSetChanged() } + @SuppressLint("NotifyDataSetChanged") override fun onActionModeDestroyed() { notifyDataSetChanged() } @@ -94,6 +96,7 @@ class AlarmsAdapter( override fun getItemCount() = alarms.size + @SuppressLint("NotifyDataSetChanged") fun updateItems(newItems: ArrayList) { alarms = newItems notifyDataSetChanged() diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/StopwatchAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/StopwatchAdapter.kt index 7624ab94..1b4e8d26 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/StopwatchAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/StopwatchAdapter.kt @@ -1,5 +1,6 @@ package org.fossify.clock.adapters +import android.annotation.SuppressLint import android.view.Menu import android.view.View import android.view.ViewGroup @@ -52,6 +53,7 @@ class StopwatchAdapter(activity: SimpleActivity, var laps: ArrayList, recyc override fun getItemCount() = laps.size + @SuppressLint("NotifyDataSetChanged") fun updateItems(newItems: ArrayList) { lastLapId = 0 laps = newItems.clone() as ArrayList diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/TimeZonesAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/TimeZonesAdapter.kt index 94f2abfd..ecdf6e50 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/TimeZonesAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/TimeZonesAdapter.kt @@ -1,5 +1,6 @@ package org.fossify.clock.adapters +import android.annotation.SuppressLint import android.view.Menu import android.view.View import android.view.ViewGroup @@ -67,12 +68,14 @@ class TimeZonesAdapter(activity: SimpleActivity, var timeZones: ArrayList) { timeZones = newItems notifyDataSetChanged() finishActMode() } + @SuppressLint("NotifyDataSetChanged") fun updateTimes() { notifyDataSetChanged() } From a16c12b5bba7cfbb01a38deb56730847277179f3 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Sun, 2 Mar 2025 16:42:37 +0530 Subject: [PATCH 19/27] Hide label view when label is empty --- app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt | 1 + 1 file changed, 1 insertion(+) 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 add69b42..557e844f 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt @@ -176,6 +176,7 @@ class TimerAdapter( timerLabel.setTextColor(textColor) timerLabel.setHintTextColor(textColor.adjustAlpha(0.7f)) timerLabel.text = timer.label + timerLabel.beVisibleIf(timer.label.isNotEmpty()) AutofitHelper.create(timerTime) timerTime.setTextColor(textColor) From f16822b81676ed496caa481609f5992c43b587e8 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Sun, 2 Mar 2025 16:47:14 +0530 Subject: [PATCH 20/27] Center children vertically in timer view --- app/src/main/res/layout/item_timer.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/layout/item_timer.xml b/app/src/main/res/layout/item_timer.xml index 3c31cf08..536b714a 100644 --- a/app/src/main/res/layout/item_timer.xml +++ b/app/src/main/res/layout/item_timer.xml @@ -8,14 +8,13 @@ android:background="?selectableItemBackground" android:clickable="true" android:focusable="true" - android:foreground="@drawable/selector"> + android:foreground="@drawable/selector" + android:paddingHorizontal="@dimen/activity_margin" + android:paddingVertical="@dimen/normal_margin"> + android:layout_height="wrap_content"> Date: Sun, 2 Mar 2025 17:12:58 +0530 Subject: [PATCH 21/27] Remove timer text size --- app/src/main/res/values/dimens.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 47bc2cf1..d700694b 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -16,7 +16,6 @@ 70sp 60sp 60sp - 48sp 80sp 48sp 14sp From 43f056c7314e5e4464664bd1a2461fcb8f04e391 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Wed, 5 Mar 2025 18:46:59 +0530 Subject: [PATCH 22/27] Simplify timer item layout --- app/src/main/res/layout/item_timer.xml | 137 ++++++++++++------------- app/src/main/res/values/dimens.xml | 1 + 2 files changed, 67 insertions(+), 71 deletions(-) diff --git a/app/src/main/res/layout/item_timer.xml b/app/src/main/res/layout/item_timer.xml index 536b714a..e914d754 100644 --- a/app/src/main/res/layout/item_timer.xml +++ b/app/src/main/res/layout/item_timer.xml @@ -1,5 +1,5 @@ - - + - + - + - + - + - - - - + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index d700694b..bdd457c1 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -16,6 +16,7 @@ 70sp 60sp 60sp + @dimen/alarm_text_size 80sp 48sp 14sp From f19e9521f9c871d48c45b7d53b1f0c8cabb53463 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Thu, 6 Mar 2025 00:08:53 +0530 Subject: [PATCH 23/27] Autofit timer text properly Text wasn't being resized to it's original size after drag handles were hidden. --- .../fossify/clock/adapters/TimerAdapter.kt | 1 - .../fossify/clock/views/AutoFitTextView.kt | 47 +++++++++++++++++++ app/src/main/res/layout/item_timer.xml | 19 +++++--- 3 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 app/src/main/kotlin/org/fossify/clock/views/AutoFitTextView.kt 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 557e844f..bb956f4d 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt @@ -178,7 +178,6 @@ class TimerAdapter( timerLabel.text = timer.label timerLabel.beVisibleIf(timer.label.isNotEmpty()) - AutofitHelper.create(timerTime) timerTime.setTextColor(textColor) timerTime.text = when (timer.state) { is TimerState.Finished -> 0.getFormattedDuration() diff --git a/app/src/main/kotlin/org/fossify/clock/views/AutoFitTextView.kt b/app/src/main/kotlin/org/fossify/clock/views/AutoFitTextView.kt new file mode 100644 index 00000000..7135d0d2 --- /dev/null +++ b/app/src/main/kotlin/org/fossify/clock/views/AutoFitTextView.kt @@ -0,0 +1,47 @@ +package org.fossify.clock.views + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Build +import android.util.AttributeSet +import android.util.TypedValue +import android.widget.TextView +import androidx.annotation.RequiresApi + +/** + * A simple wrapper TextView that restores the original text size + * when view width is restored. + */ +@SuppressLint("AppCompatCustomView") +@RequiresApi(Build.VERSION_CODES.O) +class AutoFitTextView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyle: Int = 0, +) : TextView(context, attrs, defStyle) { + + private var originalTextSize: Float = textSize + private var originalWidth: Int = 0 + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + if (originalWidth == 0) { + originalWidth = w + } + + post { + if (w >= originalWidth && textSize != originalTextSize) { + disableAutoSizing() + setTextSize(TypedValue.COMPLEX_UNIT_PX, originalTextSize) + enableAutoSizing() + } + } + } + + private fun disableAutoSizing() { + setAutoSizeTextTypeWithDefaults(AUTO_SIZE_TEXT_TYPE_NONE) + } + + private fun enableAutoSizing() { + post { setAutoSizeTextTypeWithDefaults(AUTO_SIZE_TEXT_TYPE_UNIFORM) } + } +} diff --git a/app/src/main/res/layout/item_timer.xml b/app/src/main/res/layout/item_timer.xml index e914d754..44facc71 100644 --- a/app/src/main/res/layout/item_timer.xml +++ b/app/src/main/res/layout/item_timer.xml @@ -12,14 +12,19 @@ android:paddingHorizontal="@dimen/activity_margin" android:paddingVertical="@dimen/normal_margin"> - + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent" + tools:visibility="visible" /> From 246e0bf4219bee88814707ee3874893c1ce94058 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Thu, 6 Mar 2025 00:25:35 +0530 Subject: [PATCH 24/27] Format code --- .../fossify/clock/adapters/TimerAdapter.kt | 85 ++++++++++++------- 1 file changed, 56 insertions(+), 29 deletions(-) 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 bb956f4d..5940cff9 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt @@ -8,7 +8,6 @@ import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView -import me.grantland.widget.AutofitHelper import org.fossify.clock.R import org.fossify.clock.activities.SimpleActivity import org.fossify.clock.databinding.ItemTimerBinding @@ -19,7 +18,10 @@ import org.fossify.clock.extensions.secondsToMillis import org.fossify.clock.extensions.swap import org.fossify.clock.models.Timer import org.fossify.clock.models.TimerEvent -import org.fossify.clock.models.TimerState +import org.fossify.clock.models.TimerState.Finished +import org.fossify.clock.models.TimerState.Idle +import org.fossify.clock.models.TimerState.Paused +import org.fossify.clock.models.TimerState.Running import org.fossify.commons.adapters.MyRecyclerViewAdapter import org.fossify.commons.adapters.MyRecyclerViewListAdapter import org.fossify.commons.dialogs.PermissionRequiredDialog @@ -144,8 +146,12 @@ class TimerAdapter( } override fun onBindViewHolder(holder: ViewHolder, position: Int) { - holder.bindView(getItem(position), true, true) { itemView, _ -> - setupView(itemView, getItem(position), holder) + holder.bindView( + item = getItem(position), + allowSingleClick = true, + allowLongClick = true + ) { itemView, _ -> + setupView(view = itemView, timer = getItem(position), holder = holder) } bindViewHolder(holder) } @@ -180,10 +186,10 @@ class TimerAdapter( timerTime.setTextColor(textColor) timerTime.text = when (timer.state) { - is TimerState.Finished -> 0.getFormattedDuration() - is TimerState.Idle -> timer.seconds.getFormattedDuration() - is TimerState.Paused -> timer.state.tick.getFormattedDuration() - is TimerState.Running -> timer.state.tick.getFormattedDuration() + is Finished -> 0.getFormattedDuration() + is Idle -> timer.seconds.getFormattedDuration() + is Paused -> timer.state.tick.getFormattedDuration() + is Running -> timer.state.tick.getFormattedDuration() } timerReset.applyColorFilter(textColor) @@ -193,32 +199,52 @@ class TimerAdapter( timerPlayPause.applyColorFilter(textColor) timerPlayPause.setOnClickListener { - (activity as SimpleActivity).handleNotificationPermission { granted -> - if (granted) { - when (val state = timer.state) { - is TimerState.Idle -> EventBus.getDefault().post(TimerEvent.Start(timer.id!!, timer.seconds.secondsToMillis)) - is TimerState.Paused -> EventBus.getDefault().post(TimerEvent.Start(timer.id!!, state.tick)) - is TimerState.Running -> EventBus.getDefault().post(TimerEvent.Pause(timer.id!!, state.tick)) - is TimerState.Finished -> EventBus.getDefault().post(TimerEvent.Start(timer.id!!, timer.seconds.secondsToMillis)) - } - } else { - PermissionRequiredDialog( - activity, - org.fossify.commons.R.string.allow_notifications_reminders, - { activity.openNotificationSettings() }) - } - } + toggleTimer(timer) } val state = timer.state - val resetPossible = state is TimerState.Running || state is TimerState.Paused || state is TimerState.Finished + val resetPossible = state is Running || state is Paused || state is Finished timerReset.beInvisibleIf(!resetPossible) - val drawableId = if (state is TimerState.Running) { - org.fossify.commons.R.drawable.ic_pause_vector + timerPlayPause.setImageDrawable( + simpleActivity.resources.getColoredDrawableWithColor( + drawableId = if (state is Running) { + org.fossify.commons.R.drawable.ic_pause_vector + } else { + org.fossify.commons.R.drawable.ic_play_vector + }, + color = textColor + ) + ) + } + } + + private fun toggleTimer(timer: Timer) { + (activity as SimpleActivity).handleNotificationPermission { granted -> + if (granted) { + when (val state = timer.state) { + is Idle -> EventBus.getDefault().post( + TimerEvent.Start(timer.id!!, timer.seconds.secondsToMillis) + ) + + is Paused -> EventBus.getDefault().post( + TimerEvent.Start(timer.id!!, state.tick) + ) + + is Running -> EventBus.getDefault().post( + TimerEvent.Pause(timer.id!!, state.tick) + ) + + is Finished -> EventBus.getDefault().post( + TimerEvent.Start(timer.id!!, timer.seconds.secondsToMillis) + ) + } } else { - org.fossify.commons.R.drawable.ic_play_vector + PermissionRequiredDialog( + activity = activity, + textId = org.fossify.commons.R.string.allow_notifications_reminders, + positiveActionCallback = { activity.openNotificationSettings() } + ) } - timerPlayPause.setImageDrawable(simpleActivity.resources.getColoredDrawableWithColor(drawableId, textColor)) } } @@ -244,6 +270,7 @@ class TimerAdapter( private fun saveAlarmsCustomOrder(alarms: ArrayList) { val timersCustomSortingIds = alarms.map { it.id } - simpleActivity.config.timersCustomSorting = timersCustomSortingIds.joinToString { it.toString() } + simpleActivity.config.timersCustomSorting = + timersCustomSortingIds.joinToString { it.toString() } } } From 89da9ffdf03f81f2ab7a41768b0c0389499ac242 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Thu, 6 Mar 2025 00:31:23 +0530 Subject: [PATCH 25/27] Revert change in label constraints --- app/src/main/res/layout/item_alarm.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/item_alarm.xml b/app/src/main/res/layout/item_alarm.xml index e416bdd5..f3e88470 100644 --- a/app/src/main/res/layout/item_alarm.xml +++ b/app/src/main/res/layout/item_alarm.xml @@ -34,7 +34,7 @@ android:maxLines="1" android:paddingHorizontal="@dimen/tiny_margin" android:textSize="@dimen/bigger_text_size" - app:layout_constraintEnd_toEndOf="@id/alarm_switch" + app:layout_constraintEnd_toStartOf="@id/alarm_switch" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/alarm_time" tools:text="Mon, Tue, Wed, Thu, Fri" /> @@ -48,7 +48,7 @@ android:maxLines="1" android:paddingHorizontal="@dimen/tiny_margin" android:textSize="@dimen/bigger_text_size" - app:layout_constraintEnd_toEndOf="@id/alarm_switch" + app:layout_constraintEnd_toStartOf="@id/alarm_switch" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/alarm_days" tools:text="Good morning!" /> From 7d9f32617df68a9123f7ebf0f4002efd1b8445f7 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Thu, 6 Mar 2025 00:43:44 +0530 Subject: [PATCH 26/27] Remove reorder by dragging content description Should be added in commons --- app/src/main/res/layout/item_alarm.xml | 1 - app/src/main/res/values/strings.xml | 1 - 2 files changed, 2 deletions(-) diff --git a/app/src/main/res/layout/item_alarm.xml b/app/src/main/res/layout/item_alarm.xml index f3e88470..1ef82317 100644 --- a/app/src/main/res/layout/item_alarm.xml +++ b/app/src/main/res/layout/item_alarm.xml @@ -67,7 +67,6 @@ android:id="@+id/alarm_drag_handle" android:layout_width="@dimen/drag_handle_size" android:layout_height="@dimen/drag_handle_size" - android:contentDescription="@string/reorder_by_dragging" android:paddingHorizontal="@dimen/medium_margin" android:src="@drawable/ic_drag_handle_vector" android:visibility="gone" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5ac5ee84..5990fe5e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,7 +33,6 @@ Add timer Upcoming alarm Early alarm dismissal - Reorder items by dragging Timers are running From 99904a8147c248542186eedb67789ca5389d7d7d Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Thu, 6 Mar 2025 00:50:10 +0530 Subject: [PATCH 27/27] Remove reorder by dragging content description Should be added back once commons is updated --- app/src/main/res/layout/item_timer.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/res/layout/item_timer.xml b/app/src/main/res/layout/item_timer.xml index 44facc71..96c90298 100644 --- a/app/src/main/res/layout/item_timer.xml +++ b/app/src/main/res/layout/item_timer.xml @@ -78,7 +78,6 @@ android:layout_width="@dimen/drag_handle_size" android:layout_height="@dimen/drag_handle_size" android:layout_marginStart="@dimen/medium_margin" - android:contentDescription="@string/reorder_by_dragging" android:padding="@dimen/medium_margin" android:src="@drawable/ic_drag_handle_vector" android:visibility="gone"