├── jitpack.yml
├── tasticalendar
├── .gitignore
├── consumer-rules.pro
├── src
│ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ └── attrs.xml
│ │ │ ├── drawable
│ │ │ │ ├── tasticalendar_circle.xml
│ │ │ │ └── tasticalendar_ring.xml
│ │ │ └── layout
│ │ │ │ ├── tasticalendar_year.xml
│ │ │ │ └── tasticalendar_month.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── minar
│ │ │ └── tasticalendar
│ │ │ ├── model
│ │ │ ├── TcSundayHighlight.kt
│ │ │ └── TastiCalendarEvent.kt
│ │ │ ├── utilities
│ │ │ ├── UiUtils.kt
│ │ │ ├── TextUtils.kt
│ │ │ └── ColorUtils.kt
│ │ │ └── core
│ │ │ ├── TastiCalendarYear.kt
│ │ │ └── TastiCalendarMonth.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── minar
│ │ │ └── tasticalendar
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── minar
│ │ └── tasticalendar
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── .idea
├── .gitignore
├── compiler.xml
├── vcs.xml
├── kotlinc.xml
├── migrations.xml
├── misc.xml
├── gradle.xml
└── other.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── settings.gradle
├── gradle.properties
├── .github
└── workflows
│ └── main.yml
├── README.md
├── gradlew.bat
└── gradlew
/jitpack.yml:
--------------------------------------------------------------------------------
1 | jdk:
2 | - openjdk17
--------------------------------------------------------------------------------
/tasticalendar/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/tasticalendar/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/m-i-n-a-r/tasticalendar/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/tasticalendar/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 | * It is used to populate the yearly or monthly calendar, and to display an optional label
9 | * when the day is pressed.
10 | * @param date LocalDate, the complete date of the event, it can't be null.
11 | * @param displayText the text associated with the date. If null, it will be
12 | * initialized to an empty string.
13 | */
14 | data class TastiCalendarEvent(
15 | val date: LocalDate,
16 | val displayText: String? = ""
17 | )
18 |
--------------------------------------------------------------------------------
/tasticalendar/src/main/java/com/minar/tasticalendar/utilities/TextUtils.kt:
--------------------------------------------------------------------------------
1 | package com.minar.tasticalendar.utilities
2 |
3 | import com.minar.tasticalendar.model.TastiCalendarEvent
4 |
5 | // Given a list of events, cumulate their texts in a single string
6 | fun formatEventList(events: List
6 |
30 |
23 | * This uses the month class to generate a grid of 12 months.
24 | * @see TastiCalendarMonth
25 | * @param context the context of the view.
26 | * @param attrs the set of attributes specified in the layout.
27 | */
28 | @Suppress("MemberVisibilityCanBePrivate", "unused")
29 | class TastiCalendarYear(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
30 | // Custom attributes
31 | private var hideWeekDays: Boolean
32 | private var sundayHighlight = 0
33 | private var sundayFirst: Boolean
34 | private var showSnackBars: Boolean
35 | private var appearance: Int
36 |
37 | // Other useful variables
38 | private var year: Int = LocalDate.now().year
39 | private lateinit var monthList: MutableList
64 | * This is used once when the layout is first created.
65 | */
66 | private fun initYear() {
67 | // Months
68 | val january = binding.tastiCalendarYearJan
69 | val february = binding.tastiCalendarYearFeb
70 | val march = binding.tastiCalendarYearMar
71 | val april = binding.tastiCalendarYearApr
72 | val may = binding.tastiCalendarYearMay
73 | val june = binding.tastiCalendarYearJun
74 | val july = binding.tastiCalendarYearJul
75 | val august = binding.tastiCalendarYearAug
76 | val september = binding.tastiCalendarYearSep
77 | val october = binding.tastiCalendarYearOct
78 | val november = binding.tastiCalendarYearNov
79 | val december = binding.tastiCalendarYearDec
80 |
81 | // Create a list of every month
82 | monthList = mutableListOf(
83 | january,
84 | february,
85 | march,
86 | april,
87 | may,
88 | june,
89 | july,
90 | august,
91 | september,
92 | october,
93 | november,
94 | december
95 | )
96 |
97 | // This has to be done nevertheless, since it affects the numbers
98 | if (WeekFields.of(Locale.getDefault()).firstDayOfWeek.name == "SUNDAY") {
99 | for (month in monthList) {
100 | month.setSundayFirst(true)
101 | }
102 | }
103 | // Sunday highlighting
104 | if (hideWeekDays) setHideWeekDays(true)
105 | else {
106 | when (sundayHighlight) {
107 | 0 -> for (month in monthList) month.setSundayHighlight(TcSundayHighlight.NONE)
108 | 1 -> for (month in monthList) month.setSundayHighlight(TcSundayHighlight.BOLD)
109 | 2 -> for (month in monthList) month.setSundayHighlight(TcSundayHighlight.COLORED)
110 | 3 -> for (month in monthList) month.setSundayHighlight(TcSundayHighlight.BOLDCOLORED)
111 | }
112 | }
113 |
114 | // Set the appearance (0 small default, 1 medium, 2 large, 3 xlarge)
115 | when (appearance) {
116 | 0 -> return
117 | 1 -> setAppearance(1)
118 | 2 -> setAppearance(2)
119 | 3 -> setAppearance(3)
120 | }
121 | }
122 |
123 | /**
124 | * Highlights the current date with a ring.
125 | *
126 | * This is only used internally, to circle the current day, if the displayed year
127 | * is the current year.
128 | * @param drawable a drawable to replace the default ring, it can be null.
129 | * @param color a color to replace the default color (colorTertiary), it can be null.
130 | */
131 | private fun highlightCurrentDate(drawable: Drawable? = null, color: Int? = null) {
132 | val date = LocalDate.now()
133 | if (date.year != year) return
134 | val chosenColor =
135 | color ?: getThemeColor(R.attr.colorTertiary, context)
136 | val chosenDrawable =
137 | drawable ?: AppCompatResources.getDrawable(context, R.drawable.tasticalendar_ring)
138 | highlightDate(date, chosenColor, chosenDrawable, asForeground = true)
139 | }
140 |
141 | /**
142 | * Renders a given year.
143 | *
144 | * This reloads the entire layout and apply the current settings,
145 | * it's the core method of the class. If both events and dates are not null, the
146 | * latter will be ignored.
147 | * @see TastiCalendarEvent
148 | * @param year the year to render, it can't be null, but it can also be negative.
149 | * @param events a list of TastiCalendarEvents, used to highlight a set of dates also adding
150 | * labels to it. It can be null.
151 | * @param dates a simple list of dates, used to highlight a set of dates. It can be null.
152 | */
153 | fun renderYear(
154 | year: Int,
155 | events: List
205 | * This highlights a day in a variety of ways depending on the
206 | * parameters. Some parameters may not work properly in certain cases.
207 | *
208 | * @param date the date to highlight. The year is not considered, and the date is used to
209 | * find the correct month in the year and call its function.
210 | * @param color the color used to highlight the month, if no drawable is specified,
211 | * by default of the library, it's taken from the system.
212 | * @param drawable a drawable used as background, replacing the default colored circle.
213 | * It can be null.
214 | * @param makeBold Boolean, false by default, if true the day text will be in bold style. It has some problems,
215 | * since when the font is bold, it loses the monospace feature.
216 | * @param autoOpacity Boolean, false by default, if true allow different opacity levels of the background,
217 | * depending on how many times the day has been highlighted before.
218 | * @param autoTextColor Boolean, false by default, if true the text color will be computed
219 | * automatically to grant the best contrast available.
220 | * @param asForeground Boolean, false by default, if true the drawable or color will be used as
221 | * foreground, thus covering the text, totally or partially.
222 | * @param snackbarText String, a text to display if the day cell is clicked, empty by default. If empty
223 | * or null, the cell won't react to clicks.
224 | * @see TastiCalendarMonth.highlightDay
225 | */
226 | fun highlightDate(
227 | date: LocalDate?,
228 | color: Int,
229 | drawable: Drawable?,
230 | makeBold: Boolean = false,
231 | autoOpacity: Boolean = false,
232 | autoTextColor: Boolean = false,
233 | asForeground: Boolean = false,
234 | snackbarText: String = ""
235 | ) {
236 | if (date == null) return
237 | // Since we have the full date, check if the event should be considered in the current year
238 | if (date.year > year) return
239 | // Actually highlight the date
240 | monthList[date.month.value - 1].highlightDay(
241 | date.dayOfMonth,
242 | color,
243 | drawable,
244 | makeBold = makeBold,
245 | autoOpacity = autoOpacity,
246 | autoTextColor = autoTextColor,
247 | asForeground = asForeground,
248 | snackbarText = snackbarText
249 | )
250 | }
251 |
252 | /**
253 | * Add the given prefix to the message shown when tapping the month header.
254 | *
255 | * This is used to display something before the number of events for each month,
256 | * in the year, in the form "
270 | * This is used to change the default duration, set to 3000 milliseconds. Wrapper
271 | * for the month function.
272 | * @param duration Int, can't be null, defines the duration in milliseconds.
273 | * @param refresh Boolean, true by default, if false the layout won't be refreshed.
274 | */
275 | fun setSnackBarsDuration(duration: Int, refresh: Boolean = true) {
276 | for (month in monthList)
277 | month.setSnackBarsDuration(duration, refresh)
278 | }
279 |
280 | /**
281 | * Sets the property to display the snack bars on tap or not.
282 | *
283 | * If true, it is used to display advanced information when a day or a month header is pressed.
284 | * @param enabled Boolean, can't be null, if true enables the advanced info parameter.
285 | * @param refresh Boolean, true by default, if false the layout won't be refreshed.
286 | */
287 | fun setShowSnackBarsEnabled(enabled: Boolean, refresh: Boolean = true) {
288 | showSnackBars = enabled
289 | if (refresh) renderYear(year, events)
290 | }
291 |
292 | /**
293 | * Sets the base view for the snackbar.
294 | *
295 | * It can be used to avoid unwanted behaviors when a snackbar appears. For example, the snackbar
296 | * will spawn below the action button by default. Wrapper for the month function.
297 | * @param view View, not null, it should be the base view. If the view is invalid, the binding
298 | * root will be used instead.
299 | * @param refresh Boolean, true by default, if false the layout won't be refreshed.
300 | */
301 | fun setSnackBarBaseView(view: View, refresh: Boolean = true) {
302 | for (month in monthList)
303 | month.setSnackBarBaseView(view, refresh)
304 | }
305 |
306 | /**
307 | * Forces sunday to be displayed as the first day of the week.
308 | *
309 | * This is used to force sunday as the first day of the week. If this method isn't called, the
310 | * first day of the week is automatically taken from the default locale.
311 | * @param appearance Enum of type TcAppearance, can't be null, specifies the selected
312 | * highlighting type for each month in the year.
313 | * @param refresh Boolean, true by default, if false the layout won't be refreshed.
314 | * @see TcSundayHighlight
315 | */
316 | fun setSundayHighlight(appearance: TcSundayHighlight, refresh: Boolean = true) {
317 | for (month in monthList)
318 | month.setSundayHighlight(appearance, refresh)
319 | }
320 |
321 | /**
322 | * Selects an highlighting strategy for sunday, if needed.
323 | *
324 | * This is used to change the appearance of the sunday "S" in each month
325 | * @param enable Boolean, can't be null, if true sets sunday as the first day of the week
326 | * for each month in the year.
327 | * @param refresh Boolean, true by default, if false the layout won't be refreshed.
328 | */
329 | fun setSundayFirst(enable: Boolean, refresh: Boolean = true) {
330 | if (enable != sundayFirst)
331 | for (month in monthList)
332 | month.setSundayFirst(enable, refresh)
333 | }
334 |
335 | /**
336 | * Sets the weekdays row visibility.
337 | *
338 | * This is used to show or hide the weekdays row. Useful to obtain compact layouts.
339 | * @param enable Boolean, can't be null, if true hides the week days row
340 | * for each month in the year.
341 | * @param refresh Boolean, true by default, if false the layout won't be refreshed.
342 | */
343 | fun setHideWeekDays(enable: Boolean, refresh: Boolean = true) {
344 | if (enable != hideWeekDays)
345 | for (month in monthList)
346 | month.setHideWeekDays(enable, refresh)
347 | }
348 |
349 | /**
350 | * Changes the visual density of the year.
351 | *
352 | * It is used to cycle between appearances and it's basically a wrapper around
353 | * the function of TastiCalendarMonth.
354 | * @param appearance Int, can't be null, 0 means small, 1 medium, 2 large, 3 extra large.
355 | * Every other value is ignored.
356 | * @return the appearance set, useful in case of cycling
357 | */
358 | fun setAppearance(appearance: Int): Int {
359 | if (appearance > 3 || appearance < 0) {
360 | this.appearance += 1
361 | if (this.appearance == 4) this.appearance = 0
362 | } else
363 | this.appearance = appearance
364 | for (month in monthList) {
365 | month.setAppearance(this.appearance)
366 | }
367 | return this.appearance
368 | }
369 | }
--------------------------------------------------------------------------------
/tasticalendar/src/main/res/layout/tasticalendar_month.xml:
--------------------------------------------------------------------------------
1 |
35 | * It can be used alone, or in combination with TastiCalendarYear to
36 | * render a yearly calendar. Many properties are customizable.
37 | * @see TastiCalendarYear
38 | * @param context the context of the view.
39 | * @param attrs the set of attributes specified in the layout.
40 | */
41 | @Suppress("MemberVisibilityCanBePrivate", "unused")
42 | class TastiCalendarMonth(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
43 | // Custom attributes
44 | private var month = 0
45 | private var hideWeekDays: Boolean
46 | private var sundayAppearance = 0
47 | private var sundayFirst: Boolean
48 | private var showSnackBars: Boolean
49 | private var appearance = 0
50 |
51 | // Other useful variables
52 | private var dateWithChosenMonth: LocalDate
53 | private lateinit var cellsList: MutableList
88 | * This is used once when the layout is first created.
89 | */
90 | private fun initMonth() {
91 | // Week days
92 | val weekDayOne = binding.tastiCalendarWeekDayOne
93 | val weekDayTwo = binding.tastiCalendarWeekDayTwo
94 | val weekDayThree = binding.tastiCalendarWeekDayThree
95 | val weekDayFour = binding.tastiCalendarWeekDayFour
96 | val weekDayFive = binding.tastiCalendarWeekDayFive
97 | val weekDaySix = binding.tastiCalendarWeekDaySix
98 | val weekDaySeven = binding.tastiCalendarWeekDaySeven
99 | weekDaysList = mutableListOf(
100 | weekDayOne, weekDayTwo, weekDayThree, weekDayFour, weekDayFive, weekDaySix, weekDaySeven
101 | )
102 |
103 | // Month cells
104 | val cell1 = binding.tastiCalendarCell1
105 | val cell2 = binding.tastiCalendarCell2
106 | val cell3 = binding.tastiCalendarCell3
107 | val cell4 = binding.tastiCalendarCell4
108 | val cell5 = binding.tastiCalendarCell5
109 | val cell6 = binding.tastiCalendarCell6
110 | val cell7 = binding.tastiCalendarCell7
111 | val cell8 = binding.tastiCalendarCell8
112 | val cell9 = binding.tastiCalendarCell9
113 | val cell10 = binding.tastiCalendarCell10
114 | val cell11 = binding.tastiCalendarCell11
115 | val cell12 = binding.tastiCalendarCell12
116 | val cell13 = binding.tastiCalendarCell13
117 | val cell14 = binding.tastiCalendarCell14
118 | val cell15 = binding.tastiCalendarCell15
119 | val cell16 = binding.tastiCalendarCell16
120 | val cell17 = binding.tastiCalendarCell17
121 | val cell18 = binding.tastiCalendarCell18
122 | val cell19 = binding.tastiCalendarCell19
123 | val cell20 = binding.tastiCalendarCell20
124 | val cell21 = binding.tastiCalendarCell21
125 | val cell22 = binding.tastiCalendarCell22
126 | val cell23 = binding.tastiCalendarCell23
127 | val cell24 = binding.tastiCalendarCell24
128 | val cell25 = binding.tastiCalendarCell25
129 | val cell26 = binding.tastiCalendarCell26
130 | val cell27 = binding.tastiCalendarCell27
131 | val cell28 = binding.tastiCalendarCell28
132 | val cell29 = binding.tastiCalendarCell29
133 | val cell30 = binding.tastiCalendarCell30
134 | val cell31 = binding.tastiCalendarCell31
135 | val cell32 = binding.tastiCalendarCell32
136 | val cell33 = binding.tastiCalendarCell33
137 | val cell34 = binding.tastiCalendarCell34
138 | val cell35 = binding.tastiCalendarCell35
139 | val cell36 = binding.tastiCalendarCell36
140 | val cell37 = binding.tastiCalendarCell37
141 | // Create a list of every cell
142 | cellsList = mutableListOf(
143 | cell1,
144 | cell2,
145 | cell3,
146 | cell4,
147 | cell5,
148 | cell6,
149 | cell7,
150 | cell8,
151 | cell9,
152 | cell10,
153 | cell11,
154 | cell12,
155 | cell13,
156 | cell14,
157 | cell15,
158 | cell16,
159 | cell17,
160 | cell18,
161 | cell19,
162 | cell20,
163 | cell21,
164 | cell22,
165 | cell23,
166 | cell24,
167 | cell25,
168 | cell26,
169 | cell27,
170 | cell28,
171 | cell29,
172 | cell30,
173 | cell31,
174 | cell32,
175 | cell33,
176 | cell34,
177 | cell35,
178 | cell36,
179 | cell37
180 | )
181 | }
182 |
183 | /**
184 | * Renders a given range of days.
185 | *
186 | * This is used to hide unnecessary cells.
187 | * @param monthRange the range of days to render.
188 | */
189 | private fun renderDays(monthRange: Range
242 | * This highlights a day in a variety of ways depending on the
243 | * parameters. Some parameters may not work properly in certain cases.
244 | *
245 | * @param day Int and not null, represents the day to highlight. If the month
246 | * doesn't have the day, nothing will be highlighted.
247 | * @param color the color used to highlight the month, used on the text itself
248 | * if no drawable is specified.
249 | * By default of the library, it's taken from the system.
250 | * @param drawable a drawable used as background, replacing the default colored circle.
251 | * It can be null.
252 | * @param makeBold Boolean, false by default, if true the day text will be in bold style. It has some problems,
253 | * since when the font is bold, it loses the monospace feature.
254 | * @param autoOpacity Boolean, false by default, if true allow different opacity levels of the background,
255 | * depending on how many times the day has been highlighted before.
256 | * @param autoTextColor Boolean, false by default, if true the text color will be computed
257 | * automatically to grant the best contrast available.
258 | * @param asForeground Boolean, false by default, if true the drawable or color will be used as
259 | * foreground, thus covering the text, totally or partially.
260 | * @param snackbarText String, a text to display if the day cell is clicked, empty by default. If empty
261 | * or null, the cell won't react to clicks.
262 | */
263 | fun highlightDay(
264 | day: Int,
265 | color: Int,
266 | drawable: Drawable? = null,
267 | makeBold: Boolean = false,
268 | autoOpacity: Boolean = false,
269 | autoTextColor: Boolean = false,
270 | asForeground: Boolean = false,
271 | snackbarText: String = ""
272 | ) {
273 | // Update the global event count
274 | eventCount += 1
275 | var currentAlpha = 0
276 | // The textview will be hidden if the day doesn't exist in the current month
277 | for (cell in cellsList) {
278 |
279 | // Check, for each cell, if it's the wanted day and it's visible
280 | if (cell.text.trim() == day.toString() && cell.isVisible) {
281 | // Day found, now highlight it accordingly
282 | if (drawable == null) {
283 | // No drawable, color the text
284 | cell.setTextColor(color)
285 | } else {
286 | // Use the drawable as background or foreground
287 | if (asForeground) {
288 | cell.foreground = drawable
289 | cell.foregroundTintList = ColorStateList.valueOf(color)
290 | }
291 | // In case of background, compute the opacity
292 | else {
293 | if (autoOpacity) {
294 | if (cell.background != null) currentAlpha = cell.background.alpha
295 | }
296 | cell.background = drawable
297 | cell.backgroundTintList = ColorStateList.valueOf(color)
298 |
299 | if (autoOpacity) {
300 | if (currentAlpha > 185) cell.background.alpha = 255
301 | else cell.background.alpha = currentAlpha + 70
302 | } else cell.background.alpha = 255
303 |
304 | // Apply the automatic text color if requested
305 | if (autoTextColor) {
306 | cell.setTextColor(
307 | getBestContrast(
308 | color,
309 | context,
310 | cell.background.alpha,
311 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
312 | resources.configuration.isNightModeActive
313 | else null
314 | )
315 | )
316 | }
317 | }
318 | }
319 | // The font will change since monospace doesn't have a bold style
320 | if (makeBold) {
321 | // This will result in a uglier layout and unaligned texts
322 | cell.setTypeface(null, Typeface.BOLD)
323 | }
324 |
325 | // Display a snackbar on tap if the text exists
326 | if (snackbarText.isNotBlank()) {
327 | cell.setOnClickListener {
328 | // Simply uppercase the first letter of the message, if it isn't already
329 | showSnackbar(
330 | snackbarText.replaceFirstChar {
331 | if (it.isLowerCase()) it.titlecase(
332 | Locale.ROOT
333 | ) else it.toString()
334 | },
335 | snackBarsBaseView ?: binding.root,
336 | snackBarsDuration
337 | )
338 | }
339 | }
340 |
341 | // Break the for cycle, since the correct day has been found
342 | break
343 | }
344 | }
345 | }
346 |
347 | /**
348 | * Renders a given month in a given year.
349 | *
350 | * This reloads the entire layout and apply the current settings,
351 | * it's the core method of the class.
352 | *
353 | * @param monthDate the date with the given month or year, if null the initial date is used.
354 | * @param events a list of TastiCalendarEvents, used to highlight a set of dates also adding
355 | * labels to it. It can be null.
356 | * @param dates a simple list of dates, used to highlight a set of dates. It can be null.
357 | */
358 | fun renderMonth(
359 | monthDate: LocalDate = dateWithChosenMonth,
360 | events: List
539 | * It is used to obtain different visualization styles.
540 | * @param appearance Int, can't be null, 0 means small, 1 medium, 2 large, 3 extra large.
541 | * Every other value is ignored.
542 | */
543 | fun setAppearance(appearance: Int) {
544 | when (appearance) {
545 | 0 -> {
546 | for (cell in cellsList) {
547 | val textColor = cell.currentTextColor
548 | cell.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_LabelMedium)
549 | cell.setPadding(3, 3, 3, 3)
550 | cell.typeface = Typeface.MONOSPACE
551 | cell.setTextColor(textColor)
552 | }
553 | for (day in weekDaysList) {
554 | val textColor = day.currentTextColor
555 | day.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_LabelMedium)
556 | day.setTextColor(textColor)
557 | }
558 | monthTitle.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyMedium)
559 | }
560 | 1 -> {
561 | for (cell in cellsList) {
562 | val textColor = cell.currentTextColor
563 | cell.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyMedium)
564 | cell.setPadding(8, 8, 8, 8)
565 | cell.typeface = Typeface.MONOSPACE
566 | cell.setTextColor(textColor)
567 | }
568 | for (day in weekDaysList) {
569 | val textColor = day.currentTextColor
570 | day.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyMedium)
571 | day.setTextColor(textColor)
572 | }
573 | monthTitle.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyLarge)
574 | }
575 | 2 -> {
576 | for (cell in cellsList) {
577 | val textColor = cell.currentTextColor
578 | cell.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyLarge)
579 | cell.setPadding(12, 12, 12, 12)
580 | cell.typeface = Typeface.MONOSPACE
581 | cell.setTextColor(textColor)
582 | }
583 | for (day in weekDaysList) {
584 | val textColor = day.currentTextColor
585 | day.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyLarge)
586 | day.setTextColor(textColor)
587 | }
588 | monthTitle.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_HeadlineSmall)
589 | }
590 | 3 -> {
591 | for (cell in cellsList) {
592 | val textColor = cell.currentTextColor
593 | cell.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_HeadlineMedium)
594 | cell.setPadding(16, 16, 16, 16)
595 | cell.typeface = Typeface.MONOSPACE
596 | cell.setTextColor(textColor)
597 | }
598 | for (day in weekDaysList) {
599 | val textColor = day.currentTextColor
600 | day.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_HeadlineMedium)
601 | day.setTextColor(textColor)
602 | }
603 | monthTitle.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_HeadlineLarge)
604 | }
605 | else -> return
606 | }
607 | colorize()
608 | }
609 |
610 | /**
611 | * Forces sunday to be displayed as the first day of the week.
612 | *
613 | * This is used to force sunday as the first day of the week. If this method isn't called, the
614 | * first day of the week is automatically taken from the default locale.
615 | * @param appearance Enum of type TcAppearance, can't be null, specifies the selected
616 | * highlighting type
617 | * @param refresh Boolean, true by default, if false the layout won't be refreshed.
618 | * @see TcSundayHighlight
619 | */
620 | fun setSundayHighlight(appearance: TcSundayHighlight, refresh: Boolean = true) {
621 | sundayAppearance = appearance.ordinal
622 | if (refresh) renderMonth()
623 | }
624 |
625 | /**
626 | * Forces sunday to be displayed as the first day of the week.
627 | *
628 | * This is used to force sunday as the first day of the week. If this method isn't called, the
629 | * first day of the week is automatically taken from the default locale.
630 | * @param enable Boolean, can't be null, if true sets sunday as the first day of the week
631 | * for the current month.
632 | * @param refresh Boolean, true by default, if false the layout won't be refreshed.
633 | */
634 | fun setSundayFirst(enable: Boolean, refresh: Boolean = true) {
635 | if (enable != sundayFirst) {
636 | sundayFirst = enable
637 | if (refresh) renderMonth()
638 | }
639 | }
640 |
641 | /**
642 | * Sets the weekdays row visibility.
643 | *
644 | * This is used to show or hide the weekdays row. Useful to obtain compact layouts.
645 | * @param enable Boolean, can't be null, if true hides the week days row
646 | * for the current month.
647 | * @param refresh Boolean, true by default, if false the layout won't be refreshed.
648 | */
649 | fun setHideWeekDays(enable: Boolean, refresh: Boolean = true) {
650 | if (enable != hideWeekDays) hideWeekDays = enable
651 | if (refresh) renderMonth()
652 | }
653 |
654 | /**
655 | * Add the given prefix to the message shown when tapping the month header.
656 | *
657 | * This is used to display something before the number of events in the month,
658 | * in the form "
672 | * It can be used to avoid unwanted behaviors when a snackbar appears. For example, the snackbar
673 | * will spawn below the action button by default
674 | * @param view View, not null, it should be the base view. If the view is invalid, the binding
675 | * root will be used instead
676 | * @param refresh Boolean, true by default, if false the layout won't be refreshed.
677 | */
678 | fun setSnackBarBaseView(view: View, refresh: Boolean = true) {
679 | snackBarsBaseView = view
680 | if (refresh) renderMonth()
681 | }
682 |
683 | /**
684 | * Sets the duration for the snackbar.
685 | *
686 | * This is used to change the default duration, set to 3000 milliseconds.
687 | * @param duration Int, can't be null, defines the duration in milliseconds.
688 | * @param refresh Boolean, true by default, if false the layout won't be refreshed.
689 | */
690 | fun setSnackBarsDuration(duration: Int, refresh: Boolean = true) {
691 | snackBarsDuration = duration
692 | if (refresh) renderMonth()
693 | }
694 |
695 | /**
696 | * Renders the same month for a different year.
697 | *
698 | * Basically a wrapper around renderMonth, used to quickly switch only the year.
699 | * @param year Int, can't be null, represents the year to display this month into.
700 | */
701 | fun setYear(year: Int) = renderMonth(dateWithChosenMonth.withYear(year))
702 |
703 | /**
704 | * Resets the highlighting for the current month, thus removing every event from it.
705 | *
706 | * It can be used to display a new set of events, or a different month.
707 | */
708 | fun resetHighlighting() {
709 | for (cell in cellsList) {
710 | if (cell.background != null) {
711 | cell.background.alpha = 0
712 | cell.background = null
713 | cell.setOnClickListener(null)
714 | }
715 | cell.setTextColor(
716 | getThemeColor(
717 | R.attr.colorOnBackground,
718 | context
719 | )
720 | )
721 | cell.foreground = null
722 | }
723 | }
724 |
725 | /**
726 | * Mainly used when the appearance changes, it colorizes some elements in the layout.
727 | *
728 | * This is used to colorize the current month, the other months, and to slightly change
729 | * the weekdays text opacity (.85).
730 | */
731 | private fun colorize() {
732 | if (dateWithChosenMonth.month == LocalDate.now().month && dateWithChosenMonth.year == LocalDate.now().year) {
733 | monthTitle.setTextColor(
734 | getThemeColor(
735 | R.attr.colorTertiary,
736 | context
737 | )
738 | )
739 | } else monthTitle.setTextColor(
740 | getThemeColor(
741 | R.attr.colorSecondary,
742 | context
743 | )
744 | )
745 | for (weekDay in weekDaysList) weekDay.alpha = .85f
746 |
747 | // Set the highlighting style for sunday
748 | when (sundayAppearance) {
749 | 0 -> {
750 | weekDaysList[sundayIndex].setTypeface(null, Typeface.NORMAL)
751 | weekDaysList[sundayIndex].setTextColor(
752 | getThemeColor(
753 | R.attr.colorOnSurfaceVariant,
754 | context
755 | )
756 | )
757 | }
758 | 1 -> {
759 | weekDaysList[sundayIndex].setTypeface(null, Typeface.BOLD)
760 | weekDaysList[sundayIndex].setTextColor(
761 | getThemeColor(
762 | R.attr.colorOnSurfaceVariant,
763 | context
764 | )
765 | )
766 | }
767 | 2 -> {
768 | weekDaysList[sundayIndex].setTypeface(null, Typeface.NORMAL)
769 | weekDaysList[sundayIndex].setTextColor(
770 | getThemeColor(
771 | R.attr.colorTertiary,
772 | context
773 | )
774 | )
775 | }
776 | 3 -> {
777 | weekDaysList[sundayIndex].setTypeface(null, Typeface.BOLD)
778 | weekDaysList[sundayIndex].setTextColor(
779 | getThemeColor(
780 | R.attr.colorTertiary,
781 | context
782 | )
783 | )
784 | }
785 | }
786 | }
787 | }
--------------------------------------------------------------------------------
7 |
8 |
9 |
10 |
11 |

31 | Monet support examples
32 | 
33 | 3 of the four available scale factors
34 |
6 |
261 |