Skip to content

Commit 33a7428

Browse files
committed
update README.MD & sample
1 parent 4a6fbef commit 33a7428

File tree

4 files changed

+135
-75
lines changed

4 files changed

+135
-75
lines changed

README.MD

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,20 @@
33
![Maven Central](https://img.shields.io/maven-central/v/io.github.softartdev/kronos)
44
[![Build & Publish CI/CD](https://github.com/softartdev/Kronos-Multiplatform/actions/workflows/build_publish.yml/badge.svg)](https://github.com/softartdev/Kronos-Multiplatform/actions/workflows/build_publish.yml)
55

6-
Kotlin Multiplatform library for network time synchronization.
7-
Extension for [kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) library.
8-
Supported platforms:
6+
Kotlin Multiplatform library for network time synchronization. It is an extension for the [kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) library and supports the following platforms:
97
- Android
108
- iOS
119
- Desktop JVM (MacOS, Linux, Windows)
1210
## Usage
13-
### [kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) extension
14-
Use `Clock.Network.now()` to get the current network time.
15-
This can be used in conjunction with the built-in `Clock.System.now()` method.
11+
### kotlinx-datetime Extension
12+
The library [extends the main `Clock` interface](https://github.com/softartdev/Kronos-Multiplatform/blob/main/kronos/src/commonMain/kotlin/com/softartdev/kronos/ClockExt.kt) of the kotlinx-library. You can use the [Clock.Network](https://github.com/softartdev/Kronos-Multiplatform/blob/main/kronos/src/commonMain/kotlin/com/softartdev/kronos/NetworkClock.kt) class to retrieve the current network time, similar to using the built-in [Clock.System](https://github.com/Kotlin/kotlinx-datetime/blob/master/core/common/src/Clock.kt) instance.
1613
```kotlin
1714
val networkTime: Instant = Clock.Network.now()
1815
val systemTime: Instant = Clock.System.now()
1916
val diff: Duration = networkTime - systemTime
2017
```
2118
### Synchronization
22-
When running the application, it is necessary to synchronize the time with the network using the platform code function:
19+
When running the application, it's necessary to synchronize the time with the network using the platform-specific code:
2320
- Android:
2421
```kotlin
2522
class App : Application() {
@@ -48,13 +45,13 @@ fun main() {
4845
```
4946
### Installation
5047
The latest release is available on [Maven Central](https://repo1.maven.org/maven2/io/github/softartdev/kronos/).
51-
1. Add the Maven Central repository if it is not already there:
48+
1. Add the Maven Central repository if it is not already included:
5249
```kotlin
5350
repositories {
5451
mavenCentral()
5552
}
5653
```
57-
2. In multiplatform projects, add a dependency to the commonMain source set dependencies
54+
2. In multiplatform projects, add the following dependency to the `commonMain` source set dependencies:
5855
```kotlin
5956
commonMain {
6057
dependencies {
@@ -63,10 +60,10 @@ commonMain {
6360
}
6461
```
6562
## Implementation
66-
Main common interface implemented with using:
63+
The main common interface is implemented using the following:
6764
- [lyft/Kronos](https://github.com/lyft/Kronos-Android) for Java & Android
6865
- [MobileNativeFoundation/Kronos](https://github.com/MobileNativeFoundation/Kronos) for iOS
6966

70-
The project is assembled and checked thanks to:
71-
- [Swift Klib Gradle Plugin](https://github.com/ttypic/swift-klib-plugin) including Swift source files in KMM shared module
67+
The project is built and tested using the following:
68+
- [Swift Klib Gradle Plugin](https://github.com/ttypic/swift-klib-plugin) for including Swift source files in KMM shared module
7269
- [Compose Multiplatform, by JetBrains](https://github.com/JetBrains/compose-jb) for UI samples
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<resources>
22
<style name="Theme.Splash" parent="Theme.AppCompat.DayNight.NoActionBar">
3+
<!--
34
<item name="android:windowTranslucentNavigation">true</item>
45
<item name="android:windowTranslucentStatus">true</item>
6+
-->
57
</style>
68
</resources>
Lines changed: 3 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,10 @@
11
package com.softartdev.kronos.sample
22

3-
import androidx.compose.foundation.layout.Arrangement
4-
import androidx.compose.foundation.layout.Column
5-
import androidx.compose.foundation.layout.fillMaxSize
6-
import androidx.compose.material.Button
7-
import androidx.compose.material.CircularProgressIndicator
8-
import androidx.compose.material.Text
9-
import androidx.compose.runtime.*
10-
import androidx.compose.ui.Alignment
11-
import androidx.compose.ui.Modifier
12-
import com.softartdev.kronos.Network
13-
import io.github.aakira.napier.Napier
14-
import kotlinx.coroutines.launch
15-
import kotlinx.datetime.Clock
16-
import kotlin.time.Duration
3+
import androidx.compose.runtime.Composable
174

185
@Composable
196
internal fun App() = AppTheme {
20-
var diffDuration by remember { mutableStateOf(calcDiffDuration()) }
21-
val loadingState: MutableState<Boolean> = remember { mutableStateOf(false) }
22-
val coroutineScope = rememberCoroutineScope()
23-
Column(
24-
modifier = Modifier.fillMaxSize(),
25-
horizontalAlignment = Alignment.CenterHorizontally,
26-
verticalArrangement = Arrangement.SpaceEvenly
27-
) {
28-
Text(text = "Difference duration between system and network time:\n$diffDuration")
29-
Button(onClick = { diffDuration = calcDiffDuration() }) {
30-
Text(text = "Refresh difference duration")
31-
}
32-
Button(onClick = ::clickSync) {
33-
Text(text = "Sync network time async")
34-
}
35-
if (loadingState.value) {
36-
CircularProgressIndicator()
37-
} else {
38-
Button(onClick = {
39-
coroutineScope.launch {
40-
loadingState.value = true
41-
clickAwaitSync()
42-
loadingState.value = false
43-
}
44-
}) {
45-
Text(text = "Sync network time blocking")
46-
}
47-
}
48-
Button(onClick = { openUrl("https://github.com/softartdev/Kronos-Multiplatform") }) {
49-
Text("Open github")
50-
}
51-
Text(text = Greeting().greet())
52-
}
7+
TickScreen()
538
}
549

5510
internal expect fun openUrl(url: String?)
@@ -58,19 +13,4 @@ internal expect fun clickSync()
5813

5914
internal expect fun clickBlockingSync()
6015

61-
internal expect suspend fun clickAwaitSync()
62-
63-
private fun calcDiffDuration(): Duration {
64-
val sysInstant = Clock.System.now()
65-
Napier.d(tag = "⌚️", message = "System time: $sysInstant")
66-
val netInstant = try {
67-
Clock.Network.now()
68-
} catch (exception: IllegalArgumentException) {
69-
Napier.e(tag = "⌚️", message = exception.message ?: "Network time error")
70-
sysInstant
71-
}
72-
Napier.d(tag = "⌚️", message = "Network time: $netInstant")
73-
val diff: Duration = netInstant - sysInstant
74-
Napier.d(tag = "⌚️", message = "Diff: $diff")
75-
return diff
76-
}
16+
internal expect suspend fun clickAwaitSync()
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package com.softartdev.kronos.sample
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.ColumnScope
6+
import androidx.compose.foundation.layout.Row
7+
import androidx.compose.foundation.layout.calculateStartPadding
8+
import androidx.compose.foundation.layout.padding
9+
import androidx.compose.material.Button
10+
import androidx.compose.material.Checkbox
11+
import androidx.compose.material.CircularProgressIndicator
12+
import androidx.compose.material.MaterialTheme.typography
13+
import androidx.compose.material.Scaffold
14+
import androidx.compose.material.Switch
15+
import androidx.compose.material.Text
16+
import androidx.compose.material.TopAppBar
17+
import androidx.compose.runtime.Composable
18+
import androidx.compose.runtime.LaunchedEffect
19+
import androidx.compose.runtime.MutableState
20+
import androidx.compose.runtime.derivedStateOf
21+
import androidx.compose.runtime.getValue
22+
import androidx.compose.runtime.mutableStateOf
23+
import androidx.compose.runtime.remember
24+
import androidx.compose.runtime.rememberCoroutineScope
25+
import androidx.compose.runtime.setValue
26+
import androidx.compose.ui.Alignment
27+
import androidx.compose.ui.Modifier
28+
import androidx.compose.ui.platform.LocalLayoutDirection
29+
import androidx.compose.ui.unit.dp
30+
import com.softartdev.kronos.Network
31+
import io.github.aakira.napier.Napier
32+
import kotlinx.coroutines.delay
33+
import kotlinx.coroutines.launch
34+
import kotlinx.datetime.Clock
35+
import kotlinx.datetime.Instant
36+
import kotlinx.datetime.TimeZone
37+
import kotlinx.datetime.toLocalDateTime
38+
import kotlin.time.Duration
39+
import kotlin.time.Duration.Companion.seconds
40+
41+
@Composable
42+
fun TickScreen() = Scaffold(topBar = {
43+
TopAppBar(title = { Text(text = Greeting().greet()) })
44+
}, content = { paddingValues ->
45+
Column(
46+
modifier = Modifier.padding(
47+
vertical = paddingValues.calculateTopPadding()
48+
.coerceAtLeast(minimumValue = 8.dp),
49+
horizontal = paddingValues.calculateStartPadding(LocalLayoutDirection.current)
50+
.coerceAtLeast(minimumValue = 8.dp),
51+
),
52+
horizontalAlignment = Alignment.Start,
53+
verticalArrangement = Arrangement.spacedBy(16.dp)
54+
) {
55+
var networkTime: Instant? by remember { mutableStateOf(value = clockNetworkNowOrNull()) }
56+
Text(text = "Network time:", style = typography.subtitle2)
57+
Text(text = networkTime.toString(), style = typography.body1)
58+
var systemTime: Instant by remember { mutableStateOf(Clock.System.now()) }
59+
Text(text = "System time:", style = typography.subtitle2)
60+
Text(
61+
text = systemTime.toLocalDateTime(TimeZone.currentSystemDefault()).toString(),
62+
style = typography.body1
63+
)
64+
var diff: Duration? by remember {
65+
mutableStateOf(value = networkTime?.let { it - systemTime })
66+
}
67+
Text(text = "Diff:", style = typography.subtitle2)
68+
Text(text = diff.toString(), style = typography.body1)
69+
var ticking by remember { mutableStateOf(false) }
70+
val synced by remember { derivedStateOf { networkTime != null } }
71+
Row(
72+
verticalAlignment = Alignment.CenterVertically,
73+
horizontalArrangement = Arrangement.spacedBy(8.dp)
74+
) {
75+
Text(text = "Ticking: ", style = typography.subtitle1)
76+
Switch(checked = ticking, onCheckedChange = { ticking = it })
77+
Text(text = "Synced: ", style = typography.subtitle1)
78+
Checkbox(checked = synced, onCheckedChange = null, enabled = false)
79+
}
80+
fun tick() {
81+
systemTime = Clock.System.now()
82+
networkTime = clockNetworkNowOrNull()
83+
diff = networkTime?.let { it - systemTime }
84+
Napier.d(tag = "", message = "Ticking Diff: $diff")
85+
}
86+
if (ticking) {
87+
LaunchedEffect(key1 = "tick") {
88+
while (ticking) {
89+
tick()
90+
delay(1.seconds)
91+
}
92+
}
93+
}
94+
val loadingState: MutableState<Boolean> = remember { mutableStateOf(false) }
95+
val coroutineScope = rememberCoroutineScope()
96+
if (loadingState.value) {
97+
CircularProgressIndicator()
98+
} else {
99+
Button(onClick = {
100+
coroutineScope.launch {
101+
loadingState.value = true
102+
clickAwaitSync()
103+
tick()
104+
loadingState.value = false
105+
}
106+
}) {
107+
Text(text = "Sync network time")
108+
}
109+
}
110+
Button(onClick = { openUrl("https://github.com/softartdev/Kronos-Multiplatform") }) {
111+
Text("Open github")
112+
}
113+
}
114+
})
115+
116+
private fun clockNetworkNowOrNull(): Instant? = try {
117+
Clock.Network.now()
118+
} catch (e: Exception) {
119+
Napier.e(tag = "", throwable = e, message = "Network time error")
120+
null
121+
}

0 commit comments

Comments
 (0)