Skip to content

Commit 5e7cab0

Browse files
authored
feat: added styling to CourseDateBlock (#194)
feat: added styling to CourseDateBlock - Added relative icons for each date type - Added locked content description - Improve code structuring - Improve the time format to better understand with date fix: LEARNER-9771
1 parent 1948e3c commit 5e7cab0

File tree

11 files changed

+229
-92
lines changed

11 files changed

+229
-92
lines changed

core/src/main/java/org/openedx/core/data/model/CourseDates.kt

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import com.google.gson.annotations.SerializedName
44
import org.openedx.core.domain.model.DatesSection
55
import org.openedx.core.utils.TimeUtils
66
import org.openedx.core.utils.addDays
7+
import org.openedx.core.utils.clearTime
78
import org.openedx.core.utils.isToday
9+
import java.util.Date
810
import org.openedx.core.domain.model.CourseDateBlock as DomainCourseDateBlock
911

1012
data class CourseDates(
@@ -24,7 +26,7 @@ data class CourseDates(
2426
val verifiedUpgradeLink: String? = "",
2527
) {
2628
fun getStructuredCourseDates(): LinkedHashMap<DatesSection, List<DomainCourseDateBlock>> {
27-
val currentDate = TimeUtils.getCurrentDate()
29+
val currentDate = Date()
2830
val courseDatesResponse: LinkedHashMap<DatesSection, List<DomainCourseDateBlock>> =
2931
LinkedHashMap()
3032
val datesList = mapToDomain()
@@ -36,43 +38,44 @@ data class CourseDates(
3638
datesList.filter { currentDate.after(it.date) }.also { datesList.removeAll(it) }
3739

3840
courseDatesResponse[DatesSection.TODAY] =
39-
datesList.filter { it.date != null && it.date.isToday() }
40-
.also { datesList.removeAll(it) }
41+
datesList.filter { it.date.isToday() }.also { datesList.removeAll(it) }
42+
43+
//Update the date for upcoming comparison without time
44+
currentDate.clearTime()
4145

4246
// for current week except today
4347
courseDatesResponse[DatesSection.THIS_WEEK] = datesList.filter {
44-
it.date != null && it.date.after(currentDate) &&
45-
it.date.before(currentDate.addDays(8))
48+
it.date.after(currentDate) && it.date.before(currentDate.addDays(8))
4649
}.also { datesList.removeAll(it) }
4750

4851
// for coming week
4952
courseDatesResponse[DatesSection.NEXT_WEEK] = datesList.filter {
50-
it.date != null &&
51-
it.date.after(currentDate.addDays(7)) &&
52-
it.date.before(currentDate.addDays(15))
53+
it.date.after(currentDate.addDays(7)) && it.date.before(currentDate.addDays(15))
5354
}.also { datesList.removeAll(it) }
5455

5556
// for upcoming
5657
courseDatesResponse[DatesSection.UPCOMING] = datesList.filter {
57-
it.date != null && it.date.after(currentDate.addDays(14))
58+
it.date.after(currentDate.addDays(14))
5859
}.also { datesList.removeAll(it) }
5960

6061
return courseDatesResponse
6162
}
6263

6364
private fun mapToDomain(): MutableList<DomainCourseDateBlock> {
64-
return courseDateBlocks.map { item ->
65-
DomainCourseDateBlock(
66-
title = item.title,
67-
description = item.description,
68-
link = item.link,
69-
blockId = item.blockId,
70-
date = TimeUtils.iso8601ToDate(item.date),
71-
complete = item.complete,
72-
learnerHasAccess = item.learnerHasAccess,
73-
dateType = item.dateType,
74-
assignmentType = item.assignmentType
75-
)
76-
}.sortedBy { it.date }.filter { it.date != null }.toMutableList()
65+
return courseDateBlocks.mapNotNull { item ->
66+
TimeUtils.iso8601ToDate(item.date)?.let { date ->
67+
DomainCourseDateBlock(
68+
title = item.title,
69+
description = item.description,
70+
link = item.link,
71+
blockId = item.blockId,
72+
date = date,
73+
complete = item.complete,
74+
learnerHasAccess = item.learnerHasAccess,
75+
dateType = item.dateType,
76+
assignmentType = item.assignmentType
77+
)
78+
}
79+
}.sortedBy { it.date }.toMutableList()
7780
}
7881
}
Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
11
package org.openedx.core.data.model
22

33
import com.google.gson.annotations.SerializedName
4+
import org.openedx.core.R
45

5-
enum class DateType {
6+
enum class DateType(val drawableResId: Int? = null) {
67
@SerializedName("todays-date")
7-
TODAY_DATE,
8+
TODAY_DATE(R.drawable.core_ic_calendar),
89

910
@SerializedName("course-start-date")
10-
COURSE_START_DATE,
11+
COURSE_START_DATE(R.drawable.core_ic_start_end),
1112

1213
@SerializedName("course-end-date")
13-
COURSE_END_DATE,
14+
COURSE_END_DATE(R.drawable.core_ic_start_end),
1415

1516
@SerializedName("course-expired-date")
16-
COURSE_EXPIRED_DATE,
17+
COURSE_EXPIRED_DATE(R.drawable.core_ic_course_expire),
1718

1819
@SerializedName("assignment-due-date")
19-
ASSIGNMENT_DUE_DATE,
20+
ASSIGNMENT_DUE_DATE(R.drawable.core_ic_assignment),
2021

2122
@SerializedName("certificate-available-date")
22-
CERTIFICATE_AVAILABLE_DATE,
23+
CERTIFICATE_AVAILABLE_DATE(R.drawable.core_ic_certificate),
2324

2425
@SerializedName("verified-upgrade-deadline")
25-
VERIFIED_UPGRADE_DEADLINE,
26+
VERIFIED_UPGRADE_DEADLINE(R.drawable.core_ic_calendar),
2627

2728
@SerializedName("verification-deadline-date")
28-
VERIFICATION_DEADLINE_DATE,
29+
VERIFICATION_DEADLINE_DATE(R.drawable.core_ic_calendar),
2930

3031
NONE,
3132
}
Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.openedx.core.domain.model
22

33
import org.openedx.core.data.model.DateType
4+
import org.openedx.core.utils.isTimeLessThan24Hours
5+
import org.openedx.core.utils.isToday
46
import java.util.Date
57

68
data class CourseDateBlock(
@@ -10,7 +12,7 @@ data class CourseDateBlock(
1012
val blockId: String = "",
1113
val learnerHasAccess: Boolean = false,
1214
val complete: Boolean = false,
13-
val date: Date?,
15+
val date: Date,
1416
val dateType: DateType = DateType.NONE,
1517
val assignmentType: String? = "",
1618
) {
@@ -19,7 +21,12 @@ data class CourseDateBlock(
1921
DateType.COURSE_START_DATE,
2022
DateType.COURSE_END_DATE,
2123
DateType.CERTIFICATE_AVAILABLE_DATE,
22-
DateType.VERIFICATION_DEADLINE_DATE
23-
) && date?.before(Date()) == true)
24+
DateType.VERIFIED_UPGRADE_DEADLINE,
25+
DateType.VERIFICATION_DEADLINE_DATE,
26+
) && date.before(Date()))
27+
}
28+
29+
fun isTimeDifferenceLessThan24Hours(): Boolean {
30+
return (date.isToday() && date.before(Date())) || date.isTimeLessThan24Hours()
2431
}
2532
}

core/src/main/java/org/openedx/core/utils/TimeUtils.kt

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,6 @@ object TimeUtils {
2222

2323
private const val SEVEN_DAYS_IN_MILLIS = 604800000L
2424

25-
/**
26-
* This method used to get the current date
27-
* @return The current date with time set to midnight.
28-
*/
29-
fun getCurrentDate(): Date {
30-
val calendar = Calendar.getInstance().also { it.clearTimeComponents() }
31-
return calendar.time
32-
}
33-
3425
fun getCurrentTime(): Long {
3526
return Calendar.getInstance().timeInMillis
3627
}
@@ -53,15 +44,6 @@ object TimeUtils {
5344
}
5445
}
5546

56-
/**
57-
* This method used to convert the date to ISO 8601 compliant format date string
58-
* @param date [Date]needs to be converted
59-
* @return The current date and time in a ISO 8601 compliant format.
60-
*/
61-
fun dateToIso8601(date: Date?): String {
62-
return ISO8601Utils.format(date, true)
63-
}
64-
6547
fun iso8601ToDateWithTime(context: Context, text: String): String {
6648
return try {
6749
val courseDateFormat = SimpleDateFormat(FORMAT_ISO_8601, Locale.getDefault())
@@ -75,31 +57,20 @@ object TimeUtils {
7557
}
7658
}
7759

78-
fun dateToCourseDate(resourceManager: ResourceManager, date: Date?): String {
60+
private fun dateToCourseDate(resourceManager: ResourceManager, date: Date?): String {
7961
return formatDate(
8062
format = resourceManager.getString(R.string.core_date_format_MMMM_dd), date = date
8163
)
8264
}
8365

84-
fun formatDate(format: String, date: String): String {
85-
return formatDate(format, iso8601ToDate(date))
86-
}
87-
88-
fun formatDate(format: String, date: Date?): String {
66+
private fun formatDate(format: String, date: Date?): String {
8967
if (date == null) {
9068
return ""
9169
}
9270
val sdf = SimpleDateFormat(format, Locale.getDefault())
9371
return sdf.format(date)
9472
}
9573

96-
fun stringToDate(dateFormat: String, date: String): Date? {
97-
if (dateFormat.isEmpty() || date.isEmpty()) {
98-
return null
99-
}
100-
return SimpleDateFormat(dateFormat, Locale.getDefault()).parse(date)
101-
}
102-
10374
/**
10475
* Checks if the given date is past today.
10576
*
@@ -200,6 +171,21 @@ object TimeUtils {
200171
return formattedDate
201172
}
202173

174+
/**
175+
* Method to get the formatted time string in terms of relative time with minimum resolution of minutes.
176+
* For example, if the time difference is 1 minute, it will return "1m ago".
177+
*
178+
* @param date Date object to be formatted.
179+
*/
180+
fun getFormattedTime(date: Date): String {
181+
return DateUtils.getRelativeTimeSpanString(
182+
date.time,
183+
getCurrentTime(),
184+
DateUtils.MINUTE_IN_MILLIS,
185+
DateUtils.FORMAT_ABBREV_TIME
186+
).toString()
187+
}
188+
203189
/**
204190
* Returns a formatted date string for the given date.
205191
*/
@@ -266,27 +252,56 @@ object TimeUtils {
266252
}
267253
}
268254

269-
// Extension function to clear time components
255+
/**
256+
* Extension function to clear time components of a calendar.
257+
* for example, if the time is 10:30:45, it will set the time to 00:00:00
258+
*/
270259
fun Calendar.clearTimeComponents() {
271260
this.set(Calendar.HOUR_OF_DAY, 0)
272261
this.set(Calendar.MINUTE, 0)
273262
this.set(Calendar.SECOND, 0)
274263
this.set(Calendar.MILLISECOND, 0)
275264
}
276265

277-
// Extension function to check if a date is today
266+
/**
267+
* Extension function to check if the given date is today.
268+
*/
278269
fun Date.isToday(): Boolean {
279270
val calendar = Calendar.getInstance()
280271
calendar.time = this
281272
calendar.clearTimeComponents()
282-
return calendar.time == TimeUtils.getCurrentDate()
273+
return calendar.time == Date().clearTime()
283274
}
284275

285-
// Extension function to add number of days to a date
276+
/**
277+
* Extension function to add days to a date.
278+
* for example, if the date is 2020-01-01 10:30:45, and days is 2, it will return 2020-01-03 00:00:00
279+
*/
286280
fun Date.addDays(days: Int): Date {
287281
val calendar = Calendar.getInstance()
288282
calendar.time = this
289283
calendar.clearTimeComponents()
290284
calendar.add(Calendar.DATE, days)
291285
return calendar.time
292286
}
287+
288+
/**
289+
* Extension function to clear time components of a date.
290+
* for example, if the date is 2020-01-01 10:30:45, it will return 2020-01-01 00:00:00
291+
*/
292+
fun Date.clearTime(): Date {
293+
val calendar = Calendar.getInstance()
294+
calendar.time = this
295+
calendar.clearTimeComponents()
296+
return calendar.time
297+
}
298+
299+
/**
300+
* Extension function to check if the time difference between the given date and the current date is less than 24 hours.
301+
*/
302+
fun Date.isTimeLessThan24Hours(): Boolean {
303+
val calendar = Calendar.getInstance()
304+
calendar.time = this
305+
val timeInMillis = (calendar.timeInMillis - TimeUtils.getCurrentTime()).unaryPlus()
306+
return timeInMillis < TimeUnit.DAYS.toMillis(1)
307+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="16dp"
3+
android:height="16dp"
4+
android:viewportWidth="16"
5+
android:viewportHeight="16">
6+
<group>
7+
<clip-path android:pathData="M0,0h16v16h-16z" />
8+
<path
9+
android:fillColor="#19212F"
10+
android:pathData="M3.333,15.8C2.967,15.8 2.653,15.67 2.392,15.409C2.131,15.148 2,14.834 2,14.467V5.134C2,4.767 2.131,4.453 2.392,4.192C2.653,3.931 2.967,3.801 3.333,3.801H9.283L7.95,5.134H3.333V14.467H12.667V9.834L14,8.501V14.467C14,14.834 13.869,15.148 13.608,15.409C13.347,15.67 13.033,15.8 12.667,15.8H3.333ZM10.783,4.184L11.733,5.117L7.333,9.517V10.467H8.267L12.683,6.051L13.633,6.984L8.833,11.8H6V8.967L10.783,4.184ZM13.633,6.984L10.783,4.184L12.45,2.517C12.717,2.251 13.036,2.117 13.408,2.117C13.781,2.117 14.094,2.251 14.35,2.517L15.283,3.467C15.539,3.723 15.667,4.034 15.667,4.401C15.667,4.767 15.539,5.078 15.283,5.334L13.633,6.984Z" />
11+
</group>
12+
</vector>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="16dp"
3+
android:height="16dp"
4+
android:viewportWidth="16"
5+
android:viewportHeight="16">
6+
<path
7+
android:fillColor="#19212F"
8+
android:pathData="M11.333,1.334C10.967,1.334 10.667,1.634 10.667,2.001V2.667H5.333V2.001C5.333,1.634 5.033,1.334 4.667,1.334C4.3,1.334 4,1.634 4,2.001V2.667H3.333C2.593,2.667 2.007,3.267 2.007,4.001L2,13.334C2,14.067 2.593,14.667 3.333,14.667H12.667C13.4,14.667 14,14.067 14,13.334V4.001C14,3.267 13.4,2.667 12.667,2.667H12V2.001C12,1.634 11.7,1.334 11.333,1.334ZM12.667,13.334H3.333V6.667H12.667V13.334ZM7.333,8.667C7.333,8.301 7.633,8.001 8,8.001C8.367,8.001 8.667,8.301 8.667,8.667C8.667,9.034 8.367,9.334 8,9.334C7.633,9.334 7.333,9.034 7.333,8.667ZM4.667,8.667C4.667,8.301 4.967,8.001 5.333,8.001C5.7,8.001 6,8.301 6,8.667C6,9.034 5.7,9.334 5.333,9.334C4.967,9.334 4.667,9.034 4.667,8.667ZM10,8.667C10,8.301 10.3,8.001 10.667,8.001C11.033,8.001 11.333,8.301 11.333,8.667C11.333,9.034 11.033,9.334 10.667,9.334C10.3,9.334 10,9.034 10,8.667ZM7.333,11.334C7.333,10.967 7.633,10.667 8,10.667C8.367,10.667 8.667,10.967 8.667,11.334C8.667,11.701 8.367,12.001 8,12.001C7.633,12.001 7.333,11.701 7.333,11.334ZM4.667,11.334C4.667,10.967 4.967,10.667 5.333,10.667C5.7,10.667 6,10.967 6,11.334C6,11.701 5.7,12.001 5.333,12.001C4.967,12.001 4.667,11.701 4.667,11.334ZM10,11.334C10,10.967 10.3,10.667 10.667,10.667C11.033,10.667 11.333,10.967 11.333,11.334C11.333,11.701 11.033,12.001 10.667,12.001C10.3,12.001 10,11.701 10,11.334Z" />
9+
</vector>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="16dp"
3+
android:height="16dp"
4+
android:viewportWidth="16"
5+
android:viewportHeight="16">
6+
<path
7+
android:fillColor="#19212F"
8+
android:pathData="M13.333,4.667H10V2.667C10,1.934 9.4,1.334 8.666,1.334H7.333C6.6,1.334 6,1.934 6,2.667V4.667H2.666C1.933,4.667 1.333,5.267 1.333,6.001V13.334C1.333,14.067 1.933,14.667 2.666,14.667H13.333C14.066,14.667 14.666,14.067 14.666,13.334V6.001C14.666,5.267 14.066,4.667 13.333,4.667ZM6,8.001C6.553,8.001 7,8.447 7,9.001C7,9.554 6.553,10.001 6,10.001C5.446,10.001 5,9.554 5,9.001C5,8.447 5.446,8.001 6,8.001ZM8,12.001H4V11.714C4,11.314 4.24,10.947 4.613,10.787C5.04,10.601 5.506,10.501 6,10.501C6.493,10.501 6.96,10.601 7.386,10.787C7.753,10.947 8,11.307 8,11.714V12.001ZM8.666,6.001H7.333V2.667H8.666V6.001ZM11.5,11.001H9.833C9.56,11.001 9.333,10.774 9.333,10.501C9.333,10.227 9.56,10.001 9.833,10.001H11.5C11.773,10.001 12,10.227 12,10.501C12,10.774 11.773,11.001 11.5,11.001ZM11.5,9.001H9.833C9.56,9.001 9.333,8.774 9.333,8.501C9.333,8.227 9.56,8.001 9.833,8.001H11.5C11.773,8.001 12,8.227 12,8.501C12,8.774 11.773,9.001 11.5,9.001Z" />
9+
</vector>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="16dp"
3+
android:height="16dp"
4+
android:viewportWidth="16"
5+
android:viewportHeight="16">
6+
<path
7+
android:fillColor="#19212F"
8+
android:pathData="M11,7.333C11.467,7.333 11.914,7.399 12.334,7.526V6.666C12.334,5.933 11.734,5.333 11,5.333H10.334V3.999C10.334,2.159 8.84,0.666 7,0.666C5.16,0.666 3.667,2.159 3.667,3.999V5.333H3C2.267,5.333 1.667,5.933 1.667,6.666V13.333C1.667,14.066 2.267,14.666 3,14.666H7.174C6.647,13.913 6.334,12.993 6.334,11.999C6.334,9.419 8.42,7.333 11,7.333ZM5,3.999C5,2.893 5.894,1.999 7,1.999C8.107,1.999 9,2.893 9,3.999V5.333H5V3.999Z" />
9+
<path
10+
android:fillColor="#19212F"
11+
android:pathData="M11,8.666C9.16,8.666 7.667,10.159 7.667,11.999C7.667,13.839 9.16,15.333 11,15.333C12.84,15.333 14.334,13.839 14.334,11.999C14.334,10.159 12.84,8.666 11,8.666ZM12.334,13.333C12.2,13.466 11.994,13.466 11.86,13.333L10.76,12.233C10.7,12.173 10.66,12.086 10.66,11.999V10.333C10.66,10.146 10.807,9.999 10.994,9.999C11.18,9.999 11.327,10.146 11.327,10.333V11.859L12.327,12.859C12.467,12.993 12.467,13.199 12.334,13.333Z" />
12+
</vector>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="16dp"
3+
android:height="16dp"
4+
android:viewportWidth="16"
5+
android:viewportHeight="16">
6+
<path
7+
android:fillColor="#19212F"
8+
android:pathData="M12,5.667H11.334V4.333C11.334,2.493 9.84,1 8,1C6.16,1 4.667,2.493 4.667,4.333V5.667H4C3.267,5.667 2.667,6.267 2.667,7V13.667C2.667,14.4 3.267,15 4,15H12C12.734,15 13.334,14.4 13.334,13.667V7C13.334,6.267 12.734,5.667 12,5.667ZM8,11.667C7.267,11.667 6.667,11.067 6.667,10.333C6.667,9.6 7.267,9 8,9C8.734,9 9.334,9.6 9.334,10.333C9.334,11.067 8.734,11.667 8,11.667ZM6,5.667V4.333C6,3.227 6.894,2.333 8,2.333C9.107,2.333 10,3.227 10,4.333V5.667H6Z" />
9+
</vector>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="17dp"
3+
android:height="17dp"
4+
android:viewportWidth="17"
5+
android:viewportHeight="17">
6+
<group>
7+
<clip-path android:pathData="M0.854,0.803h16v16h-16z" />
8+
<path
9+
android:fillColor="#19212F"
10+
android:pathData="M8.854,14.803L4.187,12.269V8.269L1.521,6.803L8.854,2.803L16.187,6.803V12.136H14.854V7.536L13.521,8.269V12.269L8.854,14.803ZM8.854,9.269L13.42,6.803L8.854,4.336L4.287,6.803L8.854,9.269ZM8.854,13.286L12.187,11.486V8.969L8.854,10.803L5.521,8.969V11.486L8.854,13.286Z" />
11+
</group>
12+
</vector>

0 commit comments

Comments
 (0)