Skip to content

Commit

Permalink
Add module with a support for kotlinx-datetime (#61)
Browse files Browse the repository at this point in the history
  • Loading branch information
boguszpawlowski authored Apr 16, 2022
1 parent 3c56ff1 commit 0768d84
Show file tree
Hide file tree
Showing 21 changed files with 369 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish-snapshot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_NEXUS_USERNAME }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_NEXUS_PASSWORD }}
run: ./gradlew :library:publish --no-daemon --no-parallel --stacktrace
run: ./gradlew publish --no-daemon --no-parallel --stacktrace


- name: Stop Gradle
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_NEXUS_PASSWORD }}
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SONATYPE_NEXUS_SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SONATYPE_NEXUS_SIGNING_KEY_PASSWORD }}
run: ./gradlew :library:publish --no-daemon --no-parallel --stacktrace
run: ./gradlew publish --no-daemon --no-parallel --stacktrace

- name: Publish release
env:
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright 2022 Bogusz Pawłowski

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ Library is available on Maven Central repository.
// module-level build.gradle
dependecies {
implementation "io.github.boguszpawlowski.composecalendar:composecalendar:<latest-version>"

// separate artifact with utilities for working with kotlinx-datetime
implementation "io.github.boguszpawlowski.composecalendar:kotlinx-datetime:<latest-version>"
}
```
Snapshots are available on [Sonatype’s snapshots repository](https://s01.oss.sonatype.org/content/repositories/snapshots/io/github/boguszpawlowski/composecalendar/).
Expand Down Expand Up @@ -182,9 +185,13 @@ Selection modes are represented by `SelectionMode` enum, with following values:
- `Multiple` - a list of dates can be selected.
- `Period` - selectable period - implemented by `start` and `end` dates. - selection will contain all dates between start and the end date.

## KotlinX DateTime
As the core of the library is built on `java.time` library, on Android it requires to use [core libary desugaring](https://developer.android.com/studio/write/java8-support) to be able to access it's API.
As a result library may be unavailable to some project built around different date libraries. Although the library wont be migrating from `java.time`, as it's the best suited for this project, there is a separate `kotlinx-datetime` artifact for those who need to use the library from a codebase based on it. It doesn't consist of a separate version of `ComposeCalendar` features, but offers a small bunch of utilities, that will enable you to create your own wrapper, as briefly presented in `KotlinDateTimeSample`.

## License

Copyright 2021 Bogusz Pawłowski
Copyright 2022 Bogusz Pawłowski

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
1 change: 1 addition & 0 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ object Kotlin {
const val JvmPluginId = "jvm"

const val DesugarJdkLibs = "com.android.tools:desugar_jdk_libs:1.1.5"
const val DateTime = "org.jetbrains.kotlinx:kotlinx-datetime:0.3.2"
}

object Android {
Expand Down
4 changes: 2 additions & 2 deletions detekt-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ naming:
privatePropertyPattern: '^[A-Z][a-z]+(?:[A-Z][a-z]+)*$'
PackageNaming:
active: true
packagePattern: '^[a-z]+(\.[a-z][a-z]*)*$'
packagePattern: '^[a-z]+(\.[a-z][a-zA-Z]*)*$'
TopLevelPropertyNaming:
active: false
constantPattern: '^[a-z]+(?:[A-Z][a-z]+)*$'
Expand Down Expand Up @@ -244,7 +244,7 @@ style:
active: true
RedundantVisibilityModifierRule:
active: true
excludes: ['**/library/**']
excludes: ['**/library/**', '**/kotlinx-datetime/**']
SafeCast:
active: true
SerialVersionUIDInSerializableClass:
Expand Down
12 changes: 12 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,15 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
android.useAndroidX=true
android.enableJetifier=true
kotlin.code.style=official

POM_NAME=Compose Calendar
GROUP=io.github.boguszpawlowski.composecalendar
POM_URL=https://github.com/boguszpawlowski/ComposeCalendar
POM_SCM_URL=https://github.com/boguszpawlowski/ComposeCalendar
POM_SCM_CONNECTION=git@github.com:boguszpawlowski/ComposeCalendar.git
POM_SCM_DEV_CONNECTION=git@github.com:boguszpawlowski/ComposeCalendar.git
POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=boguszp
POM_DEVELOPER_NAME=Bogusz Pawlowski
1 change: 1 addition & 0 deletions kotlinx-datetime/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
26 changes: 26 additions & 0 deletions kotlinx-datetime/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import com.vanniktech.maven.publish.SonatypeHost

plugins {
kotlin(Kotlin.JvmPluginId)
id(MavenPublish.PluginId)
}

kotlin {
explicitApi()
}

dependencies {
api(Kotlin.DateTime)
implementation(Kotlin.StdLib)

testImplementation(Kotest.Assertions)
testImplementation(Kotest.RunnerJunit5)
testImplementation(Kotlin.Reflect)
}

plugins.withId("com.vanniktech.maven.publish") {
mavenPublish {
sonatypeHost = SonatypeHost.S01
releaseSigningEnabled = true
}
}
3 changes: 3 additions & 0 deletions kotlinx-datetime/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
POM_ARTIFACT_ID=kotlinx-datetime
POM_DESCRIPTION=A set of utilities supporting usage of kotlin datetime instead of java.time.
POM_PACKAGING=aar
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.github.boguszpawlowski.composecalendar.kotlinxDateTime

public fun YearMonth.toJavaYearMonth(): java.time.YearMonth = java.time.YearMonth.of(year, month)

public fun java.time.YearMonth.toKotlinYearMonth(): YearMonth = YearMonth.of(year, month)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.github.boguszpawlowski.composecalendar.kotlinxDateTime

import kotlinx.datetime.Clock
import kotlinx.datetime.DayOfWeek
import kotlinx.datetime.LocalDate
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
import java.time.temporal.WeekFields
import java.util.Locale

public fun LocalDate.Companion.now(): LocalDate =
Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date

public val Locale.firstDayOfWeek: DayOfWeek
get() = WeekFields.of(this).firstDayOfWeek
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package io.github.boguszpawlowski.composecalendar.kotlinxDateTime

import kotlinx.datetime.DateTimeUnit
import kotlinx.datetime.LocalDate
import kotlinx.datetime.Month
import java.time.Month.DECEMBER
import java.time.Month.JANUARY
import java.time.temporal.ChronoField.YEAR

/**
* Kotlin implementation of `YearMonth` available in java.time, since `KotlinxDateTime` doesn't
* include a substitute for it: https://github.com/Kotlin/kotlinx-datetime/issues/168
*
* For construction use factory methods 'of' provided in companion object
*/
@Suppress("DataClassPrivateConstructor")
public data class YearMonth private constructor(
val year: Int,
val month: Month,
) {

/**
* Increment by one month
*/
public operator fun inc(): YearMonth = when (month.value) {
in 1..11 -> YearMonth(year, month)
else -> YearMonth(year + 1, JANUARY)
}

/**
* Decrement by one month
*/
public operator fun dec(): YearMonth = when (month.value) {
in 2..12 -> YearMonth(year, month)
else -> YearMonth(year - 1, DECEMBER)
}

/**
* Add specified amount of months to current date
*/
public fun plus(value: Int, unit: DateTimeUnit.MonthBased): YearMonth =
plus(value.toLong(), unit)

/**
* Subtract specified amount of months from current date
*/
public fun minus(value: Int, unit: DateTimeUnit.MonthBased): YearMonth =
plus(-value.toLong(), unit)

public fun minus(value: Long, unit: DateTimeUnit.MonthBased): YearMonth =
plus(-value, unit)

public fun plus(value: Long, unit: DateTimeUnit.MonthBased): YearMonth {
val monthsToAdd = value * unit.months
if (monthsToAdd == 0L) {
return this
}
val monthCount = year * 12L + (month.value - 1)
val calcMonths = monthCount + monthsToAdd

val newYear = YEAR.checkValidIntValue(calcMonths.floorDiv(12))
val newMonth = calcMonths.floorMod(12) + 1
return of(newYear, newMonth.toInt())
}

override fun toString(): String = toJavaYearMonth().toString()

public companion object {
public fun of(year: Int, month: Int): YearMonth = YearMonth(year, Month.of(month))

public fun of(year: Int, month: Month): YearMonth = YearMonth(year, month)

public fun parse(value: String): YearMonth =
java.time.YearMonth.parse(value).toKotlinYearMonth()

public fun now(): YearMonth {
val today = LocalDate.now()

return of(today.year, today.month.value)
}
}
}

private fun Long.floorMod(other: Long): Long = when (other) {
0L -> this
else -> this - floorDiv(other) * other
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package io.github.boguszpawlowski.composecalendar.kotlinxDateTime

import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.ShouldSpec
import io.kotest.data.Headers3
import io.kotest.data.Row3
import io.kotest.data.forAll
import io.kotest.data.table
import io.kotest.matchers.shouldBe
import kotlinx.datetime.DateTimeUnit
import java.time.DateTimeException

internal class YearMonthTest : ShouldSpec({

context("Year Month") {
should("overflow a year if adding months") {
val yearMonth = YearMonth.of(2002, 11)
val expectedResult = YearMonth.of(2003, 1)

val result = yearMonth.plus(2, DateTimeUnit.MONTH)

result shouldBe expectedResult
}
should("add years if adding months") {
val yearMonth = YearMonth.of(2002, 11)
val expectedResult = YearMonth.of(2202, 11)

val result = yearMonth.plus(2, DateTimeUnit.CENTURY)

result shouldBe expectedResult
}
should("subtract years if subtracting months") {
val yearMonth = YearMonth.of(2002, 1)
val expectedResult = YearMonth.of(2001, 11)

val result = yearMonth.minus(2, DateTimeUnit.MONTH)

result shouldBe expectedResult
}
should("subtract year if subtracting months") {
val yearMonth = YearMonth.of(2002, 11)
val expectedResult = YearMonth.of(2000, 11)

val result = yearMonth.minus(2, DateTimeUnit.YEAR)

result shouldBe expectedResult
}
should("throw an error if months greater than 12") {
shouldThrow<DateTimeException> {
YearMonth.of(1222, 13)
}
}
should("correctly add months") {
forAll(
table(
Headers3("starting month", "months to add", "expected month"),
Row3(1, 2, 3),
Row3(12, 24, 12),
Row3(11, 2, 1),
Row3(1, 14, 3),
Row3(6, 7, 1),
Row3(10, 20, 6),
)
) { startingMonth: Int, monthsToAdd: Int, expectedMonth: Int ->
val yearMonth = YearMonth.of(2000, startingMonth)

val result = yearMonth.plus(monthsToAdd, DateTimeUnit.MONTH).month.value

result shouldBe expectedMonth
}
}
should("correctly add years") {
forAll(
table(
Headers3("starting month", "months to add", "expected year"),
Row3(1, 2, 2000),
Row3(12, 24, 2002),
Row3(11, 2, 2001),
Row3(1, 14, 2001),
Row3(6, 7, 2001),
Row3(10, 20, 2002),
)
) { startingMonth: Int, monthsToAdd: Int, expectedYear: Int ->
val yearMonth = YearMonth.of(2000, startingMonth)

val result = yearMonth.plus(monthsToAdd, DateTimeUnit.MONTH).year

result shouldBe expectedYear
}
}
}
})
Empty file removed library/consumer-rules.pro
Empty file.
17 changes: 1 addition & 16 deletions library/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
POM_ARTIFACT_ID=composecalendar
POM_NAME=Compose Calendar
POM_PACKAGING=aar

GROUP=io.github.boguszpawlowski.composecalendar
POM_DESCRIPTION=Library for handling the Calendar view in Jetpack Compose.

POM_URL=https://github.com/boguszpawlowski/ComposeCalendar
POM_SCM_URL=https://github.com/boguszpawlowski/ComposeCalendar
POM_SCM_CONNECTION=git@github.com:boguszpawlowski/ComposeCalendar.git
POM_SCM_DEV_CONNECTION=git@github.com:boguszpawlowski/ComposeCalendar.git

POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt

POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=boguszp
POM_DEVELOPER_NAME=Bogusz Pawlowski
POM_PACKAGING=aar
21 changes: 0 additions & 21 deletions library/proguard-rules.pro

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ public class DynamicSelectionState(
}

internal companion object {
@Suppress("FunctionName") // Factory function
@Suppress("FunctionName", "UNCHECKED_CAST") // Factory function
fun Saver(onSelectionChanged: (List<LocalDate>) -> Unit): Saver<DynamicSelectionState, Any> =
listSaver(
save = {
listOf(it.selectionMode, it.selection.map { it.toString() })
save = { raw ->
listOf(raw.selectionMode, raw.selection.map { it.toString() })
},
restore = { restored ->
DynamicSelectionState(
Expand Down
1 change: 1 addition & 0 deletions sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ android {

dependencies {
implementation(project(autoModules.library))
implementation(project(autoModules.kotlinxDatetime))

implementation(Kotlin.StdLib)

Expand Down
Loading

0 comments on commit 0768d84

Please sign in to comment.