Skip to content

Commit 149d1ee

Browse files
Refactor on this day game to use LocalDate
1 parent 4464e3d commit 149d1ee

File tree

4 files changed

+51
-112
lines changed

4 files changed

+51
-112
lines changed

app/src/main/java/org/wikipedia/games/db/DailyGameHistory.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package org.wikipedia.games.db
22

33
import androidx.room.Entity
4+
import androidx.room.Ignore
45
import androidx.room.PrimaryKey
6+
import java.time.LocalDate
57

68
@Entity
79
data class DailyGameHistory(
@@ -14,4 +16,7 @@ data class DailyGameHistory(
1416
var score: Int,
1517
var playType: Int,
1618
var gameData: String?
17-
)
19+
) {
20+
@Ignore
21+
val date: LocalDate = LocalDate.of(year, month, day)
22+
}

app/src/main/java/org/wikipedia/games/onthisday/DateDecorator.kt

Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,18 @@ package org.wikipedia.games.onthisday
22

33
import android.content.Context
44
import android.content.res.ColorStateList
5-
import android.os.Parcel
6-
import android.os.Parcelable
75
import androidx.core.content.ContextCompat
86
import com.google.android.material.datepicker.DayViewDecorator
7+
import kotlinx.parcelize.Parcelize
98
import org.wikipedia.R
10-
import java.util.Calendar
11-
import java.util.Date
9+
import java.time.LocalDate
1210

11+
@Parcelize
1312
class DateDecorator(
14-
private val startDate: Date,
15-
private val endDate: Date,
16-
private val scoreData: Map<Long, Int>
13+
private val startDate: LocalDate,
14+
private val endDate: LocalDate,
15+
private val scoreData: Map<LocalDate, Int>
1716
) : DayViewDecorator() {
18-
19-
private val calendar = Calendar.getInstance()
20-
21-
private fun isDateInRange(year: Int, month: Int, day: Int): Boolean {
22-
synchronized(calendar) {
23-
calendar.set(year, month, day, 0, 0, 0)
24-
calendar.set(Calendar.MILLISECOND, 0)
25-
26-
return !calendar.before(startDate) && !calendar.after(endDate)
27-
}
28-
}
29-
3017
override fun getBackgroundColor(
3118
context: Context,
3219
year: Int,
@@ -35,14 +22,12 @@ class DateDecorator(
3522
valid: Boolean,
3623
selected: Boolean
3724
): ColorStateList? {
38-
if (!isDateInRange(year, month, day)) {
25+
val date = LocalDate.of(year, month + 1, day)
26+
if (date !in startDate..endDate) {
3927
return null
4028
}
4129

42-
val dateKey = getDateKey(year, month + 1, day)
43-
val score = scoreData[dateKey]
44-
45-
return when (score) {
30+
return when (scoreData[date]) {
4631
0, 1, 2 -> ColorStateList.valueOf(ContextCompat.getColor(context, R.color.yellow200))
4732
3, 4 -> ColorStateList.valueOf(ContextCompat.getColor(context, R.color.orange200))
4833
5 -> ColorStateList.valueOf(ContextCompat.getColor(context, R.color.green600))
@@ -58,36 +43,12 @@ class DateDecorator(
5843
valid: Boolean,
5944
selected: Boolean
6045
): ColorStateList? {
61-
val dateKey = getDateKey(year, month + 1, day)
62-
val score = scoreData[dateKey]
46+
val date = LocalDate.of(year, month + 1, day)
47+
val score = scoreData[date]
6348

6449
return when (score) {
6550
null -> super.getTextColor(context, year, month, day, valid, selected)
6651
else -> ColorStateList.valueOf(ContextCompat.getColor(context, R.color.gray700))
6752
}
6853
}
69-
70-
constructor(parcel: Parcel) : this(
71-
Date(),
72-
Date(),
73-
hashMapOf()
74-
)
75-
76-
override fun describeContents(): Int { return 0 }
77-
78-
override fun writeToParcel(dest: Parcel, flags: Int) {}
79-
80-
companion object CREATOR : Parcelable.Creator<DateDecorator> {
81-
override fun createFromParcel(parcel: Parcel): DateDecorator {
82-
return DateDecorator(parcel)
83-
}
84-
85-
override fun newArray(size: Int): Array<DateDecorator?> {
86-
return arrayOfNulls(size)
87-
}
88-
89-
fun getDateKey(year: Int, month: Int, day: Int): Long {
90-
return (year * 10000 + month * 100 + day).toLong()
91-
}
92-
}
9354
}

app/src/main/java/org/wikipedia/games/onthisday/OnThisDayGameBaseFragment.kt

Lines changed: 29 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@ import org.wikipedia.analytics.eventplatform.WikiGamesEvent
1919
import org.wikipedia.games.onthisday.OnThisDayGameViewModel.Companion.LANG_CODES_SUPPORTED
2020
import org.wikipedia.games.onthisday.OnThisDayGameViewModel.Companion.dateReleasedForLang
2121
import org.wikipedia.util.log.L
22+
import java.time.Instant
2223
import java.time.LocalDate
2324
import java.time.ZoneId
24-
import java.time.ZoneOffset
25-
import java.util.Calendar
26-
import java.util.Date
27-
import java.util.TimeZone
25+
import java.time.temporal.ChronoUnit
2826

2927
abstract class OnThisDayGameBaseFragment : Fragment() {
30-
private var scoreData: Map<Long, Int> = emptyMap()
28+
private var scoreData = emptyMap<LocalDate, Int>()
3129

3230
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
3331
@SuppressLint("RestrictedApi")
@@ -38,7 +36,7 @@ abstract class OnThisDayGameBaseFragment : Fragment() {
3836
(calendar as MaterialCalendar<Long>?)?.addOnSelectionChangedListener(object :
3937
OnSelectionChangedListener<Long>() {
4038
override fun onSelectionChanged(selection: Long) {
41-
maybeShowToastForDate(selection, scoreData)
39+
maybeShowToastForDate(selection)
4240
}
4341
})
4442
}
@@ -58,90 +56,66 @@ abstract class OnThisDayGameBaseFragment : Fragment() {
5856
protected fun prepareAndOpenArchiveCalendar(viewModel: OnThisDayGameViewModel) {
5957
lifecycleScope.launch {
6058
val startDateBasedOnLanguage = LANG_CODES_SUPPORTED.associateWith { dateReleasedForLang(it) }
61-
val localDate = startDateBasedOnLanguage[viewModel.wikiSite.languageCode]
62-
val startDate = Date.from(localDate?.atStartOfDay(ZoneId.systemDefault())?.toInstant())
59+
val startDate = startDateBasedOnLanguage[viewModel.wikiSite.languageCode]!!
6360
scoreData = viewModel.getDataForArchiveCalendar(language = viewModel.wikiSite.languageCode)
64-
showArchiveCalendar(
65-
startDate,
66-
Date(),
67-
scoreData,
68-
onDateSelected = { selectedDateInMillis ->
69-
handleDateSelection(selectedDateInMillis)
70-
}
71-
)
61+
showArchiveCalendar(startDate, onDateSelected = ::handleDateSelection)
7262
}
7363
}
7464

75-
private fun showArchiveCalendar(startDate: Date, endDate: Date, scoreData: Map<Long, Int>, onDateSelected: (Long) -> Unit) {
76-
val startTimeInMillis = startDate.time
77-
val endTimeInMillis = endDate.time
65+
private fun showArchiveCalendar(startDate: LocalDate, onDateSelected: (Long) -> Unit) {
66+
val startInstant = startDate.atStartOfDay(ZoneId.systemDefault()).toInstant()
67+
val startTimeInMillis = startInstant.toEpochMilli()
68+
val endInstant = Instant.now()
69+
val endTimeInMillis = endInstant.toEpochMilli()
70+
val oneDayBeforeStart = startInstant.minus(1, ChronoUnit.DAYS).toEpochMilli()
7871
val calendarConstraints = CalendarConstraints.Builder()
79-
.setStart(startDate.time)
72+
.setStart(startTimeInMillis)
8073
.setEnd(endTimeInMillis)
8174
.setValidator(
8275
CompositeDateValidator.allOf(
8376
listOf(
84-
DateValidatorPointForward.from(startTimeInMillis - (24 * 60 * 60 * 1000)),
77+
DateValidatorPointForward.from(oneDayBeforeStart),
8578
DateValidatorPointBackward.before(endTimeInMillis)
8679
)
8780
)
8881
)
8982
.build()
9083

84+
val endDate = LocalDate.ofInstant(endInstant, ZoneId.systemDefault())
9185
val datePicker = MaterialDatePicker.Builder.datePicker()
9286
.setTitleText(getString(R.string.on_this_day_game_archive_calendar_title))
9387
.setTheme(R.style.MaterialDatePickerStyle)
94-
.setDayViewDecorator(
95-
DateDecorator(
96-
startDate,
97-
endDate,
98-
scoreData
99-
)
100-
)
88+
.setDayViewDecorator(DateDecorator(startDate, endDate, scoreData))
10189
.setCalendarConstraints(calendarConstraints)
10290
.setSelection(endTimeInMillis)
10391
.build()
10492
.apply {
105-
addOnPositiveButtonClickListener { selectedDateInMillis ->
106-
onDateSelected(selectedDateInMillis)
107-
}
93+
addOnPositiveButtonClickListener(onDateSelected)
10894
}
10995

11096
datePicker.show(childFragmentManager, "datePicker")
11197
}
11298

11399
private fun handleDateSelection(selectedDateInMillis: Long) {
114-
val calendar = Calendar.getInstance(TimeZone.getTimeZone(ZoneOffset.UTC))
115-
calendar.timeInMillis = selectedDateInMillis
116-
val year = calendar.get(Calendar.YEAR)
117-
val month = calendar.get(Calendar.MONTH) + 1
118-
val day = calendar.get(Calendar.DAY_OF_MONTH)
119-
val scoreDataKey = DateDecorator.getDateKey(year, month, day)
120-
if (scoreData[scoreDataKey] != null) {
100+
val localDate = LocalDate.ofInstant(Instant.ofEpochMilli(selectedDateInMillis),
101+
ZoneId.systemDefault())
102+
if (scoreData[localDate] != null) {
121103
return
122104
}
123105
WikiGamesEvent.submit("date_select", "game_play", slideName = "archive_calendar")
124-
onArchiveDateSelected(LocalDate.of(year, month, day))
106+
onArchiveDateSelected(localDate)
125107
}
126108

127109
abstract fun onArchiveDateSelected(date: LocalDate)
128110

129-
private fun maybeShowToastForDate(selectedDateInMillis: Long, scoreData: Map<Long, Int>) {
130-
val calendar = Calendar.getInstance(TimeZone.getTimeZone(ZoneOffset.UTC))
131-
calendar.timeInMillis = selectedDateInMillis
132-
val year = calendar.get(Calendar.YEAR)
133-
val month = calendar.get(Calendar.MONTH)
134-
val day = calendar.get(Calendar.DAY_OF_MONTH)
135-
val scoreDataKey = DateDecorator.getDateKey(year, month + 1, day)
136-
if (scoreData[scoreDataKey] != null) {
137-
Toast.makeText(
138-
requireContext(),
139-
getString(
140-
R.string.on_this_day_game_score_toast_message,
141-
scoreData[scoreDataKey],
142-
OnThisDayGameViewModel.MAX_QUESTIONS
143-
), Toast.LENGTH_SHORT
144-
).show()
111+
private fun maybeShowToastForDate(selectedDateInMillis: Long) {
112+
val localDate = LocalDate.ofInstant(Instant.ofEpochMilli(selectedDateInMillis),
113+
ZoneId.systemDefault())
114+
val score = scoreData[localDate]
115+
if (score != null) {
116+
val message = getString(R.string.on_this_day_game_score_toast_message, score,
117+
OnThisDayGameViewModel.MAX_QUESTIONS)
118+
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
145119
}
146120
}
147121

app/src/main/java/org/wikipedia/games/onthisday/OnThisDayGameViewModel.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -312,13 +312,12 @@ class OnThisDayGameViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
312312
return event.pages.firstOrNull { !it.thumbnailUrl.isNullOrEmpty() }?.thumbnailUrl
313313
}
314314

315-
suspend fun getDataForArchiveCalendar(gameName: Int = WikiGames.WHICH_CAME_FIRST.ordinal, language: String): Map<Long, Int> {
315+
suspend fun getDataForArchiveCalendar(
316+
gameName: Int = WikiGames.WHICH_CAME_FIRST.ordinal,
317+
language: String
318+
): Map<LocalDate, Int> {
316319
val history = AppDatabase.instance.dailyGameHistoryDao().getGameHistory(gameName, language)
317-
val map = history.associate {
318-
val scoreKey = DateDecorator.getDateKey(it.year, it.month, it.day)
319-
scoreKey to it.score
320-
}
321-
return map
320+
return history.associate { it.date to it.score }
322321
}
323322

324323
fun getCurrentGameState(): GameState {

0 commit comments

Comments
 (0)