Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace WeekViewEntity with more versatile WeekViewItem #272

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
testOptions {
unitTests.includeAndroidResources = true
}
}

dependencies {
Expand Down
122 changes: 50 additions & 72 deletions core/src/main/java/com/alamkanak/weekview/CalendarExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,6 @@ import kotlin.math.roundToInt

internal const val DAY_IN_MILLIS = 1000L * 60L * 60L * 24L

internal interface Duration {
val inMillis: Int
}

internal inline class Days(val days: Int) : Duration {
override val inMillis: Int
get() = days * (24 * 60 * 60 * 1_000)
}

internal inline class Hours(val hours: Int) : Duration {
override val inMillis: Int
get() = hours * (60 * 60 * 1_000)
}

internal inline class Minutes(val minutes: Int) : Duration {
override val inMillis: Int
get() = minutes * (60 * 1_000)
}

internal inline class Millis(val millis: Int) : Duration {
override val inMillis: Int
get() = millis
}

internal var Calendar.hour: Int
get() = get(Calendar.HOUR_OF_DAY)
set(value) {
Expand Down Expand Up @@ -61,82 +37,68 @@ internal val Calendar.year: Int

internal fun Calendar.isEqual(other: Calendar) = timeInMillis == other.timeInMillis

internal fun Calendar.isNotEqual(other: Calendar) = isEqual(other).not()

internal operator fun Calendar.plus(days: Days): Calendar {
internal fun Calendar.plusDays(days: Int): Calendar {
return copy().apply {
add(Calendar.DATE, days.days)
add(Calendar.DATE, days)
}
}

internal operator fun Calendar.plusAssign(days: Days) {
add(Calendar.DATE, days.days)
}

internal operator fun Calendar.minus(days: Days): Calendar {
internal fun Calendar.plusHours(hours: Int): Calendar {
return copy().apply {
add(Calendar.DATE, days.days * (-1))
add(Calendar.HOUR_OF_DAY, hours)
}
}

internal operator fun Calendar.minusAssign(days: Days) {
add(Calendar.DATE, days.days * (-1))
internal fun Calendar.addDays(days: Int) {
add(Calendar.DATE, days)
}

internal operator fun Calendar.plus(minutes: Minutes): Calendar {
internal fun Calendar.minusDays(days: Int): Calendar {
return copy().apply {
add(Calendar.MINUTE, minutes.minutes)
add(Calendar.DATE, days * -1)
}
}

internal operator fun Calendar.minus(minutes: Minutes): Calendar {
internal fun Calendar.minusHours(hours: Int): Calendar {
return copy().apply {
add(Calendar.MINUTE, minutes.minutes * (-1))
add(Calendar.HOUR_OF_DAY, hours * -1)
}
}

internal operator fun Calendar.minusAssign(minutes: Minutes) {
add(Calendar.MINUTE, minutes.minutes * (-1))
}

internal operator fun Calendar.plus(hours: Hours): Calendar {
internal fun Calendar.plusMillis(millis: Int): Calendar {
return copy().apply {
add(Calendar.HOUR_OF_DAY, hours.hours)
add(Calendar.MILLISECOND, millis)
}
}

internal operator fun Calendar.plusAssign(hours: Hours) {
add(Calendar.HOUR_OF_DAY, hours.hours)
}

internal operator fun Calendar.minus(hours: Hours): Calendar {
internal fun Calendar.minusMillis(millis: Int): Calendar {
return copy().apply {
add(Calendar.HOUR_OF_DAY, hours.hours * (-1))
add(Calendar.MILLISECOND, millis * -1)
}
}

internal operator fun Calendar.minusAssign(hours: Hours) {
add(Calendar.HOUR_OF_DAY, hours.hours * (-1))
internal fun Calendar.subtractMillis(millis: Int) {
add(Calendar.MILLISECOND, millis * -1)
}

internal operator fun Calendar.plus(millis: Millis): Calendar {
internal fun Calendar.plusMinutes(minutes: Int): Calendar {
return copy().apply {
add(Calendar.MILLISECOND, millis.millis)
add(Calendar.MINUTE, minutes)
}
}

internal operator fun Calendar.plusAssign(millis: Millis) {
add(Calendar.MILLISECOND, millis.millis)
}

internal operator fun Calendar.minus(millis: Millis): Calendar {
internal fun Calendar.minusMinutes(minutes: Int): Calendar {
return copy().apply {
add(Calendar.MILLISECOND, millis.millis * (-1))
add(Calendar.MINUTE, minutes * -1)
}
}

internal operator fun Calendar.minusAssign(millis: Millis) {
add(Calendar.MILLISECOND, millis.millis * (-1))
internal fun Calendar.subtractMinutes(hours: Int) {
add(Calendar.MINUTE, hours * -1)
}

internal fun Calendar.subtractHours(hours: Int) {
add(Calendar.HOUR_OF_DAY, hours * -1)
}

internal fun Calendar.isBefore(other: Calendar) = timeInMillis < other.timeInMillis
Expand All @@ -151,9 +113,9 @@ internal val Calendar.isToday: Boolean

internal fun Calendar.toEpochDays(): Int = (atStartOfDay.timeInMillis / DAY_IN_MILLIS).toInt()

internal infix fun Calendar.minutesUntil(other: Calendar): Minutes {
internal infix fun Calendar.minutesUntil(other: Calendar): Int {
val diff = (timeInMillis - other.timeInMillis) / 60_000
return Minutes(diff.toInt())
return diff.toInt()
}

internal val Calendar.lengthOfMonth: Int
Expand Down Expand Up @@ -245,7 +207,7 @@ internal fun List<Calendar>.validate(viewState: ViewState): List<Calendar> {
viewState.createDateRange(minDate!!)
}
mustAdjustEnd -> {
val start = maxDate!! - Days(viewState.numberOfVisibleDays - 1)
val start = maxDate!!.minusDays(viewState.numberOfVisibleDays - 1)
viewState.createDateRange(start)
}
else -> {
Expand Down Expand Up @@ -310,7 +272,7 @@ internal fun Calendar.format(): String {
return sdf.format(time)
}

fun Calendar.computeDifferenceWithFirstDayOfWeek(): Int {
internal fun Calendar.computeDifferenceWithFirstDayOfWeek(): Int {
val firstDayOfWeek = firstDayOfWeek
return if (firstDayOfWeek == Calendar.MONDAY && dayOfWeek == Calendar.SUNDAY) {
// Special case, because Calendar.MONDAY has constant value 2 and Calendar.SUNDAY has
Expand All @@ -321,18 +283,34 @@ fun Calendar.computeDifferenceWithFirstDayOfWeek(): Int {
}
}

fun Calendar.previousFirstDayOfWeek(): Calendar {
val result = this - Days(1)
internal fun Calendar.previousFirstDayOfWeek(): Calendar {
val result = this.minusDays(1)
while (result.dayOfWeek != firstDayOfWeek) {
result.add(Calendar.DATE, -1)
}
return result
}

fun Calendar.nextFirstDayOfWeek(): Calendar {
val result = this + Days(1)
internal fun Calendar.nextFirstDayOfWeek(): Calendar {
val result = this.plusDays(1)
while (result.dayOfWeek != firstDayOfWeek) {
result.add(Calendar.DATE, 1)
}
return result
}

internal fun Calendar.limitToMinHour(minHour: Int): Calendar {
return if (hour < minHour) {
withTimeAtStartOfPeriod(hour = minHour)
} else {
this
}
}

internal fun Calendar.limitToMaxHour(maxHour: Int): Calendar {
return if (hour >= maxHour) {
withTimeAtEndOfPeriod(hour = maxHour)
} else {
this
}
}
16 changes: 12 additions & 4 deletions core/src/main/java/com/alamkanak/weekview/CalendarRenderer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ private class SingleEventsUpdater(
}

val eventChips = chipsCache?.normalEventChipsByDate(date).orEmpty().filter {
it.event.isWithin(viewState.minHour, viewState.maxHour)
it.item.isWithin(viewState.minHour, viewState.maxHour)
}

eventChips.calculateBounds(startPixel = modifiedStartPixel)
Expand Down Expand Up @@ -244,11 +244,19 @@ private class SingleEventsDrawer(
return
}

val sortedEventChips = eventChips.sortedBy {
it.event.id == viewState.dragState?.eventId
val (backgroundChips, foregroundChips) = eventChips.partition {
it.item.configuration.arrangement == WeekViewItem.Arrangement.Background
}

for (eventChip in sortedEventChips) {
val draggedEventId = viewState.dragState?.eventId

val sortedChips = mutableListOf<EventChip>().apply {
// Make sure that the currently dragged chip is rendered above all other chips
this += backgroundChips.sortedBy { it.item.id == draggedEventId }
this += foregroundChips.sortedBy { it.item.id == draggedEventId }
}

for (eventChip in sortedChips) {
val textLayout = eventLabels[eventChip.id]
eventChipDrawer.draw(eventChip, canvas = this, textLayout)
}
Expand Down
44 changes: 26 additions & 18 deletions core/src/main/java/com/alamkanak/weekview/DragHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal class DragHandler(

private val executor = DragScrollExecutor()

private val draggedEvent: ResolvedWeekViewEntity?
private val draggedEvent: WeekViewItem?
get() {
val eventsCache = eventsCacheProvider() ?: return null
val eventId = viewState.dragState?.eventId ?: return null
Expand All @@ -30,8 +30,8 @@ internal class DragHandler(

fun startDragAndDrop(eventChip: EventChip, x: Float, y: Float) {
viewState.dragState = DragState(
eventId = eventChip.eventId,
draggedEventStartTime = eventChip.event.startTime,
eventId = eventChip.itemId,
draggedEventStartTime = eventChip.item.duration.startTime,
dragStartTime = requireNotNull(touchHandler.calculateTimeFromPoint(x, y)),
)

Expand Down Expand Up @@ -64,33 +64,33 @@ internal class DragHandler(
): Calendar {
val dragState = requireNotNull(viewState.dragState)
val delta = currentDragLocation minutesUntil dragState.dragStartTime
return dragState.draggedEventStartTime + delta
return dragState.draggedEventStartTime.plusMinutes(delta)
}

private fun sanitizeEventStart(
rawEventStart: Calendar,
): Calendar {
val minutesBeyondQuarterHour = rawEventStart.minute % 15
val minutesUntilNextQuarterHour = 15 - minutesBeyondQuarterHour

return if (minutesBeyondQuarterHour >= 8) {
// Go to next quarter hour
rawEventStart + Minutes(minutesUntilNextQuarterHour)
val minutesUntilNextQuarterHour = 15 - minutesBeyondQuarterHour
rawEventStart.plusMinutes(minutesUntilNextQuarterHour)
} else {
// Go to previous quarter hour
rawEventStart - Minutes(minutesBeyondQuarterHour)
rawEventStart.minusMinutes(minutesBeyondQuarterHour)
}
}

private fun updateDraggedEvent(newStartTime: Calendar) {
val originalEvent = draggedEvent ?: return
val updatedEvent = originalEvent.createCopy(
val updatedEvent = originalEvent.copyWith(
startTime = newStartTime,
endTime = newStartTime + Minutes(originalEvent.durationInMinutes),
endTime = newStartTime.plusMinutes(originalEvent.durationInMinutes),
)

val eventsProcessor = eventsProcessorProvider() ?: return
eventsProcessor.updateDraggedEntity(updatedEvent, viewState)
eventsProcessor.updateDraggedItem(updatedEvent, viewState)
}

private fun scrollIfNecessary(e: MotionEvent) {
Expand All @@ -116,7 +116,7 @@ internal class DragHandler(
}

val draggedEvent = draggedEvent ?: return@execute
updateDraggedEvent(newStartTime = draggedEvent.startTime - Minutes(15))
updateDraggedEvent(newStartTime = draggedEvent.duration.startTime.minusMinutes(15))

val distance = viewState.hourHeight / 4f
navigator.scrollVerticallyBy(distance = distance * (-1))
Expand All @@ -132,30 +132,38 @@ internal class DragHandler(
}

val draggedEvent = draggedEvent ?: return@execute
updateDraggedEvent(newStartTime = draggedEvent.startTime + Minutes(15))
updateDraggedEvent(newStartTime = draggedEvent.duration.startTime.plusMinutes(15))

val distance = viewState.hourHeight / 4f
navigator.scrollVerticallyBy(distance = distance)
}
}

private fun scrollLeft() {
if (!viewState.horizontalScrollingEnabled) {
return
}

executor.execute(delay = 600) {
val draggedEvent = draggedEvent ?: return@execute
updateDraggedEvent(newStartTime = draggedEvent.startTime - Days(1))
updateDraggedEvent(newStartTime = draggedEvent.duration.startTime.minusDays(1))

val date = draggedEvent.startTime.atStartOfDay
navigator.scrollHorizontallyTo(date - Days(1))
val date = draggedEvent.duration.startTime.atStartOfDay
navigator.scrollHorizontallyTo(date.minusDays(1))
}
}

private fun scrollRight() {
if (!viewState.horizontalScrollingEnabled) {
return
}

executor.execute(delay = 600) {
val draggedEvent = draggedEvent ?: return@execute
updateDraggedEvent(newStartTime = draggedEvent.startTime + Days(1))
updateDraggedEvent(newStartTime = draggedEvent.duration.startTime.plusDays(1))

val date = draggedEvent.startTime.atStartOfDay
navigator.scrollHorizontallyTo(date + Days(1))
val date = draggedEvent.duration.startTime.atStartOfDay
navigator.scrollHorizontallyTo(date.plusDays(1))
}
}

Expand Down
Loading