Skip to content

Commit d8f6daa

Browse files
authored
Merge pull request #67 from ronniedroid/timers_sort
FEAT: added Sorting dialog to the timer tab
2 parents 208b2e3 + cb73377 commit d8f6daa

File tree

9 files changed

+176
-21
lines changed

9 files changed

+176
-21
lines changed

app/src/main/kotlin/org/fossify/clock/activities/MainActivity.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import org.fossify.clock.BuildConfig
1313
import org.fossify.clock.R
1414
import org.fossify.clock.adapters.ViewPagerAdapter
1515
import org.fossify.clock.databinding.ActivityMainBinding
16-
import org.fossify.clock.extensions.*
16+
import org.fossify.clock.extensions.config
17+
import org.fossify.clock.extensions.getEnabledAlarms
18+
import org.fossify.clock.extensions.rescheduleEnabledAlarms
19+
import org.fossify.clock.extensions.updateWidgets
1720
import org.fossify.clock.helpers.*
1821
import org.fossify.commons.databinding.BottomTablayoutItemBinding
1922
import org.fossify.commons.extensions.*
@@ -127,7 +130,11 @@ class MainActivity : SimpleActivity() {
127130
private fun setupOptionsMenu() {
128131
binding.mainToolbar.setOnMenuItemClickListener { menuItem ->
129132
when (menuItem.itemId) {
130-
R.id.sort -> getViewPagerAdapter()?.showAlarmSortDialog()
133+
R.id.sort -> when (binding.viewPager.currentItem) {
134+
TAB_ALARM_INDEX -> getViewPagerAdapter()?.showAlarmSortDialog()
135+
TAB_TIMER_INDEX -> getViewPagerAdapter()?.showTimerSortDialog()
136+
}
137+
131138
R.id.more_apps_from_us -> launchMoreAppsFromUsIntent()
132139
R.id.settings -> launchSettings()
133140
R.id.about -> launchAbout()
@@ -139,7 +146,7 @@ class MainActivity : SimpleActivity() {
139146

140147
private fun refreshMenuItems() {
141148
binding.mainToolbar.menu.apply {
142-
findItem(R.id.sort).isVisible = binding.viewPager.currentItem == getTabIndex(TAB_ALARM)
149+
findItem(R.id.sort).isVisible = binding.viewPager.currentItem == getTabIndex(TAB_ALARM) || binding.viewPager.currentItem == getTabIndex(TAB_TIMER)
143150
findItem(R.id.more_apps_from_us).isVisible = !resources.getBoolean(org.fossify.commons.R.bool.hide_google_relations)
144151
}
145152
}

app/src/main/kotlin/org/fossify/clock/adapters/TimerAdapter.kt

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ import org.fossify.clock.models.TimerEvent
1616
import org.fossify.clock.models.TimerState
1717
import org.fossify.commons.adapters.MyRecyclerViewListAdapter
1818
import org.fossify.commons.dialogs.PermissionRequiredDialog
19-
import org.fossify.commons.extensions.*
19+
import org.fossify.commons.extensions.adjustAlpha
20+
import org.fossify.commons.extensions.applyColorFilter
21+
import org.fossify.commons.extensions.beInvisibleIf
22+
import org.fossify.commons.extensions.getColoredDrawableWithColor
23+
import org.fossify.commons.extensions.getFormattedDuration
24+
import org.fossify.commons.extensions.openNotificationSettings
2025
import org.fossify.commons.views.MyRecyclerView
2126
import org.greenrobot.eventbus.EventBus
2227

@@ -41,6 +46,24 @@ class TimerAdapter(
4146

4247
init {
4348
setupDragListener(true)
49+
setHasStableIds(true)
50+
}
51+
52+
override fun getItemId(position: Int): Long {
53+
return getItem(position).id!!.toLong()
54+
}
55+
56+
override fun submitList(list: MutableList<Timer>?, commitCallback: Runnable?) {
57+
val layoutManager = recyclerView.layoutManager!!
58+
val recyclerViewState = layoutManager.onSaveInstanceState()
59+
super.submitList(list) {
60+
layoutManager.onRestoreInstanceState(recyclerViewState)
61+
commitCallback?.run()
62+
}
63+
}
64+
65+
override fun submitList(list: MutableList<Timer>?) {
66+
submitList(list, null)
4467
}
4568

4669
override fun getActionMenuId() = R.menu.cab_alarms

app/src/main/kotlin/org/fossify/clock/adapters/ViewPagerAdapter.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ class ViewPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) {
4545
(fragments[TAB_ALARM_INDEX] as? AlarmFragment)?.showSortingDialog()
4646
}
4747

48+
fun showTimerSortDialog() {
49+
(fragments[TAB_TIMER_INDEX] as? TimerFragment)?.showSortingDialog()
50+
}
51+
4852
fun updateClockTabAlarm() {
4953
(fragments[TAB_CLOCK_INDEX] as? ClockFragment)?.updateAlarm()
5054
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.fossify.clock.dialogs
2+
3+
import org.fossify.clock.R
4+
import org.fossify.clock.databinding.DialogChangeTimerSortBinding
5+
import org.fossify.clock.extensions.config
6+
import org.fossify.clock.helpers.SORT_BY_CREATION_ORDER
7+
import org.fossify.clock.helpers.SORT_BY_TIMER_DURATION
8+
import org.fossify.commons.activities.BaseSimpleActivity
9+
import org.fossify.commons.extensions.getAlertDialogBuilder
10+
import org.fossify.commons.extensions.setupDialogStuff
11+
12+
class ChangeTimerSortDialog(val activity: BaseSimpleActivity, val callback: () -> Unit) {
13+
private val binding = DialogChangeTimerSortBinding.inflate(activity.layoutInflater).apply {
14+
val activeRadioButton = when (activity.config.timerSort) {
15+
SORT_BY_TIMER_DURATION -> sortingDialogRadioTimerDuration
16+
else -> sortingDialogRadioCreationOrder
17+
}
18+
activeRadioButton.isChecked = true
19+
}
20+
21+
init {
22+
activity.getAlertDialogBuilder()
23+
.setPositiveButton(org.fossify.commons.R.string.ok) { _, _ -> dialogConfirmed() }
24+
.setNegativeButton(org.fossify.commons.R.string.cancel, null)
25+
.apply {
26+
activity.setupDialogStuff(binding.root, this, org.fossify.commons.R.string.sort_by)
27+
}
28+
}
29+
30+
private fun dialogConfirmed() {
31+
val sort = when (binding.sortingDialogRadioSorting.checkedRadioButtonId) {
32+
R.id.sorting_dialog_radio_timer_duration -> SORT_BY_TIMER_DURATION
33+
else -> SORT_BY_CREATION_ORDER
34+
}
35+
36+
activity.config.timerSort = sort
37+
callback()
38+
}
39+
}

app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,26 @@ import androidx.fragment.app.Fragment
1010
import org.fossify.clock.activities.SimpleActivity
1111
import org.fossify.clock.adapters.TimerAdapter
1212
import org.fossify.clock.databinding.FragmentTimerBinding
13+
import org.fossify.clock.dialogs.ChangeTimerSortDialog
1314
import org.fossify.clock.dialogs.EditTimerDialog
1415
import org.fossify.clock.extensions.config
1516
import org.fossify.clock.extensions.createNewTimer
1617
import org.fossify.clock.extensions.timerHelper
1718
import org.fossify.clock.helpers.DisabledItemChangeAnimator
19+
import org.fossify.clock.helpers.SORT_BY_TIMER_DURATION
1820
import org.fossify.clock.models.Timer
1921
import org.fossify.clock.models.TimerEvent
2022
import org.fossify.commons.extensions.getProperBackgroundColor
2123
import org.fossify.commons.extensions.getProperTextColor
2224
import org.fossify.commons.extensions.hideKeyboard
2325
import org.fossify.commons.extensions.updateTextColors
26+
import org.fossify.commons.helpers.SORT_BY_DATE_CREATED
2427
import org.fossify.commons.models.AlarmSound
2528
import org.greenrobot.eventbus.EventBus
2629
import org.greenrobot.eventbus.Subscribe
2730
import org.greenrobot.eventbus.ThreadMode
2831

2932
class TimerFragment : Fragment() {
30-
private val INVALID_POSITION = -1
3133
private lateinit var binding: FragmentTimerBinding
3234
private lateinit var timerAdapter: TimerAdapter
3335
private var timerPositionToScrollTo = INVALID_POSITION
@@ -43,7 +45,11 @@ class TimerFragment : Fragment() {
4345
super.onDestroy()
4446
}
4547

46-
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
48+
override fun onCreateView(
49+
inflater: LayoutInflater,
50+
container: ViewGroup?,
51+
savedInstanceState: Bundle?,
52+
): View {
4753
binding = FragmentTimerBinding.inflate(inflater, container, false).apply {
4854
timersList.itemAnimator = DisabledItemChangeAnimator()
4955
timerAdd.setOnClickListener {
@@ -73,7 +79,12 @@ class TimerFragment : Fragment() {
7379
timerAdapter.updateBackgroundColor(requireContext().getProperBackgroundColor())
7480
timerAdapter.updateTextColor(requireContext().getProperTextColor())
7581
} else {
76-
timerAdapter = TimerAdapter(requireActivity() as SimpleActivity, binding.timersList, ::refreshTimers, ::openEditTimer)
82+
timerAdapter = TimerAdapter(
83+
simpleActivity = requireActivity() as SimpleActivity,
84+
recyclerView = binding.timersList,
85+
onRefresh = ::refreshTimers,
86+
onItemClick = ::openEditTimer
87+
)
7788
binding.timersList.adapter = timerAdapter
7889
}
7990
}
@@ -85,16 +96,47 @@ class TimerFragment : Fragment() {
8596
refreshTimers()
8697
}
8798

88-
private fun refreshTimers(scrollToLatest: Boolean = false) {
99+
fun showSortingDialog() {
100+
ChangeTimerSortDialog(activity as SimpleActivity) {
101+
refreshTimers(
102+
animate = false // disable sorting animations for now.
103+
)
104+
}
105+
}
106+
107+
private fun getSortedTimers(callback: (List<Timer>) -> Unit) {
89108
activity?.timerHelper?.getTimers { timers ->
109+
val sortedTimers = when (requireContext().config.timerSort) {
110+
SORT_BY_TIMER_DURATION -> timers.sortedBy { it.seconds }
111+
SORT_BY_DATE_CREATED -> timers.sortedBy { it.id }
112+
else -> timers
113+
}
114+
90115
activity?.runOnUiThread {
91-
timerAdapter.submitList(timers) {
116+
callback(sortedTimers)
117+
}
118+
}
119+
}
120+
121+
private fun refreshTimers(animate: Boolean = true) {
122+
getSortedTimers { timers ->
123+
with(binding.timersList) {
124+
val originalAnimator = itemAnimator
125+
if (!animate) {
126+
itemAnimator = null
127+
}
128+
129+
timerAdapter.submitList(timers.toMutableList()) {
92130
view?.post {
93-
if (timerPositionToScrollTo != INVALID_POSITION && timerAdapter.itemCount > timerPositionToScrollTo) {
94-
binding.timersList.scrollToPosition(timerPositionToScrollTo)
131+
if (timerPositionToScrollTo != INVALID_POSITION &&
132+
timerAdapter.itemCount > timerPositionToScrollTo
133+
) {
134+
smoothScrollToPosition(timerPositionToScrollTo)
95135
timerPositionToScrollTo = INVALID_POSITION
96-
} else if (scrollToLatest) {
97-
binding.timersList.scrollToPosition(timers.lastIndex)
136+
}
137+
138+
if (!animate) {
139+
itemAnimator = originalAnimator
98140
}
99141
}
100142
}
@@ -112,15 +154,13 @@ class TimerFragment : Fragment() {
112154
}
113155

114156
fun updatePosition(timerId: Int) {
115-
activity?.timerHelper?.getTimers { timers ->
157+
getSortedTimers { timers ->
116158
val position = timers.indexOfFirst { it.id == timerId }
117159
if (position != INVALID_POSITION) {
118-
activity?.runOnUiThread {
119-
if (timerAdapter.itemCount > position) {
120-
binding.timersList.scrollToPosition(position)
121-
} else {
122-
timerPositionToScrollTo = position
123-
}
160+
if (timerAdapter.itemCount > position) {
161+
binding.timersList.smoothScrollToPosition(position)
162+
} else {
163+
timerPositionToScrollTo = position
124164
}
125165
}
126166
}
@@ -133,3 +173,5 @@ class TimerFragment : Fragment() {
133173
}
134174
}
135175
}
176+
177+
private const val INVALID_POSITION = -1

app/src/main/kotlin/org/fossify/clock/helpers/Config.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ class Config(context: Context) : BaseConfig(context) {
5959
get() = prefs.getInt(ALARMS_SORT_BY, SORT_BY_CREATION_ORDER)
6060
set(alarmSort) = prefs.edit().putInt(ALARMS_SORT_BY, alarmSort).apply()
6161

62+
var timerSort: Int
63+
get() = prefs.getInt(TIMERS_SORT_BY, SORT_BY_CREATION_ORDER)
64+
set(timerSort) = prefs.edit().putInt(TIMERS_SORT_BY, timerSort).apply()
65+
6266
var alarmMaxReminderSecs: Int
6367
get() = prefs.getInt(ALARM_MAX_REMINDER_SECS, DEFAULT_MAX_ALARM_REMINDER_SECS)
6468
set(alarmMaxReminderSecs) = prefs.edit().putInt(ALARM_MAX_REMINDER_SECS, alarmMaxReminderSecs).apply()

app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const val ALARM_LAST_CONFIG = "alarm_last_config"
2424
const val TIMER_LAST_CONFIG = "timer_last_config"
2525
const val INCREASE_VOLUME_GRADUALLY = "increase_volume_gradually"
2626
const val ALARMS_SORT_BY = "alarms_sort_by"
27+
const val TIMERS_SORT_BY = "timers_sort_by"
2728
const val STOPWATCH_LAPS_SORT_BY = "stopwatch_laps_sort_by"
2829
const val WAS_INITIAL_WIDGET_SET_UP = "was_initial_widget_set_up"
2930
const val DATA_EXPORT_EXTENSION = ".json"
@@ -70,10 +71,11 @@ const val SORT_BY_LAP = 1
7071
const val SORT_BY_LAP_TIME = 2
7172
const val SORT_BY_TOTAL_TIME = 4
7273

73-
// alarm sorting
74+
// alarm and timer sorting
7475
const val SORT_BY_CREATION_ORDER = 0
7576
const val SORT_BY_ALARM_TIME = 1
7677
const val SORT_BY_DATE_AND_TIME = 2
78+
const val SORT_BY_TIMER_DURATION = 3
7779

7880
const val TODAY_BIT = -1
7981
const val TOMORROW_BIT = -2
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:id="@+id/sorting_dialog_scrollview"
4+
android:layout_width="match_parent"
5+
android:layout_height="match_parent">
6+
7+
<RadioGroup
8+
android:id="@+id/sorting_dialog_radio_sorting"
9+
android:layout_width="match_parent"
10+
android:layout_height="wrap_content"
11+
android:layout_marginBottom="@dimen/medium_margin"
12+
android:paddingStart="@dimen/activity_margin"
13+
android:paddingTop="@dimen/activity_margin"
14+
android:paddingEnd="@dimen/activity_margin">
15+
16+
<org.fossify.commons.views.MyCompatRadioButton
17+
android:id="@+id/sorting_dialog_radio_creation_order"
18+
android:layout_width="match_parent"
19+
android:layout_height="wrap_content"
20+
android:paddingTop="@dimen/medium_margin"
21+
android:paddingBottom="@dimen/medium_margin"
22+
android:text="@string/sort_by_creation_order" />
23+
24+
<org.fossify.commons.views.MyCompatRadioButton
25+
android:id="@+id/sorting_dialog_radio_timer_duration"
26+
android:layout_width="match_parent"
27+
android:layout_height="wrap_content"
28+
android:paddingTop="@dimen/medium_margin"
29+
android:paddingBottom="@dimen/medium_margin"
30+
android:text="@string/sort_by_timer_duration" />
31+
32+
</RadioGroup>
33+
</ScrollView>

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<string name="swipe_right_to_dismiss">Swipe right to Dismiss, or left to Snooze.</string>
1919
<string name="sort_by_creation_order">Creation order</string>
2020
<string name="sort_by_alarm_time">Alarm time</string>
21+
<string name="sort_by_timer_duration">Timer duration</string>
2122
<string name="sort_by_day_and_alarm_time">Day and Alarm time</string>
2223
<string name="analogue_clock">Analogue clock</string>
2324
<string name="digital_clock">Digital clock</string>

0 commit comments

Comments
 (0)