From 420a19e0c4e83e5c5f3107fba428a16d30a134e2 Mon Sep 17 00:00:00 2001 From: Till Hellmund Date: Thu, 20 Jan 2022 21:32:04 -0500 Subject: [PATCH] Revert back to using builder pattern This is more extensible for the date library modules. --- .../com/alamkanak/weekview/WeekViewItem.kt | 78 +++++++++++++++---- .../com/alamkanak/weekview/DiffResultTest.kt | 6 +- .../java/com/alamkanak/weekview/util/Mocks.kt | 5 +- .../weekview/jodatime/DurationExtensions.kt | 35 --------- .../jodatime/WeekViewItemBuilderExtensions.kt | 16 ++++ .../weekview/jsr310/DurationExtensions.kt | 35 --------- .../jsr310/WeekViewItemBuilderExtensions.kt | 16 ++++ .../weekview/sample/data/EventsRepository.kt | 4 +- .../weekview/sample/data/model/ApiEvent.kt | 21 +++-- .../sample/data/model/CalendarItem.kt | 68 ++++++++-------- .../weekview/sample/ui/BasicActivity.kt | 2 +- .../threetenabp/DurationExtensions.kt | 35 --------- .../WeekViewItemBuilderExtensions.kt | 16 ++++ 13 files changed, 169 insertions(+), 168 deletions(-) delete mode 100644 jodatime/src/main/java/com/alamkanak/weekview/jodatime/DurationExtensions.kt create mode 100644 jodatime/src/main/java/com/alamkanak/weekview/jodatime/WeekViewItemBuilderExtensions.kt delete mode 100644 jsr310/src/main/java/com/alamkanak/weekview/jsr310/DurationExtensions.kt create mode 100644 jsr310/src/main/java/com/alamkanak/weekview/jsr310/WeekViewItemBuilderExtensions.kt delete mode 100644 threetenabp/src/main/java/com/alamkanak/weekview/threetenabp/DurationExtensions.kt create mode 100644 threetenabp/src/main/java/com/alamkanak/weekview/threetenabp/WeekViewItemBuilderExtensions.kt diff --git a/core/src/main/java/com/alamkanak/weekview/WeekViewItem.kt b/core/src/main/java/com/alamkanak/weekview/WeekViewItem.kt index d88f9835..db2047dc 100644 --- a/core/src/main/java/com/alamkanak/weekview/WeekViewItem.kt +++ b/core/src/main/java/com/alamkanak/weekview/WeekViewItem.kt @@ -12,7 +12,7 @@ import java.util.Calendar * The item is rendered based on the information provided in its [style] and [configuration] * properties. */ -data class WeekViewItem( +data class WeekViewItem internal constructor( val id: Long = 0L, val title: CharSequence, val subtitle: CharSequence? = null, @@ -100,6 +100,67 @@ data class WeekViewItem( } } + companion object { + fun of(data: Any): Builder = Builder(data) + } + + /** + * Builder to construct a [WeekViewItem]. A [WeekViewItem] needs an [id], a [title], and + * a [duration]. The latter can be a [WeekViewItem.Duration.AllDay] or a + * [WeekViewItem.Duration.Bounded]. + */ + class Builder internal constructor(private val data: Any) { + + private var id: Long? = null + private var title: CharSequence? = null + private var subtitle: CharSequence? = null + private var duration: Duration? = null + private var style: Style = Style() + private var configuration = Configuration() + + fun setId(id: Long): Builder { + this.id = id + return this + } + + fun setTitle(title: CharSequence): Builder { + this.title = title + return this + } + + fun setSubtitle(subtitle: CharSequence): Builder { + this.subtitle = subtitle + return this + } + + fun setAllDayDuration(date: Calendar): Builder { + this.duration = Duration.AllDay(date) + return this + } + + fun setBoundedDuration(startTime: Calendar, endTime: Calendar): Builder { + this.duration = Duration.Bounded(startTime, endTime) + return this + } + + fun setStyle(style: Style): Builder { + this.style = style + return this + } + + fun setConfiguration(configuration: Configuration): Builder { + this.configuration = configuration + return this + } + + fun build(): WeekViewItem { + val id = requireNotNull(id) { "id == null" } + val title = requireNotNull(title) { "title == null" } + val duration = requireNotNull(duration) { "duration == null" } + return WeekViewItem(id, title, subtitle, duration, style, configuration, data) + } + } + internal val isAllDay: Boolean = duration is Duration.AllDay internal val isNotAllDay: Boolean = !isAllDay @@ -141,21 +202,6 @@ data class WeekViewItem( internal fun collidesWith(other: WeekViewItem): Boolean = duration.overlapsWith(other.duration) } -/** - * Creates an [WeekViewItem.Duration.AllDay] with the receiving [Calendar] as the date. - */ -fun Calendar.toAllDayDuration(): WeekViewItem.Duration.AllDay { - return WeekViewItem.Duration.AllDay(date = this.atStartOfDay) -} - -/** - * Creates an [WeekViewItem.Duration.Bounded] with the receiving [Calendar] as the start time and - * the provided parameter as the end time. - */ -fun Calendar.toBoundedDurationUntil(endTime: Calendar): WeekViewItem.Duration.Bounded { - return WeekViewItem.Duration.Bounded(startTime = this, endTime = endTime) -} - private fun WeekViewItem.Duration.overlapsWith(other: WeekViewItem.Duration): Boolean { if (this is WeekViewItem.Duration.AllDay || other is WeekViewItem.Duration.AllDay) { return false diff --git a/core/src/test/java/com/alamkanak/weekview/DiffResultTest.kt b/core/src/test/java/com/alamkanak/weekview/DiffResultTest.kt index 57567b4a..fec91bc6 100644 --- a/core/src/test/java/com/alamkanak/weekview/DiffResultTest.kt +++ b/core/src/test/java/com/alamkanak/weekview/DiffResultTest.kt @@ -45,7 +45,7 @@ class DiffResultTest { val existingEntity = Mocks.weekViewItem() val newEntity = existingEntity.copyWith( startTime = existingEntity.duration.startTime, - endTime = existingEntity.duration.endTime + Hours(1) + endTime = existingEntity.duration.endTime.plusMinutes(60), ) val result = DiffResult.calculateDiff( @@ -60,12 +60,12 @@ class DiffResultTest { @Test fun `New and updated entities are correctly recognized together`() { val startTime = Calendar.getInstance() - val endTime = startTime + Hours(1) + val endTime = startTime.plusMinutes(60) val existingEntity = Mocks.weekViewItem(startTime, endTime) val updatedEntity = existingEntity.copyWith( startTime = existingEntity.duration.startTime, - endTime = existingEntity.duration.endTime + Hours(1), + endTime = existingEntity.duration.endTime.plusMinutes(60), ) val newEntity = Mocks.weekViewItem(startTime, endTime) diff --git a/core/src/test/java/com/alamkanak/weekview/util/Mocks.kt b/core/src/test/java/com/alamkanak/weekview/util/Mocks.kt index 77fe4b63..a6af692a 100644 --- a/core/src/test/java/com/alamkanak/weekview/util/Mocks.kt +++ b/core/src/test/java/com/alamkanak/weekview/util/Mocks.kt @@ -1,8 +1,7 @@ package com.alamkanak.weekview.util -import com.alamkanak.weekview.Hours import com.alamkanak.weekview.WeekViewItem -import com.alamkanak.weekview.plus +import com.alamkanak.weekview.plusMinutes import java.util.Calendar import kotlin.random.Random @@ -14,7 +13,7 @@ internal object Mocks { fun weekViewItem( startTime: Calendar = Calendar.getInstance(), - endTime: Calendar = Calendar.getInstance() + Hours(1), + endTime: Calendar = Calendar.getInstance().plusMinutes(60), ): WeekViewItem { val id = Random.nextLong() return WeekViewItem( diff --git a/jodatime/src/main/java/com/alamkanak/weekview/jodatime/DurationExtensions.kt b/jodatime/src/main/java/com/alamkanak/weekview/jodatime/DurationExtensions.kt deleted file mode 100644 index c0a2b8b2..00000000 --- a/jodatime/src/main/java/com/alamkanak/weekview/jodatime/DurationExtensions.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.alamkanak.weekview.jodatime - -import com.alamkanak.weekview.PublicApi -import com.alamkanak.weekview.WeekViewItem -import org.joda.time.LocalDate -import org.joda.time.LocalDateTime - -/** - * Creates an [WeekViewItem.Duration.AllDay] with the receiving [LocalDate] as the date. - */ -@PublicApi -fun LocalDate.toAllDayDuration(): WeekViewItem.Duration.AllDay { - return WeekViewItem.Duration.AllDay(date = this.toCalendar()) -} - -/** - * Creates an [WeekViewItem.Duration.AllDay] with the receiving [LocalDateTime.toLocalDate] as the - * date. - */ -@PublicApi -fun LocalDateTime.toAllDayDuration(): WeekViewItem.Duration.AllDay { - return toLocalDate().toAllDayDuration() -} - -/** - * Creates an [WeekViewItem.Duration.Bounded] with the receiving [LocalDateTime] as the start time - * and the provided parameter as the end time. - */ -@PublicApi -fun LocalDateTime.toBoundedDurationUntil(endTime: LocalDateTime): WeekViewItem.Duration.Bounded { - return WeekViewItem.Duration.Bounded( - startTime = this.toCalendar(), - endTime = endTime.toCalendar(), - ) -} diff --git a/jodatime/src/main/java/com/alamkanak/weekview/jodatime/WeekViewItemBuilderExtensions.kt b/jodatime/src/main/java/com/alamkanak/weekview/jodatime/WeekViewItemBuilderExtensions.kt new file mode 100644 index 00000000..01715678 --- /dev/null +++ b/jodatime/src/main/java/com/alamkanak/weekview/jodatime/WeekViewItemBuilderExtensions.kt @@ -0,0 +1,16 @@ +package com.alamkanak.weekview.jodatime + +import com.alamkanak.weekview.WeekViewItem +import org.joda.time.LocalDate +import org.joda.time.LocalDateTime + +fun WeekViewItem.Builder.setAllDayDuration(date: LocalDate): WeekViewItem.Builder { + return setAllDayDuration(date.toCalendar()) +} + +fun WeekViewItem.Builder.setBoundedDuration( + startTime: LocalDateTime, + endTime: LocalDateTime, +): WeekViewItem.Builder { + return setBoundedDuration(startTime.toCalendar(), endTime.toCalendar()) +} diff --git a/jsr310/src/main/java/com/alamkanak/weekview/jsr310/DurationExtensions.kt b/jsr310/src/main/java/com/alamkanak/weekview/jsr310/DurationExtensions.kt deleted file mode 100644 index 12d0cc98..00000000 --- a/jsr310/src/main/java/com/alamkanak/weekview/jsr310/DurationExtensions.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.alamkanak.weekview.jsr310 - -import com.alamkanak.weekview.PublicApi -import com.alamkanak.weekview.WeekViewItem -import java.time.LocalDate -import java.time.LocalDateTime - -/** - * Creates an [WeekViewItem.Duration.AllDay] with the receiving [LocalDate] as the date. - */ -@PublicApi -fun LocalDate.toAllDayDuration(): WeekViewItem.Duration.AllDay { - return WeekViewItem.Duration.AllDay(date = this.toCalendar()) -} - -/** - * Creates an [WeekViewItem.Duration.AllDay] with the receiving [LocalDateTime.toLocalDate] as the - * date. - */ -@PublicApi -fun LocalDateTime.toAllDayDuration(): WeekViewItem.Duration.AllDay { - return toLocalDate().toAllDayDuration() -} - -/** - * Creates an [WeekViewItem.Duration.Bounded] with the receiving [LocalDateTime] as the start time - * and the provided parameter as the end time. - */ -@PublicApi -fun LocalDateTime.toBoundedDurationUntil(endTime: LocalDateTime): WeekViewItem.Duration.Bounded { - return WeekViewItem.Duration.Bounded( - startTime = this.toCalendar(), - endTime = endTime.toCalendar(), - ) -} diff --git a/jsr310/src/main/java/com/alamkanak/weekview/jsr310/WeekViewItemBuilderExtensions.kt b/jsr310/src/main/java/com/alamkanak/weekview/jsr310/WeekViewItemBuilderExtensions.kt new file mode 100644 index 00000000..fe84e4ae --- /dev/null +++ b/jsr310/src/main/java/com/alamkanak/weekview/jsr310/WeekViewItemBuilderExtensions.kt @@ -0,0 +1,16 @@ +package com.alamkanak.weekview.jsr310 + +import com.alamkanak.weekview.WeekViewItem +import java.time.LocalDate +import java.time.LocalDateTime + +fun WeekViewItem.Builder.setAllDayDuration(date: LocalDate): WeekViewItem.Builder { + return setAllDayDuration(date.toCalendar()) +} + +fun WeekViewItem.Builder.setBoundedDuration( + startTime: LocalDateTime, + endTime: LocalDateTime, +): WeekViewItem.Builder { + return setBoundedDuration(startTime.toCalendar(), endTime.toCalendar()) +} diff --git a/sample/src/main/java/com/alamkanak/weekview/sample/data/EventsRepository.kt b/sample/src/main/java/com/alamkanak/weekview/sample/data/EventsRepository.kt index fa7c35ba..f57ff608 100644 --- a/sample/src/main/java/com/alamkanak/weekview/sample/data/EventsRepository.kt +++ b/sample/src/main/java/com/alamkanak/weekview/sample/data/EventsRepository.kt @@ -21,7 +21,7 @@ class EventsRepository(private val context: Context) { fun fetch( yearMonths: List, - onSuccess: (List) -> Unit + onSuccess: (List) -> Unit, ) { val handlerThread = HandlerThread("events-fetching") handlerThread.start() @@ -34,7 +34,7 @@ class EventsRepository(private val context: Context) { val calendarEntities = yearMonths.flatMap { yearMonth -> apiEntities.mapIndexedNotNull { index, apiResult -> - apiResult.toCalendarEntity(yearMonth, index) + apiResult.toCalendarItem(yearMonth, index) } } diff --git a/sample/src/main/java/com/alamkanak/weekview/sample/data/model/ApiEvent.kt b/sample/src/main/java/com/alamkanak/weekview/sample/data/model/ApiEvent.kt index 1f6ddec2..9410a991 100644 --- a/sample/src/main/java/com/alamkanak/weekview/sample/data/model/ApiEvent.kt +++ b/sample/src/main/java/com/alamkanak/weekview/sample/data/model/ApiEvent.kt @@ -7,7 +7,7 @@ import java.time.LocalTime import java.time.YearMonth interface ApiResult { - fun toCalendarEntity(yearMonth: YearMonth, index: Int): CalendarItem? + fun toCalendarItem(yearMonth: YearMonth, index: Int): CalendarItem? } data class ApiEvent( @@ -18,16 +18,16 @@ data class ApiEvent( @SerializedName("duration") val duration: Int, @SerializedName("color") val color: String, @SerializedName("is_canceled") val isCanceled: Boolean, - @SerializedName("is_all_day") val isAllDay: Boolean + @SerializedName("is_all_day") val isAllDay: Boolean, ) : ApiResult { - override fun toCalendarEntity(yearMonth: YearMonth, index: Int): CalendarItem? { + override fun toCalendarItem(yearMonth: YearMonth, index: Int): CalendarItem? { return try { val startTime = LocalTime.parse(startTime) val startDateTime = yearMonth.atDay(dayOfMonth).atTime(startTime) val endDateTime = startDateTime.plusMinutes(duration.toLong()) CalendarItem.Event( - id = "100${yearMonth.year}00${yearMonth.monthValue}00$index".toLong(), + id = generateId(yearMonth, index), title = title, location = location, startTime = startDateTime, @@ -45,16 +45,16 @@ data class ApiEvent( data class ApiBlockedTime( @SerializedName("day_of_month") val dayOfMonth: Int, @SerializedName("start_time") val startTime: String, - @SerializedName("duration") val duration: Int + @SerializedName("duration") val duration: Int, ) : ApiResult { - override fun toCalendarEntity(yearMonth: YearMonth, index: Int): CalendarItem? { + override fun toCalendarItem(yearMonth: YearMonth, index: Int): CalendarItem? { return try { val startTime = LocalTime.parse(startTime) val startDateTime = yearMonth.atDay(dayOfMonth).atTime(startTime) val endDateTime = startDateTime.plusMinutes(duration.toLong()) CalendarItem.BlockedTimeSlot( - id = "200${yearMonth.year}00${yearMonth.monthValue}00$index".toLong(), + id = generateId(yearMonth, index), startTime = startDateTime, endTime = endDateTime ) @@ -63,3 +63,10 @@ data class ApiBlockedTime( } } } + +private fun generateId(yearMonth: YearMonth, index: Int): Long { + val eventNumber = index.toString().padStart(length = 4, padChar = '0') + val year = yearMonth.year * 1_000_000 + val month = yearMonth.monthValue * 1_000 + return "$year$month$eventNumber".toLong() +} diff --git a/sample/src/main/java/com/alamkanak/weekview/sample/data/model/CalendarItem.kt b/sample/src/main/java/com/alamkanak/weekview/sample/data/model/CalendarItem.kt index af0e282e..c6dfdb1d 100644 --- a/sample/src/main/java/com/alamkanak/weekview/sample/data/model/CalendarItem.kt +++ b/sample/src/main/java/com/alamkanak/weekview/sample/data/model/CalendarItem.kt @@ -9,10 +9,10 @@ import android.text.style.TypefaceSpan import androidx.core.content.ContextCompat import com.alamkanak.weekview.WeekViewEntity import com.alamkanak.weekview.WeekViewItem +import com.alamkanak.weekview.jsr310.setAllDayDuration +import com.alamkanak.weekview.jsr310.setBoundedDuration import com.alamkanak.weekview.jsr310.setEndTime import com.alamkanak.weekview.jsr310.setStartTime -import com.alamkanak.weekview.jsr310.toAllDayDuration -import com.alamkanak.weekview.jsr310.toBoundedDurationUntil import com.alamkanak.weekview.sample.R import java.time.LocalDateTime @@ -63,40 +63,46 @@ fun CalendarItem.Event.toWeekViewItem(context: Context): WeekViewItem { } } - val timing = if (isAllDay) { - startTime.toAllDayDuration() - } else { - startTime.toBoundedDurationUntil(endTime) - } - - return WeekViewItem( - id = id, - title = title, - subtitle = subtitle, - duration = timing, - style = WeekViewItem.Style( - textColor = textColor, - backgroundColor = backgroundColor, - borderWidth = borderWidth, - borderColor = color, - ), - configuration = WeekViewItem.Configuration.foreground(), - data = this, + val style = WeekViewItem.Style( + textColor = textColor, + backgroundColor = backgroundColor, + borderWidth = borderWidth, + borderColor = color, ) + + val config = WeekViewItem.Configuration.foreground() + + return WeekViewItem.of(this) + .setId(id) + .setTitle(title) + .setSubtitle(subtitle) + .apply { + if (isAllDay) { + setAllDayDuration(startTime.toLocalDate()) + } else { + setBoundedDuration(startTime, endTime) + } + } + .setStyle(style) + .setConfiguration(config) + .build() } fun CalendarItem.BlockedTimeSlot.toWeekViewItem(context: Context): WeekViewItem { - return WeekViewItem( - id = id, - title = "Unavailable", - duration = startTime.toBoundedDurationUntil(endTime), - style = WeekViewItem.Style( - backgroundColor = ContextCompat.getColor(context, R.color.gray_alpha10), - cornerRadius = context.resources.getDimensionPixelSize(R.dimen.no_corner_radius), - ), - configuration = WeekViewItem.Configuration.background(), - data = this, + val style = WeekViewItem.Style( + backgroundColor = ContextCompat.getColor(context, R.color.gray_alpha10), + cornerRadius = context.resources.getDimensionPixelSize(R.dimen.no_corner_radius), ) + + val config = WeekViewItem.Configuration.background() + + return WeekViewItem.of(this) + .setId(id) + .setTitle("Unavailable") + .setBoundedDuration(startTime, endTime) + .setStyle(style) + .setConfiguration(config) + .build() } fun CalendarItem.toWeekViewEntity(): WeekViewEntity { diff --git a/sample/src/main/java/com/alamkanak/weekview/sample/ui/BasicActivity.kt b/sample/src/main/java/com/alamkanak/weekview/sample/ui/BasicActivity.kt index 438decdb..bda4b470 100644 --- a/sample/src/main/java/com/alamkanak/weekview/sample/ui/BasicActivity.kt +++ b/sample/src/main/java/com/alamkanak/weekview/sample/ui/BasicActivity.kt @@ -71,7 +71,7 @@ class BasicActivity : AppCompatActivity() { } } -private class BasicActivityWeekViewAdapter( +class BasicActivityWeekViewAdapter( private val dragHandler: (Long, LocalDateTime, LocalDateTime) -> Unit, private val loadMoreHandler: (List) -> Unit ) : WeekViewPagingAdapterJsr310() { diff --git a/threetenabp/src/main/java/com/alamkanak/weekview/threetenabp/DurationExtensions.kt b/threetenabp/src/main/java/com/alamkanak/weekview/threetenabp/DurationExtensions.kt deleted file mode 100644 index 17d0ecaf..00000000 --- a/threetenabp/src/main/java/com/alamkanak/weekview/threetenabp/DurationExtensions.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.alamkanak.weekview.threetenabp - -import com.alamkanak.weekview.PublicApi -import com.alamkanak.weekview.WeekViewItem -import org.threeten.bp.LocalDate -import org.threeten.bp.LocalDateTime - -/** - * Creates an [WeekViewItem.Duration.AllDay] with the receiving [LocalDate] as the date. - */ -@PublicApi -fun LocalDate.toAllDayDuration(): WeekViewItem.Duration.AllDay { - return WeekViewItem.Duration.AllDay(date = this.toCalendar()) -} - -/** - * Creates an [WeekViewItem.Duration.AllDay] with the receiving [LocalDateTime.toLocalDate] as the - * date. - */ -@PublicApi -fun LocalDateTime.toAllDayDuration(): WeekViewItem.Duration.AllDay { - return toLocalDate().toAllDayDuration() -} - -/** - * Creates an [WeekViewItem.Duration.Bounded] with the receiving [LocalDateTime] as the start time - * and the provided parameter as the end time. - */ -@PublicApi -fun LocalDateTime.toBoundedDurationUntil(endTime: LocalDateTime): WeekViewItem.Duration.Bounded { - return WeekViewItem.Duration.Bounded( - startTime = this.toCalendar(), - endTime = endTime.toCalendar(), - ) -} diff --git a/threetenabp/src/main/java/com/alamkanak/weekview/threetenabp/WeekViewItemBuilderExtensions.kt b/threetenabp/src/main/java/com/alamkanak/weekview/threetenabp/WeekViewItemBuilderExtensions.kt new file mode 100644 index 00000000..bbad3510 --- /dev/null +++ b/threetenabp/src/main/java/com/alamkanak/weekview/threetenabp/WeekViewItemBuilderExtensions.kt @@ -0,0 +1,16 @@ +package com.alamkanak.weekview.threetenabp + +import com.alamkanak.weekview.WeekViewItem +import org.threeten.bp.LocalDate +import org.threeten.bp.LocalDateTime + +fun WeekViewItem.Builder.setAllDayDuration(date: LocalDate): WeekViewItem.Builder { + return setAllDayDuration(date.toCalendar()) +} + +fun WeekViewItem.Builder.setBoundedDuration( + startTime: LocalDateTime, + endTime: LocalDateTime, +): WeekViewItem.Builder { + return setBoundedDuration(startTime.toCalendar(), endTime.toCalendar()) +}