@@ -99,7 +99,6 @@ class MyWidgetMonthlyProvider : AppWidgetProvider() {
9999 val dimCompletedTasks = context.config.dimCompletedTasks
100100 val smallerFontSize = context.getWidgetFontSize() - 3f
101101 val res = context.resources
102- val len = days.size
103102 val packageName = context.packageName
104103 views.apply {
105104 setTextColor(R .id.week_num, textColor)
@@ -117,51 +116,121 @@ class MyWidgetMonthlyProvider : AppWidgetProvider() {
117116 }
118117 }
119118
120- for (i in 0 until len) {
121- val day = days[i]
119+ val eventDayIndices = mutableMapOf<Pair <Long , Long >, MutableList <Int >>()
120+ val eventByKey = mutableMapOf<Pair <Long , Long >, Event > ()
121+ for (i in days.indices) {
122+ for (event in days[i].dayEvents) {
123+ val key = Pair (event.id ? : 0L , event.startTS)
124+ eventDayIndices.getOrPut(key) { mutableListOf () }.add(i)
125+ if (key !in eventByKey) eventByKey[key] = event
126+ }
127+ }
122128
129+ val sortedKeys = eventDayIndices.keys.sortedWith(
130+ compareBy(
131+ { - (eventDayIndices[it]!! .size) },
132+ { (eventByKey[it]!! .flags and FLAG_ALL_DAY ) == 0 },
133+ { eventByKey[it]!! .startTS },
134+ { eventByKey[it]!! .endTS },
135+ { eventDayIndices[it]!! .firstOrNull() ? : 0 },
136+ { eventByKey[it]!! .title }
137+ )
138+ )
139+
140+ val daySlotLists = buildDaySlotLists(days.size, sortedKeys, eventDayIndices, eventByKey)
141+
142+ val titleShownForKey = mutableSetOf<Pair <Long , Long >>()
143+ for (i in days.indices) {
144+ val day = days[i]
123145 val dayTextColor = if (context.config.highlightWeekends && day.isWeekend) {
124146 context.config.highlightWeekendsColor
125147 } else {
126148 textColor
127149 }
128-
129150 val weakTextColor = dayTextColor.adjustAlpha(MEDIUM_ALPHA )
130151 val currTextColor = if (day.isThisMonth) dayTextColor else weakTextColor
131152 val id = res.getIdentifier(" day_$i " , " id" , packageName)
132153 views.removeAllViews(id)
133154 addDayNumber(context, views, day, currTextColor, id)
134155 setupDayOpenIntent(context, views, id, day.code)
135156
136- day.dayEvents = day.dayEvents.asSequence().sortedWith(compareBy({ it.flags and FLAG_ALL_DAY == 0 }, { it.startTS }, { it.title }))
137- .toMutableList() as ArrayList <Event >
138-
139- day.dayEvents.forEach {
140- val backgroundColor = it.color
141- var eventTextColor = backgroundColor.getContrastColor()
142- val shouldDim = (it.isTask() && it.isTaskCompleted() && dimCompletedTasks)
143- || (dimPastEvents && it.isPastEvent && ! it.isTask())
144- if (shouldDim) {
145- eventTextColor = eventTextColor.adjustAlpha(MEDIUM_ALPHA )
157+ for (slotEvent in daySlotLists[i]) {
158+ if (slotEvent == null ) {
159+ views.addView(id, createSpacerView(packageName))
160+ } else {
161+ val key = Pair (slotEvent.id ? : 0L , slotEvent.startTS)
162+ val showTitle = titleShownForKey.add(key) || i % 7 == 0
163+ var eventTextColor = slotEvent.color.getContrastColor()
164+ val shouldDim = (slotEvent.isTask() && slotEvent.isTaskCompleted() && dimCompletedTasks)
165+ || (dimPastEvents && slotEvent.isPastEvent && ! slotEvent.isTask())
166+ if (shouldDim) {
167+ eventTextColor = eventTextColor.adjustAlpha(MEDIUM_ALPHA )
168+ }
169+ val dayIndices = eventDayIndices[key]!!
170+ val prevInRun = i > 0 && i % 7 != 0 && dayIndices.contains(i - 1 )
171+ val nextInRun = i < days.size - 1 && (i + 1 ) % 7 != 0 && dayIndices.contains(i + 1 )
172+ val eventLayout = when {
173+ prevInRun && nextInRun -> R .layout.day_monthly_event_view_widget_event_middle
174+ prevInRun -> R .layout.day_monthly_event_view_widget_event_end
175+ nextInRun -> R .layout.day_monthly_event_view_widget_event_start
176+ else -> R .layout.day_monthly_event_view_widget
177+ }
178+ val newRemoteView = RemoteViews (packageName, eventLayout).apply {
179+ setTextColor(R .id.day_monthly_event_id, eventTextColor)
180+ setTextSize(R .id.day_monthly_event_id, smallerFontSize - 3f )
181+ setInt(R .id.day_monthly_event_background, " setColorFilter" , slotEvent.color)
182+ if (showTitle) {
183+ setText(R .id.day_monthly_event_id, slotEvent.title.replace(" " , " \u00A0 " ))
184+ setVisibleIf(R .id.day_monthly_task_image, slotEvent.isTask())
185+ applyColorFilter(R .id.day_monthly_task_image, eventTextColor)
186+ if (slotEvent.shouldStrikeThrough()) {
187+ setInt(R .id.day_monthly_event_id, " setPaintFlags" , Paint .ANTI_ALIAS_FLAG or Paint .STRIKE_THRU_TEXT_FLAG )
188+ } else {
189+ setInt(R .id.day_monthly_event_id, " setPaintFlags" , Paint .ANTI_ALIAS_FLAG )
190+ }
191+ } else {
192+ setText(R .id.day_monthly_event_id, " " )
193+ setVisibleIf(R .id.day_monthly_task_image, false )
194+ setInt(R .id.day_monthly_event_id, " setPaintFlags" , Paint .ANTI_ALIAS_FLAG )
195+ }
196+ }
197+ views.addView(id, newRemoteView)
146198 }
199+ }
200+ }
201+ }
147202
148- val newRemoteView = RemoteViews (packageName, R .layout.day_monthly_event_view_widget).apply {
149- setText(R .id.day_monthly_event_id, it.title.replace(" " , " \u00A0 " ))
150- setTextColor(R .id.day_monthly_event_id, eventTextColor)
151- setTextSize(R .id.day_monthly_event_id, smallerFontSize - 3f )
152- setVisibleIf(R .id.day_monthly_task_image, it.isTask())
153- applyColorFilter(R .id.day_monthly_task_image, eventTextColor)
154- setInt(R .id.day_monthly_event_background, " setColorFilter" , it.color)
155-
156- if (it.shouldStrikeThrough()) {
157- setInt(R .id.day_monthly_event_id, " setPaintFlags" , Paint .ANTI_ALIAS_FLAG or Paint .STRIKE_THRU_TEXT_FLAG )
158- } else {
159- setInt(R .id.day_monthly_event_id, " setPaintFlags" , Paint .ANTI_ALIAS_FLAG )
160- }
203+ private fun buildDaySlotLists (
204+ daysSize : Int ,
205+ sortedKeys : List <Pair <Long , Long >>,
206+ eventDayIndices : Map <Pair <Long , Long >, List <Int >>,
207+ eventByKey : Map <Pair <Long , Long >, Event >
208+ ): Array <MutableList <Event ?>> {
209+ val daySlotIndex = IntArray (daysSize) { 0 }
210+ val daySlotLists = Array (daysSize) { mutableListOf<Event ?>() }
211+ for (key in sortedKeys) {
212+ val dayIndices = eventDayIndices[key]!!
213+ val event = eventByKey[key]!!
214+ val slot = dayIndices.maxOf { daySlotIndex[it] }
215+ for (dayIdx in dayIndices) {
216+ while (daySlotIndex[dayIdx] < slot) {
217+ daySlotLists[dayIdx].add(null ) // invisible spacer
218+ daySlotIndex[dayIdx]++
161219 }
162- views.addView(id, newRemoteView)
220+ daySlotLists[dayIdx].add(event)
221+ daySlotIndex[dayIdx]++
163222 }
164223 }
224+ return daySlotLists
225+ }
226+
227+ private fun createSpacerView (packageName : String ): RemoteViews {
228+ return RemoteViews (packageName, R .layout.day_monthly_event_view_widget).apply {
229+ setText(R .id.day_monthly_event_id, " " )
230+ setViewVisibility(R .id.day_monthly_event_background, View .INVISIBLE )
231+ setViewVisibility(R .id.day_monthly_task_image, View .GONE )
232+ setInt(R .id.day_monthly_event_id, " setPaintFlags" , Paint .ANTI_ALIAS_FLAG )
233+ }
165234 }
166235
167236 private fun addDayNumber (context : Context , views : RemoteViews , day : DayMonthly , textColor : Int , id : Int ) {
0 commit comments