Skip to content

Commit 2aaf4f7

Browse files
committed
update readme & deps, fix lib & sample
1 parent 44d087a commit 2aaf4f7

7 files changed

Lines changed: 88 additions & 37 deletions

File tree

README.MD

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,56 @@
11
# Kronos Multiplatform Library
2+
Development in progress 🛠
23

3-
Development in progress
4+
Kotlin Multiplatform library for time synchronization.
5+
Extension for [kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) library.
6+
Supported platforms:
7+
- Android
8+
- iOS
9+
- Desktop JVM (MacOS, Linux, Windows)
10+
## Usage
11+
### [kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) extension
12+
Use `Clock.Network.now()` to get the current network time.
13+
This can be used in conjunction with the built-in `Clock.System.now()` method.
14+
```kotlin
15+
val networkTime: Instant = Clock.Network.now()
16+
val systemTime: Instant = Clock.System.now()
17+
val diff: Duration = networkTime - systemTime
18+
```
19+
### Synchronization
20+
When running the application, it is necessary to synchronize the time with the network using the platform code function:
21+
```kotlin
22+
Clock.Network.sync()
23+
```
24+
For example, on Android:
25+
```kotlin
26+
class App : Application() {
27+
override fun onCreate() {
28+
super.onCreate()
29+
Clock.Network.sync(applicationContext)
30+
}
31+
}
32+
```
33+
### Installation
34+
The latest release is available on [Maven Central](https://repo1.maven.org/maven2/io/github/softartdev/kronos/).
35+
1. Add the Maven Central repository if it is not already there:
36+
```kotlin
37+
repositories {
38+
mavenCentral()
39+
}
40+
```
41+
2. In multiplatform projects, add a dependency to the commonMain source set dependencies
42+
```kotlin
43+
commonMain {
44+
dependencies {
45+
implementation("io.github.softartdev:kronos:$latestVersion")
46+
}
47+
}
48+
```
49+
## Implementation
50+
Main common interface implemented with using:
51+
- [lyft/Kronos](https://github.com/lyft/Kronos-Android) for Java & Android
52+
- [MobileNativeFoundation/Kronos](https://github.com/MobileNativeFoundation/Kronos) for iOS
453

5-
## Before running!
6-
- check your system with (KDoctor)[https://github.com/Kotlin/kdoctor]
7-
- add `local.properties` file to the project root and set a path to Android SDK there
8-
- run `./gradlew podInstall` in the project root
9-
10-
### Android
11-
To run the application on android device/emulator:
12-
- open project in Android Studio and run imported android run configuration
13-
14-
To build the application bundle:
15-
- run `./gradlew :composeApp:assembleDebug`
16-
- find `.apk` file in `composeApp/build/outputs/apk/debug/composeApp-debug.apk`
17-
18-
### Desktop
19-
Run the desktop application: `./gradlew :composeApp:run`
20-
21-
### iOS
22-
To run the application on iPhone device/simulator:
23-
- Open `iosApp/iosApp.xcworkspace` in Xcode and run standard configuration
24-
- Or use (Kotlin Multiplatform Mobile plugin)[https://plugins.jetbrains.com/plugin/14936-kotlin-multiplatform-mobile] for Android Studio
54+
The project is assembled and checked thanks to:
55+
- [Swift Klib Gradle Plugin](https://github.com/ttypic/swift-klib-plugin) including Swift source files in KMM shared module
56+
- [Compose Multiplatform, by JetBrains](https://github.com/JetBrains/compose-jb) for UI samples

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
lyft-kronos = "0.0.1-alpha11"
44
kotlin = "1.8.20"
55
agp = "7.4.2"
6-
compose = "1.4.0-rc03"
6+
compose = "1.4.0"
77
androidx-appcompat = "1.6.1"
88
androidx-activityCompose = "1.7.0"
99
androidx-test = "1.5.0"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-all.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

kronos/src/commonMain/kotlin/com/softartdev/kronos/NetworkClock.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,9 @@ interface NetworkClock : Clock {
1212
/**
1313
* Returns the [Instant] corresponding to the current time, according to this clock.
1414
*/
15-
override fun now(): Instant = getCurrentNtpTimeMs()!!.let(Instant::fromEpochMilliseconds)
15+
override fun now(): Instant {
16+
val currentNtpTimeMs = getCurrentNtpTimeMs()
17+
requireNotNull(currentNtpTimeMs) { "No ntp sync has occurred" }
18+
return Instant.fromEpochMilliseconds(currentNtpTimeMs)
19+
}
1620
}

kronos/src/iosMain/kotlin/com/softartdev/kronos/IosNetworkClock.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ object IosNetworkClock : NetworkClock {
2323
}
2424

2525
override fun getCurrentNtpTimeMs(): Long? {
26-
val nsDate: NSDate? = Kronos.now()
27-
return nsDate?.timeIntervalSince1970?.toLong()
26+
val nsDate: NSDate = Kronos.now() ?: return null
27+
return nsDate.timeIntervalSince1970.toLong() * 1000
2828
}
2929
}

kronos/src/iosTest/kotlin/com/softartdev/kronos/PlatformTest.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,18 @@ class PlatformTest {
1919
}
2020
assertNotNull(Clock.Network.getCurrentNtpTimeMs())
2121
}
22+
23+
@Ignore
24+
@Test
25+
fun awaitSyncTest() = runTest {
26+
val currentNtpTimeMs = Clock.Network.getCurrentNtpTimeMs()
27+
println("⏺️ before sync: $currentNtpTimeMs")
28+
assertNull(currentNtpTimeMs)
29+
30+
Clock.Network.awaitSync()
31+
32+
val instance = Clock.Network.now()
33+
println("⏺️ after sync: $instance")
34+
assertNotNull(instance)
35+
}
2236
}

sampleApp/src/commonMain/kotlin/com/softartdev/kronos/sample/App.kt

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,21 @@ import com.softartdev.kronos.Network
1313
import io.github.aakira.napier.Napier
1414
import kotlinx.coroutines.launch
1515
import kotlinx.datetime.Clock
16+
import kotlin.time.Duration
1617

1718
@Composable
1819
internal fun App() = AppTheme {
19-
var ntpTimeMs by remember { mutableStateOf(Clock.Network.getCurrentNtpTimeMs()) }
20+
var diffDuration by remember { mutableStateOf(calcDiffDuration()) }
2021
val loadingState: MutableState<Boolean> = remember { mutableStateOf(false) }
2122
val coroutineScope = rememberCoroutineScope()
2223
Column(
2324
modifier = Modifier.fillMaxSize(),
2425
horizontalAlignment = Alignment.CenterHorizontally,
2526
verticalArrangement = Arrangement.SpaceEvenly
2627
) {
27-
Text(text = "Network time millis: $ntpTimeMs")
28-
Button(onClick = { ntpTimeMs = logNtpTimeMs() }) {
29-
Text(text = "Refresh network time millis")
28+
Text(text = "Difference duration between system and network time:\n$diffDuration")
29+
Button(onClick = { diffDuration = calcDiffDuration() }) {
30+
Text(text = "Refresh difference duration")
3031
}
3132
Button(onClick = ::clickSync) {
3233
Text(text = "Sync network time async")
@@ -59,12 +60,12 @@ internal expect fun clickBlockingSync()
5960

6061
internal expect suspend fun clickAwaitSync()
6162

62-
private fun logNtpTimeMs(): Long? {
63-
val networkTimeMs = Clock.Network.getCurrentNtpTimeMs()
64-
Napier.d(tag = "⌚️", message = "Network time millis: $networkTimeMs")
65-
val systemTimeMs = Clock.System.now().toEpochMilliseconds()
66-
Napier.d(tag = "⌚️", message = "System time millis: $systemTimeMs")
67-
val diff = networkTimeMs?.minus(systemTimeMs)
63+
private fun calcDiffDuration(): Duration {
64+
val sysInstant = Clock.System.now()
65+
Napier.d(tag = "⌚️", message = "System time: $sysInstant")
66+
val netInstant = Clock.Network.now()
67+
Napier.d(tag = "⌚️", message = "Network time: $netInstant")
68+
val diff: Duration = netInstant - sysInstant
6869
Napier.d(tag = "⌚️", message = "Diff: $diff")
69-
return networkTimeMs
70+
return diff
7071
}

0 commit comments

Comments
 (0)