Skip to content

Commit 965e88d

Browse files
committed
Simplify EventsCaches and change behavior of PagedEventsCache
The PagedEventsCache will now cache all events submitted to it until refresh() is called on WeekView.PagingAdapter.
1 parent 207ceac commit 965e88d

20 files changed

+257
-282
lines changed

core/src/main/java/com/alamkanak/weekview/CalendarRenderer.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,15 @@ private class SingleEventsDrawer(
234234
private val eventChipDrawer = EventChipDrawer(viewState)
235235

236236
override fun draw(canvas: Canvas) {
237-
for (date in viewState.dateRange) {
238-
drawEventsForDate(date, canvas)
237+
canvas.drawInBounds(
238+
left = viewState.timeColumnWidth,
239+
top = viewState.headerHeight,
240+
right = viewState.viewWidth.toFloat(),
241+
bottom = viewState.viewHeight.toFloat()
242+
) {
243+
for (date in viewState.dateRange) {
244+
drawEventsForDate(date, canvas)
245+
}
239246
}
240247
}
241248

core/src/main/java/com/alamkanak/weekview/CanvasExtensions.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ fun Canvas.withTranslation(x: Float, y: Float, block: Canvas.() -> Unit) {
1010
restore()
1111
}
1212

13-
fun Canvas.drawInRect(
13+
fun Canvas.drawInBounds(
1414
left: Float,
1515
top: Float,
1616
right: Float,

core/src/main/java/com/alamkanak/weekview/DateTimeInterpreter.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.alamkanak.weekview
22

33
import java.util.Calendar
44

5+
@Deprecated("Use setDateFormatter() and setTimeFormatter() instead.")
56
interface DateTimeInterpreter {
67
fun onSetNumberOfDays(days: Int) {
78
// Free ad space

core/src/main/java/com/alamkanak/weekview/EventChipDrawer.kt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,11 @@ internal class EventChipDrawer(
7272
}
7373

7474
if (event.style.borderWidth != null) {
75-
drawStroke(eventChip, canvas)
75+
drawBorderStroke(eventChip, canvas)
7676
}
7777
}
7878

79-
private fun drawStroke(
79+
private fun drawBorderStroke(
8080
eventChip: EventChip,
8181
canvas: Canvas
8282
) {
@@ -185,20 +185,20 @@ internal class EventChipDrawer(
185185
private fun updateBackgroundPaint(
186186
event: ResolvedWeekViewEvent<*>,
187187
paint: Paint
188-
) {
189-
paint.color = event.style.backgroundColor ?: viewState.defaultEventColor
190-
paint.isAntiAlias = true
191-
paint.strokeWidth = 0f
192-
paint.style = Paint.Style.FILL
188+
) = with(paint) {
189+
color = event.style.backgroundColor ?: viewState.defaultEventColor
190+
isAntiAlias = true
191+
strokeWidth = 0f
192+
style = Paint.Style.FILL
193193
}
194194

195195
private fun updateBorderPaint(
196196
event: ResolvedWeekViewEvent<*>,
197197
paint: Paint
198-
) {
199-
paint.color = event.style.borderColor ?: viewState.defaultEventColor
200-
paint.isAntiAlias = true
201-
paint.strokeWidth = event.style.borderWidth?.toFloat() ?: 0f
202-
paint.style = Paint.Style.STROKE
198+
) = with(paint) {
199+
color = event.style.borderColor ?: viewState.defaultEventColor
200+
isAntiAlias = true
201+
strokeWidth = event.style.borderWidth?.toFloat() ?: 0f
202+
style = Paint.Style.STROKE
203203
}
204204
}
Lines changed: 18 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,18 @@
11
package com.alamkanak.weekview
22

3-
import androidx.annotation.VisibleForTesting
3+
import androidx.collection.ArrayMap
44
import java.util.Calendar
55

6-
// /**
7-
// * Wraps all available [EventsCache]s to allow for dynamic switching between them.
8-
// */
9-
// internal class EventsCacheWrapper<T> {
10-
//
11-
// private val simpleEventsCache: EventsCache<T> = SimpleEventsCache()
12-
// private val pagedEventsCache: EventsCache<T> = PagedEventsCache()
13-
//
14-
// private var currentEventsCache = simpleEventsCache
15-
//
16-
// /**
17-
// * Returns the [EventsCache] that is currently in use.
18-
// */
19-
// fun get() = currentEventsCache
20-
//
21-
// /**
22-
// * Switches the currently used [EventsCache] to a [PagedEventsCache] (if [listener] is not null)
23-
// * or [SimpleEventsCache] (otherwise).
24-
// */
25-
// fun onListenerChanged(listener: OnMonthChangeListener<T>?) {
26-
// currentEventsCache = if (listener != null) pagedEventsCache else simpleEventsCache
27-
// }
28-
//
29-
// /**
30-
// * Switches the currently used [EventsCache] to a [PagedEventsCache] (if [listener] is not null)
31-
// * or [SimpleEventsCache] (otherwise).
32-
// */
33-
// fun onListenerChanged(listener: OnLoadMoreListener?) {
34-
// currentEventsCache = if (listener != null) pagedEventsCache else simpleEventsCache
35-
// }
36-
// }
37-
386
/**
397
* An abstract class that provides functionality to cache [WeekViewEvent]s.
408
*/
419
internal abstract class EventsCache<T> {
4210

4311
abstract val allEvents: List<ResolvedWeekViewEvent<T>>
12+
abstract fun update(events: List<ResolvedWeekViewEvent<T>>)
4413
abstract fun clear()
4514

46-
operator fun get(id: Long): ResolvedWeekViewEvent<T>? {
47-
return allEvents.firstOrNull { it.id == id }
48-
}
15+
operator fun get(id: Long): ResolvedWeekViewEvent<T>? = allEvents.firstOrNull { it.id == id }
4916

5017
operator fun get(
5118
dateRange: List<Calendar>
@@ -62,8 +29,6 @@ internal abstract class EventsCache<T> {
6229
val endTime = fetchRange.next.endDate
6330
return allEvents.filter { it.endTime >= startTime && it.startTime <= endTime }
6431
}
65-
66-
open operator fun get(period: Period): List<ResolvedWeekViewEvent<T>>? = null
6732
}
6833

6934
/**
@@ -77,7 +42,7 @@ internal class SimpleEventsCache<T> : EventsCache<T>() {
7742
override val allEvents: List<ResolvedWeekViewEvent<T>>
7843
get() = _allEvents.orEmpty()
7944

80-
fun update(events: List<ResolvedWeekViewEvent<T>>) {
45+
override fun update(events: List<ResolvedWeekViewEvent<T>>) {
8146
_allEvents = events
8247
}
8348

@@ -87,103 +52,34 @@ internal class SimpleEventsCache<T> : EventsCache<T>() {
8752
}
8853

8954
/**
90-
* Represents an [EventsCache] that caches [WeekViewEvent]s for a particular [FetchRange].
55+
* Represents an [EventsCache] that caches [ResolvedWeekViewEvent]s for their respective [Period]
56+
* and allows retrieval based on that [Period].
9157
*/
9258
internal class PagedEventsCache<T> : EventsCache<T>() {
9359

9460
override val allEvents: List<ResolvedWeekViewEvent<T>>
95-
get() = previousPeriodEvents.orEmpty() +
96-
currentPeriodEvents.orEmpty() +
97-
nextPeriodEvents.orEmpty()
98-
99-
private var previousPeriodEvents: List<ResolvedWeekViewEvent<T>>? = null
100-
private var currentPeriodEvents: List<ResolvedWeekViewEvent<T>>? = null
101-
private var nextPeriodEvents: List<ResolvedWeekViewEvent<T>>? = null
102-
103-
@VisibleForTesting
104-
internal var fetchedRange: FetchRange? = null
61+
get() = eventsByPeriod.values.flatten()
10562

106-
operator fun contains(period: Period) = fetchedRange?.periods?.contains(period) ?: false
63+
private val eventsByPeriod: ArrayMap<Period, List<ResolvedWeekViewEvent<T>>> = ArrayMap()
10764

108-
operator fun contains(fetchRange: FetchRange) = fetchedRange?.isEqual(fetchRange) ?: false
109-
110-
override fun get(period: Period): List<ResolvedWeekViewEvent<T>>? {
111-
val range = checkNotNull(fetchedRange)
112-
return when (period) {
113-
range.previous -> previousPeriodEvents
114-
range.current -> currentPeriodEvents
115-
range.next -> nextPeriodEvents
116-
else -> throw IllegalStateException("Requesting events for invalid period $period")
65+
override fun update(events: List<ResolvedWeekViewEvent<T>>) {
66+
val groupedEvents = events.groupBy { Period.fromDate(it.startTime) }
67+
for ((period, periodEvents) in groupedEvents) {
68+
eventsByPeriod[period] = periodEvents
11769
}
11870
}
11971

120-
/**
121-
* Adjusts the [WeekViewEvent]s of the fetched [Period]s to the new [FetchRange]. This means
122-
* that if the user scrolled to the next month, the following would happen:
123-
* 1. The events of the current month would be moved to [previousPeriodEvents].
124-
* 2. The events of the next month would be moved to [currentPeriodEvents].
125-
* 3. The events of the following month aren't loaded yet; [nextPeriodEvents] will be null.
126-
* 4. The [fetchedRange] will be set to the provided [FetchRange].
127-
*
128-
* When scrolling to the previous month, the behavior would be like so:
129-
* 1. The events of the current month would be moved to [nextPeriodEvents].
130-
* 2. The events of the previous month would be moved to [currentPeriodEvents].
131-
* 2. The events of the preceding month aren't loaded yet; [previousPeriodEvents] will be null.
132-
* 4. The [fetchedRange] will be set to the provided [FetchRange].
133-
*/
134-
fun adjustToFetchRange(fetchRange: FetchRange) {
135-
val oldFetchRange = fetchedRange ?: fetchRange
136-
val newCurrentPeriod = fetchRange.current
137-
138-
val previousEvents = when (newCurrentPeriod) {
139-
oldFetchRange.previous -> null
140-
oldFetchRange.next -> currentPeriodEvents
141-
else -> previousPeriodEvents
142-
}
72+
internal fun determinePeriodsToFetch(range: FetchRange) = range.periods.filter { it !in this }
14373

144-
val currentEvents = when (newCurrentPeriod) {
145-
oldFetchRange.previous -> previousPeriodEvents
146-
oldFetchRange.next -> nextPeriodEvents
147-
else -> currentPeriodEvents
148-
}
74+
operator fun contains(period: Period) = eventsByPeriod.contains(period)
14975

150-
val nextEvents = when (newCurrentPeriod) {
151-
oldFetchRange.previous -> currentPeriodEvents
152-
oldFetchRange.next -> null
153-
else -> nextPeriodEvents
154-
}
155-
156-
previousPeriodEvents = previousEvents
157-
currentPeriodEvents = currentEvents
158-
nextPeriodEvents = nextEvents
159-
fetchedRange = fetchRange
160-
}
161-
162-
fun update(eventsByPeriod: Map<Period, List<ResolvedWeekViewEvent<T>>>) {
163-
for ((period, events) in eventsByPeriod) {
164-
update(period, events)
165-
}
166-
}
167-
168-
private fun update(period: Period, events: List<ResolvedWeekViewEvent<T>>) {
169-
val range = checkNotNull(fetchedRange)
170-
when (period) {
171-
range.previous -> previousPeriodEvents = events
172-
range.current -> currentPeriodEvents = events
173-
range.next -> nextPeriodEvents = events
174-
}
175-
}
76+
operator fun contains(range: FetchRange) = eventsByPeriod.containsAll(range.periods)
17677

177-
operator fun set(
178-
period: Period,
179-
events: List<ResolvedWeekViewEvent<T>>
180-
) {
181-
update(period, events)
78+
fun reserve(period: Period) {
79+
eventsByPeriod[period] = listOf()
18280
}
18381

18482
override fun clear() {
185-
previousPeriodEvents = null
186-
currentPeriodEvents = null
187-
nextPeriodEvents = null
83+
eventsByPeriod.clear()
18884
}
18985
}

core/src/main/java/com/alamkanak/weekview/EventsDiffer.kt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,14 @@ internal class EventsDiffer<T>(
6161
return
6262
}
6363

64-
when (eventsCache) {
65-
is SimpleEventsCache -> eventsCache.update(events)
66-
is PagedEventsCache -> eventsCache.update(mapEventsToPeriod(events))
64+
eventsCache.update(events)
65+
66+
if (eventsCache is SimpleEventsCache) {
67+
// When using SimpleEventsCache, we completely replace all event chips that are
68+
// currently cached.
69+
eventChipsCache.clear()
6770
}
6871

6972
eventChipsCache += eventChipsFactory.createEventChips(events, viewState)
7073
}
71-
72-
private fun mapEventsToPeriod(
73-
events: List<ResolvedWeekViewEvent<T>>
74-
) = events.groupBy { Period.fromDate(it.startTime) }
7574
}

core/src/main/java/com/alamkanak/weekview/FloatExtensions.kt

Lines changed: 0 additions & 9 deletions
This file was deleted.

core/src/main/java/com/alamkanak/weekview/HeaderRenderer.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ private class DayLabelsDrawer(
140140
val right = canvas.width.toFloat()
141141
val bottom = viewState.getTotalHeaderHeight()
142142

143-
canvas.drawInRect(left, top, right, bottom) {
143+
canvas.drawInBounds(left, top, right, bottom) {
144144
viewState.dateRangeWithStartPixels.forEach { (date, startPixel) ->
145145
drawLabel(date, startPixel, this)
146146
}
@@ -319,7 +319,7 @@ internal class AllDayEventsDrawer(
319319
val right = canvas.width.toFloat()
320320
val bottom = viewState.getTotalHeaderHeight()
321321

322-
canvas.drawInRect(left, top, right, bottom) {
322+
canvas.drawInBounds(left, top, right, bottom) {
323323
for ((eventChip, textLayout) in allDayEventLayouts) {
324324
eventChipDrawer.draw(eventChip, canvas, textLayout)
325325
}

core/src/main/java/com/alamkanak/weekview/Period.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ internal data class FetchRange(
1010

1111
val periods: List<Period> = listOf(previous, current, next)
1212

13-
fun isEqual(other: FetchRange) = this == other
14-
1513
internal companion object {
1614
fun create(firstVisibleDay: Calendar): FetchRange {
1715
val current = Period.fromDate(firstVisibleDay)

core/src/main/java/com/alamkanak/weekview/ViewState.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,11 @@ private fun TypedArray.getInt(index: Int): Int? {
846846
return if (hasValue(index)) getInteger(index, 0) else null
847847
}
848848

849+
private fun Float.limit(
850+
minValue: Float,
851+
maxValue: Float
852+
): Float = min(max(this, minValue), maxValue)
853+
849854
private object Defaults {
850855
const val BACKGROUND_COLOR = Color.WHITE
851856
val PAST_BACKGROUND_COLOR = Color.rgb(227, 227, 227)

0 commit comments

Comments
 (0)