@@ -7,6 +7,7 @@ import android.text.StaticLayout
7
7
import android.util.SparseArray
8
8
import androidx.collection.ArrayMap
9
9
import java.util.Calendar
10
+ import kotlin.math.max
10
11
import kotlin.math.roundToInt
11
12
12
13
internal class HeaderRenderer (
@@ -19,8 +20,7 @@ internal class HeaderRenderer(
19
20
20
21
private val headerRowUpdater = HeaderRowUpdater (
21
22
viewState = viewState,
22
- labelLayouts = dateLabelLayouts,
23
- eventChipsCache = eventChipsCache
23
+ labelLayouts = dateLabelLayouts
24
24
)
25
25
26
26
private val dateLabelDrawer = DayLabelsDrawer (
@@ -50,69 +50,39 @@ internal class HeaderRenderer(
50
50
}
51
51
52
52
override fun render (canvas : Canvas ) {
53
- if (headerRowUpdater.isRequired()) {
54
- headerRowUpdater.update()
55
- }
56
- dateLabelDrawer.draw(canvas)
57
-
58
53
if (eventsUpdater.isRequired()) {
59
54
eventsUpdater.update()
60
55
}
61
56
eventsDrawer.draw(canvas)
57
+
58
+ headerRowUpdater.update()
59
+ dateLabelDrawer.draw(canvas)
62
60
}
63
61
}
64
62
65
63
private class HeaderRowUpdater (
66
64
private val viewState : ViewState ,
67
- private val labelLayouts : SparseArray <StaticLayout >,
68
- private val eventChipsCache : EventChipsCache
65
+ private val labelLayouts : SparseArray <StaticLayout >
69
66
) : Updater {
70
67
71
- private var previousHorizontalOrigin: Float? = null
72
- private val previousAllDayEventIds = mutableSetOf<Long >()
73
-
74
- override fun isRequired (): Boolean {
75
- val didScrollHorizontally = previousHorizontalOrigin != viewState.currentOrigin.x
76
- val currentTimeColumnWidth = viewState.timeTextWidth + viewState.timeColumnPadding * 2
77
- val didTimeColumnChange = currentTimeColumnWidth != viewState.timeColumnWidth
78
- val allDayEvents = eventChipsCache.allDayEventChipsInDateRange(viewState.dateRange)
79
- .map { it.eventId }
80
- .toSet()
81
- val didEventsChange = allDayEvents.hashCode() != previousAllDayEventIds.hashCode()
82
- return (didScrollHorizontally || didTimeColumnChange || didEventsChange).also {
83
- previousAllDayEventIds.clear()
84
- previousAllDayEventIds + = allDayEvents
68
+ override fun update () {
69
+ val missingDates = viewState.dateRange.filterNot { labelLayouts.contains(it.toEpochDays()) }
70
+ for (date in missingDates) {
71
+ val key = date.toEpochDays()
72
+ labelLayouts.put(key, calculateStaticLayoutForDate(date))
85
73
}
86
- }
87
74
88
- override fun update () {
89
- val dateLabels = updateDateLabels(viewState)
90
- updateHeaderHeight(viewState, dateLabels)
75
+ val dateLabels = viewState.dateRange.map { labelLayouts[it.toEpochDays()] }
76
+ updateHeaderHeight(dateLabels)
91
77
}
92
78
93
- private fun updateDateLabels (state : ViewState ): List <StaticLayout > {
94
- val textLayouts = state.dateRange.map { date ->
95
- date.toEpochDays() to calculateStaticLayoutForDate(date)
96
- }.toMap()
97
-
98
- labelLayouts.clear()
99
- labelLayouts + = textLayouts
100
-
101
- return textLayouts.values.toList()
102
- }
79
+ private fun <E > SparseArray<E>.contains (key : Int ): Boolean = indexOfKey(key) >= 0
103
80
104
81
private fun updateHeaderHeight (
105
- state : ViewState ,
106
82
dateLabels : List <StaticLayout >
107
83
) {
108
84
val maximumLayoutHeight = dateLabels.map { it.height.toFloat() }.max() ? : 0f
109
- state.headerTextHeight = maximumLayoutHeight
110
- refreshHeaderHeight()
111
- }
112
-
113
- private fun refreshHeaderHeight () {
114
- val visibleEvents = eventChipsCache.allDayEventChipsInDateRange(viewState.dateRange)
115
- viewState.hasEventInHeader = visibleEvents.isNotEmpty()
85
+ viewState.dateLabelHeight = maximumLayoutHeight
116
86
viewState.refreshHeaderHeight()
117
87
}
118
88
@@ -135,23 +105,23 @@ private class DayLabelsDrawer(
135
105
) : Drawer {
136
106
137
107
override fun draw (canvas : Canvas ) {
138
- val left = viewState.timeColumnWidth
139
- val top = 0f
140
- val right = canvas.width.toFloat()
141
- val bottom = viewState.getTotalHeaderHeight()
142
-
143
- canvas.drawInBounds(left, top, right, bottom ) {
108
+ canvas.drawInBounds(
109
+ left = viewState.timeColumnWidth,
110
+ top = 0f ,
111
+ right = canvas.width.toFloat(),
112
+ bottom = viewState.headerHeight
113
+ ) {
144
114
viewState.dateRangeWithStartPixels.forEach { (date, startPixel) ->
145
- drawLabel(date, startPixel, this )
115
+ drawLabel(date, startPixel)
146
116
}
147
117
}
148
118
}
149
119
150
- private fun drawLabel (day : Calendar , startPixel : Float , canvas : Canvas ) {
120
+ private fun Canvas. drawLabel (day : Calendar , startPixel : Float ) {
151
121
val key = day.toEpochDays()
152
122
val textLayout = dateLabelLayouts[key]
153
123
154
- canvas. withTranslation(
124
+ withTranslation(
155
125
x = startPixel + viewState.widthPerDay / 2 ,
156
126
y = viewState.headerRowPadding.toFloat()
157
127
) {
@@ -192,7 +162,10 @@ private class AllDayEventsUpdater(
192
162
193
163
val eventChips = eventChipsCache.allDayEventChipsByDate(date)
194
164
for (eventChip in eventChips) {
195
- calculateTextLayout(eventChip, modifiedStartPixel)
165
+ val bounds = eventChip.calculateBounds(modifiedStartPixel)
166
+ if (bounds != null ) {
167
+ eventsLabelLayouts[eventChip] = eventChip.calculateTextLayout()
168
+ }
196
169
}
197
170
}
198
171
@@ -201,27 +174,18 @@ private class AllDayEventsUpdater(
201
174
.map { it.height().roundToInt() }
202
175
.max() ? : 0
203
176
204
- viewState.updateAllDayEventHeight( maximumChipHeight)
177
+ viewState.currentAllDayEventHeight = maximumChipHeight
205
178
}
206
179
207
- private fun calculateTextLayout (
208
- eventChip : EventChip ,
209
- startPixel : Float
210
- ) {
211
- val chipRect = boundsCalculator.calculateAllDayEvent(eventChip, startPixel)
212
- eventChip.bounds = if (chipRect.isValidEventBounds) chipRect else null
213
-
214
- if (chipRect.isValidEventBounds) {
215
- val textLayout = calculateChipTextLayout(eventChip)
216
- if (textLayout != null ) {
217
- eventsLabelLayouts[eventChip] = textLayout
218
- }
219
- }
180
+ private fun EventChip.calculateBounds (startPixel : Float ): RectF ? {
181
+ val chipRect = boundsCalculator.calculateAllDayEvent(this , startPixel)
182
+ bounds = chipRect
183
+ return chipRect.takeIf { it.isValidEventBounds }
220
184
}
221
185
222
- private fun calculateChipTextLayout ( eventChip : EventChip ): StaticLayout ? {
223
- val event = eventChip. event
224
- val bounds = checkNotNull(eventChip. bounds)
186
+ private fun EventChip. calculateTextLayout ( ): StaticLayout ? {
187
+ val event = event
188
+ val bounds = checkNotNull(bounds)
225
189
226
190
val fullHorizontalPadding = viewState.eventPaddingHorizontal * 2
227
191
val fullVerticalPadding = viewState.eventPaddingVertical * 2
@@ -262,7 +226,7 @@ private class AllDayEventsUpdater(
262
226
val chipHeight = lineHeight + fullVerticalPadding
263
227
bounds.bottom = bounds.top + chipHeight
264
228
265
- return eventChip. ellipsizeText(text, availableWidth, existingTextLayout = textLayout)
229
+ return ellipsizeText(text, availableWidth, existingTextLayout = textLayout)
266
230
}
267
231
268
232
/* *
@@ -314,12 +278,12 @@ internal class AllDayEventsDrawer(
314
278
private val eventChipDrawer = EventChipDrawer (viewState)
315
279
316
280
override fun draw (canvas : Canvas ) {
317
- val left = viewState.timeColumnWidth
318
- val top = 0f
319
- val right = canvas.width.toFloat()
320
- val bottom = viewState.getTotalHeaderHeight()
321
-
322
- canvas.drawInBounds(left, top, right, bottom ) {
281
+ canvas.drawInBounds(
282
+ left = viewState.timeColumnWidth,
283
+ top = 0f ,
284
+ right = canvas.width.toFloat(),
285
+ bottom = viewState.headerHeight
286
+ ) {
323
287
for ((eventChip, textLayout) in allDayEventLayouts) {
324
288
eventChipDrawer.draw(eventChip, canvas, textLayout)
325
289
}
0 commit comments