Skip to content

Commit

Permalink
[Compose][Fix] Changing firstDayOfWeek does not refresh the current…
Browse files Browse the repository at this point in the history
… month #514
  • Loading branch information
kizitonwose committed Dec 13, 2023
1 parent 8c6a2aa commit bbdf35d
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ private fun Calendar(
contentPadding = contentPadding,
) {
CalendarMonths(
monthCount = state.monthIndexCount,
monthCount = state.calendarInfo.indexCount,
monthData = { offset -> state.store[offset] },
contentHeightMode = contentHeightMode,
dayContent = dayContent,
Expand All @@ -196,7 +196,7 @@ private fun Calendar(
contentPadding = contentPadding,
) {
CalendarMonths(
monthCount = state.monthIndexCount,
monthCount = state.calendarInfo.indexCount,
monthData = { offset -> state.store[offset] },
contentHeightMode = contentHeightMode,
dayContent = dayContent,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.kizitonwose.calendar.compose

import com.kizitonwose.calendar.core.OutDateStyle
import java.time.DayOfWeek

internal data class CalendarInfo(
val indexCount: Int,
private val firstDayOfWeek: DayOfWeek? = null,
private val outDateStyle: OutDateStyle? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class CalendarState internal constructor(
firstVisibleItemScrollOffset = visibleItemState?.firstVisibleItemScrollOffset ?: 0,
)

internal var monthIndexCount by mutableStateOf(0)
internal var calendarInfo by mutableStateOf(CalendarInfo(indexCount = 0))

internal val store = DataStore { offset ->
getCalendarMonthData(
Expand All @@ -200,7 +200,16 @@ class CalendarState internal constructor(
private fun monthDataChanged() {
store.clear()
checkDateRange(startMonth, endMonth)
monthIndexCount = getMonthIndicesCount(startMonth, endMonth)
// Read the firstDayOfWeek and outDateStyle properties to ensure recomposition
// even though they are unused in the CalendarInfo. Alternatively, we could use
// mutableStateMapOf() as the backing store for DataStore() to ensure recomposition
// but not sure how compose handles recomposition of a lazy list that reads from
// such map when an entry unrelated to the visible indices changes.
calendarInfo = CalendarInfo(
indexCount = getMonthIndicesCount(startMonth, endMonth),
firstDayOfWeek = firstDayOfWeek,
outDateStyle = outDateStyle,
)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ internal fun HeatMapCalendarImpl(
contentPadding = contentPadding,
) {
items(
count = state.monthIndexCount,
count = state.calendarInfo.indexCount,
key = { offset -> state.store[offset].yearMonth },
) { offset ->
val calendarMonth = state.store[offset]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import com.kizitonwose.calendar.compose.CalendarInfo
import com.kizitonwose.calendar.compose.CalendarLayoutInfo
import com.kizitonwose.calendar.compose.VisibleItemState
import com.kizitonwose.calendar.core.CalendarMonth
Expand Down Expand Up @@ -162,7 +163,7 @@ class HeatMapCalendarState internal constructor(
firstVisibleItemScrollOffset = visibleItemState?.firstVisibleItemScrollOffset ?: 0,
)

internal var monthIndexCount by mutableStateOf(0)
internal var calendarInfo by mutableStateOf(CalendarInfo(indexCount = 0))

internal val store = DataStore { offset ->
getHeatMapCalendarMonthData(
Expand All @@ -179,7 +180,10 @@ class HeatMapCalendarState internal constructor(
private fun monthDataChanged() {
store.clear()
checkDateRange(startMonth, endMonth)
monthIndexCount = getMonthIndicesCount(startMonth, endMonth)
calendarInfo = CalendarInfo(
indexCount = getMonthIndicesCount(startMonth, endMonth),
firstDayOfWeek = firstDayOfWeek,
)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.listSaver
Expand Down Expand Up @@ -179,7 +180,7 @@ class WeekCalendarState internal constructor(
).week
}

internal var weekIndexCount by mutableStateOf(0)
internal var weekIndexCount by mutableIntStateOf(0)

internal val listState = run {
// Update date range and weekIndexCount initially.
Expand Down
7 changes: 5 additions & 2 deletions data/src/main/java/com/kizitonwose/calendar/data/DataStore.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ package com.kizitonwose.calendar.data
* Basically [MutableMap.getOrPut] but allows us read the map
* in multiple places without calling `getOrPut` everywhere.
*/
class DataStore<V>(private val create: (offset: Int) -> V) : HashMap<Int, V>() {
class DataStore<V>(
private val store: MutableMap<Int, V> = HashMap(),
private val create: (offset: Int) -> V,
) : MutableMap<Int, V> by store {
override fun get(key: Int): V {
val value = super.get(key)
val value = store[key]
return if (value == null) {
val data = create(key)
put(key, data)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
Expand Down Expand Up @@ -61,7 +62,7 @@ private enum class Level(val color: Color) {
}

private fun generateRandomData(startDate: LocalDate, endDate: LocalDate): Map<LocalDate, Level> {
val levels = Level.values()
val levels = Level.entries
return (0..ChronoUnit.DAYS.between(startDate, endDate))
.associateTo(hashMapOf()) { count ->
startDate.plusDays(count) to levels.random()
Expand All @@ -70,7 +71,7 @@ private fun generateRandomData(startDate: LocalDate, endDate: LocalDate): Map<Lo

@Composable
fun Example6Page() {
var refreshKey by remember { mutableStateOf(1) }
var refreshKey by remember { mutableIntStateOf(1) }
val endDate = remember { LocalDate.now() }
// GitHub only shows contributions for the past 12 months
val startDate = remember { endDate.minusMonths(12) }
Expand Down Expand Up @@ -173,7 +174,7 @@ private fun CalendarInfo(modifier: Modifier = Modifier) {
verticalAlignment = Alignment.Bottom,
) {
Text(text = "Less", fontSize = 10.sp)
Level.values().forEach { level ->
Level.entries.forEach { level ->
LevelBox(level.color)
}
Text(text = "More", fontSize = 10.sp)
Expand Down

0 comments on commit bbdf35d

Please sign in to comment.