Skip to content

Commit 1813bfa

Browse files
authored
Merge pull request #92 from hoc081098/renovate/deps.compose.androidxcomposecompilerversion
Compose to v1.5.6, kotlin to v1.9.21, remove kswift, use SKIE and more...
2 parents 71773b3 + 4b038b3 commit 1813bfa

File tree

109 files changed

+1424
-1242
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+1424
-1242
lines changed

.editorconfig

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
1-
root = true
1+
root=true
22
[*]
33
indent_size=2
44
end_of_line=lf
55
charset=utf-8
66
trim_trailing_whitespace=true
77
insert_final_newline=true
8-
[*.{kt, kts}]
8+
[*.{kt,kts}]
99
ij_kotlin_imports_layout=*
10-
disabled_rules=filename
10+
ij_continuation_indent_size=4
11+
ij_kotlin_allow_trailing_comma_on_call_site=true
12+
ij_kotlin_allow_trailing_comma=true
13+
ktlint_standard_filename=disabled
14+
ktlint_standard_package-name=disabled
15+
ktlint_standard_property-naming=disabled
16+
ktlint_standard_function-naming=disabled
17+
filename=disabled
18+
ktlint_experimental=enabled
19+
ktlint_code_style=android_studio
20+
max_line_length=120
21+
[*.kts]
22+
max_line_length=300
23+
ktlint_standard_multiline-expression-wrapping=disabled
24+
ktlint_standard_function-signature=disabled
1125
[*.xml]
1226
indent_size=4

.github/workflows/ios-build.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,7 @@ jobs:
6868
${{ runner.os }}-konan-
6969
7070
- name: Gen pod
71-
run: ./gradlew :shared:podGenIOS --parallel
72-
73-
- name: Gen KSwift
74-
run: ./gradlew kSwiftsharedPodspec
71+
run: ./gradlew :shared:podGenIOS :shared:generateDummyFramework --parallel --stacktrace
7572

7673
- name: Install Pod
7774
run: pod install

README.md

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Github Repos Search - Kotlin Multiplatform Mobile using Jetpack Compose, SwiftUI
77
[![iOS Build CI](https://github.com/hoc081098/GithubSearchKMM/actions/workflows/ios-build.yml/badge.svg)](https://github.com/hoc081098/GithubSearchKMM/actions/workflows/ios-build.yml)
88
[![Validate Gradle Wrapper](https://github.com/hoc081098/GithubSearchKMM/actions/workflows/gradle-wrapper-validation.yml/badge.svg)](https://github.com/hoc081098/GithubSearchKMM/actions/workflows/gradle-wrapper-validation.yml)
99
[![API](https://img.shields.io/badge/API-23%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=23)
10-
[![Kotlin](https://img.shields.io/badge/kotlin-1.9.10-blue.svg?logo=kotlin)](http://kotlinlang.org)
10+
[![Kotlin](https://img.shields.io/badge/kotlin-1.9.21-blue.svg?logo=kotlin)](http://kotlinlang.org)
1111
[![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fhoc081098%2FGithubSearchKMM&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false)](https://hits.seeyoufarm.com)
1212
[![License: MIT](https://img.shields.io/badge/License-MIT-purple.svg)](https://opensource.org/licenses/MIT)
1313
[![codecov](https://codecov.io/gh/hoc081098/GithubSearchKMM/branch/master/graph/badge.svg?token=qzSAFkj09P)](https://codecov.io/gh/hoc081098/GithubSearchKMM)
@@ -35,7 +35,7 @@ Liked some of my work? Buy me a coffee (or more likely a beer)
3535
## Tech Stacks
3636
- Functional & Reactive programming with **Kotlin Coroutines with Flow**
3737
- **Clean Architecture** with **MVI** (Uni-directional data flow)
38-
- [**Multiplatform ViewModel and SavedStateHandle**](https://github.com/hoc081098/kmp-viewmodel) (save and restore states across process death), by @hoc081098
38+
- [**Multiplatform ViewModel and SavedStateHandle**](https://github.com/hoc081098/kmp-viewmodel) (save and restore states across process death), by [@hoc081098](https://github.com/hoc081098)
3939
- **Multiplatform FlowRedux** State Management
4040
- [**Λrrow** - Functional companion to Kotlin's Standard Library](https://arrow-kt.io/)
4141
- [Either](https://arrow-kt.io/docs/apidocs/arrow-core/arrow.core/-either/)
@@ -51,8 +51,8 @@ Liked some of my work? Buy me a coffee (or more likely a beer)
5151
- [Ktor client library](https://ktor.io/docs/getting-started-ktor-client-multiplatform-mobile.html) for networking
5252
- [Kotlinx Serialization](https://github.com/Kotlin/kotlinx.serialization) for JSON serialization/deserialization.
5353
- [Napier](https://github.com/AAkira/Napier) for Multiplatform Logging.
54-
- [FlowExt](https://github.com/hoc081098/FlowExt) provides many kotlinx.coroutines.Flow operators, by @hoc081098.
55-
- [MOKO KSwift](https://github.com/icerockdev/moko-kswift) is a gradle plugin for generation Swift-friendly API for Kotlin/Native framework.
54+
- [FlowExt](https://github.com/hoc081098/FlowExt) provides many kotlinx.coroutines.Flow operators, by [@hoc081098](https://github.com/hoc081098)
55+
- [Touchlab SKIE](https://skie.touchlab.co/) a Swift-friendly API Generator for Kotlin Multiplatform.
5656
- [kotlinx.collections.immutable](https://github.com/Kotlin/kotlinx.collections.immutable): immutable collection interfaces and implementation prototypes for Kotlin..
5757
- Testing
5858
- [Kotlin Test](https://kotlinlang.org/docs/multiplatform-run-tests.html) for running tests with Kotlin Multiplatform.
@@ -193,7 +193,6 @@ Conform to `ObservableObject` and use `@Published` property wrapper.
193193
import Foundation
194194
import Combine
195195
import shared
196-
import sharedSwift
197196

198197
@MainActor
199198
class IOSGithubSearchViewModel: ObservableObject {
@@ -243,8 +242,8 @@ class IOSGithubSearchViewModel: ObservableObject {
243242

244243
# Building & Develop
245244

246-
- `Android Studio Giraffe | 2022.3.1` (note: **Java 17 is now the minimum version required**).
247-
- `Xcode 13.2` or later (due to use of new Swift 5.5 concurrency APIs).
245+
- `Android Studio Hedgehog | 2023.1.1` (note: **Java 17 is now the minimum version required**).
246+
- `Xcode 13.2.1` or later (due to use of new Swift 5.5 concurrency APIs).
248247
- Clone project: `git clone https://github.com/hoc081098/GithubSearchKMM.git`
249248
- Android: open project by `Android Studio` and run as usual.
250249
- iOS
@@ -261,34 +260,22 @@ class IOSGithubSearchViewModel: ObservableObject {
261260
<br>
262261
<kbd>Cmd</kbd> + <kbd>R</kbd> to run.
263262

264-
When you see any error like this:
265-
```
266-
./GithubSearchKMM/iosApp/iosApp/ContentView.swift:4:8: No such module 'sharedSwift'
267-
```
268-
You can run the following commands (must select `Read from disk` inside Xcode):
269-
```shell
270-
# go to iosApp directory
271-
cd iosApp
272-
273-
# install pods
274-
pod install
275-
```
276-
Then, you can build and run inside Xcode as usual.
263+
You can also build and run iOS app from Xcode as usual.
277264

278265
# LOC
279266

280267
```shell
281268
--------------------------------------------------------------------------------
282269
Language Files Lines Blank Comment Code
283270
--------------------------------------------------------------------------------
284-
Kotlin 106 7789 963 417 6409
271+
Kotlin 116 7942 996 453 6493
285272
JSON 7 3938 0 0 3938
286-
Swift 16 903 118 102 683
287-
Markdown 1 294 54 0 240
288-
Bourne Shell 2 250 28 116 106
273+
Swift 16 960 124 102 734
274+
Markdown 1 281 53 0 228
275+
Bourne Shell 2 249 28 116 105
289276
Batch 1 92 21 0 71
290277
XML 6 69 6 0 63
291278
--------------------------------------------------------------------------------
292-
Total 139 13335 1190 635 11510
279+
Total 149 13531 1228 671 11632
293280
--------------------------------------------------------------------------------
294281
```

androidApp/build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ android {
6161
"-opt-in=kotlinx.coroutines.FlowPreview",
6262
"-opt-in=kotlin.Experimental",
6363
// Enable experimental kotlinx serialization APIs
64-
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi"
64+
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
6565
)
6666
}
6767

@@ -133,7 +133,7 @@ fun Project.buildComposeMetricsParameters(): List<String> {
133133
val metricsFolder = File(project.buildDir, "compose-metrics")
134134
metricParameters.add("-P")
135135
metricParameters.add(
136-
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + metricsFolder.absolutePath
136+
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + metricsFolder.absolutePath,
137137
)
138138
}
139139

@@ -143,7 +143,7 @@ fun Project.buildComposeMetricsParameters(): List<String> {
143143
val reportsFolder = File(project.buildDir, "compose-reports")
144144
metricParameters.add("-P")
145145
metricParameters.add(
146-
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + reportsFolder.absolutePath
146+
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + reportsFolder.absolutePath,
147147
)
148148
}
149149
return metricParameters.toList()
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package com.hoc081098.github_search_kmm.android.compose_utils
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.Immutable
5+
import androidx.compose.runtime.LaunchedEffect
6+
import androidx.compose.runtime.NonRestartableComposable
7+
import androidx.compose.runtime.RememberObserver
8+
import androidx.compose.runtime.remember
9+
import androidx.compose.runtime.rememberUpdatedState
10+
import androidx.compose.ui.platform.LocalLifecycleOwner
11+
import androidx.lifecycle.Lifecycle
12+
import androidx.lifecycle.LifecycleOwner
13+
import androidx.lifecycle.repeatOnLifecycle
14+
import kotlinx.coroutines.CoroutineDispatcher
15+
import kotlinx.coroutines.CoroutineScope
16+
import kotlinx.coroutines.Dispatchers
17+
import kotlinx.coroutines.Job
18+
import kotlinx.coroutines.cancel
19+
import kotlinx.coroutines.flow.Flow
20+
import kotlinx.coroutines.launch
21+
22+
@Immutable
23+
enum class CollectWithLifecycleEffectDispatcher {
24+
/**
25+
* Use [Dispatchers.Main][kotlinx.coroutines.MainCoroutineDispatcher].
26+
*/
27+
Main,
28+
29+
/**
30+
* Use [Dispatchers.Main.immediate][kotlinx.coroutines.MainCoroutineDispatcher.immediate].
31+
*/
32+
ImmediateMain,
33+
34+
/**
35+
* Use [androidx.compose.runtime.Composer.applyCoroutineContext].
36+
* Under the hood, it uses Compose [androidx.compose.ui.platform.AndroidUiDispatcher].
37+
*/
38+
Composer,
39+
}
40+
41+
/**
42+
* Collect the given [Flow] in an effect that runs when [LifecycleOwner.lifecycle] is at least at [minActiveState].
43+
*
44+
* - If [dispatcher] is [CollectWithLifecycleEffectDispatcher.ImmediateMain], the effect will run in
45+
* [Dispatchers.Main.immediate][kotlinx.coroutines.MainCoroutineDispatcher.immediate].
46+
* - If [dispatcher] is [CollectWithLifecycleEffectDispatcher.Main], the effect will run in
47+
* [Dispatchers.Main][kotlinx.coroutines.MainCoroutineDispatcher].
48+
* - If [dispatcher] is [CollectWithLifecycleEffectDispatcher.Composer], the effect will run in
49+
* [androidx.compose.runtime.Composer.applyCoroutineContext].
50+
*
51+
* NOTE: When [dispatcher] or [collector] changes, the effect will **NOT** be restarted.
52+
* The latest [collector] will be used to receive values from the [Flow] ([rememberUpdatedState] is used).
53+
* If you want to restart the effect, you need to change [keys].
54+
*
55+
* @param keys Keys to be used to [remember] the effect.
56+
* @param lifecycleOwner The [LifecycleOwner] to be used to [repeatOnLifecycle].
57+
* @param minActiveState The minimum [Lifecycle.State] to be used to [repeatOnLifecycle].
58+
* @param dispatcher The dispatcher to be used to launch the [Flow].
59+
* @param collector The collector to be used to collect the [Flow].
60+
*
61+
* @see [LaunchedEffect]
62+
* @see [CollectWithLifecycleEffectDispatcher]
63+
*/
64+
@Composable
65+
fun <T> Flow<T>.CollectWithLifecycleEffect(
66+
vararg keys: Any?,
67+
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
68+
minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
69+
dispatcher: CollectWithLifecycleEffectDispatcher = CollectWithLifecycleEffectDispatcher.ImmediateMain,
70+
collector: (T) -> Unit,
71+
) {
72+
val flow = this
73+
val collectorState = rememberUpdatedState(collector)
74+
75+
val block: suspend CoroutineScope.() -> Unit = {
76+
lifecycleOwner.repeatOnLifecycle(minActiveState) {
77+
// NOTE: we don't use `flow.collect(collectState.value)` because it can use the old value
78+
flow.collect { collectorState.value(it) }
79+
}
80+
}
81+
82+
when (dispatcher) {
83+
CollectWithLifecycleEffectDispatcher.ImmediateMain -> {
84+
LaunchedEffectInImmediateMain(flow, lifecycleOwner, minActiveState, *keys, block = block)
85+
}
86+
87+
CollectWithLifecycleEffectDispatcher.Main -> {
88+
LaunchedEffectInMain(flow, lifecycleOwner, minActiveState, *keys, block = block)
89+
}
90+
91+
CollectWithLifecycleEffectDispatcher.Composer -> {
92+
LaunchedEffect(flow, lifecycleOwner, minActiveState, *keys, block = block)
93+
}
94+
}
95+
}
96+
97+
@Composable
98+
@NonRestartableComposable
99+
@Suppress("ArrayReturn")
100+
private fun LaunchedEffectInImmediateMain(vararg keys: Any?, block: suspend CoroutineScope.() -> Unit) {
101+
remember(*keys) { LaunchedEffectImpl(block, Dispatchers.Main.immediate) }
102+
}
103+
104+
@Composable
105+
@NonRestartableComposable
106+
@Suppress("ArrayReturn")
107+
private fun LaunchedEffectInMain(vararg keys: Any?, block: suspend CoroutineScope.() -> Unit) {
108+
remember(*keys) { LaunchedEffectImpl(block, Dispatchers.Main) }
109+
}
110+
111+
private class LaunchedEffectImpl(
112+
private val task: suspend CoroutineScope.() -> Unit,
113+
dispatcher: CoroutineDispatcher,
114+
) : RememberObserver {
115+
private val scope = CoroutineScope(dispatcher)
116+
private var job: Job? = null
117+
118+
override fun onRemembered() {
119+
job?.cancel("Old job was still running!")
120+
job = scope.launch(block = task)
121+
}
122+
123+
override fun onForgotten() {
124+
job?.cancel()
125+
job = null
126+
}
127+
128+
override fun onAbandoned() {
129+
job?.cancel()
130+
job = null
131+
}
132+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
package com.hoc081098.github_search_kmm.android.compose_utils
22

3+
import androidx.compose.runtime.Composable
34
import androidx.compose.runtime.Stable
5+
import androidx.compose.runtime.remember
6+
import kotlin.reflect.KProperty
47

58
@Stable
69
@JvmInline
710
value class StableWrapper<T>(val value: T)
11+
12+
@Stable
13+
@Suppress("NOTHING_TO_INLINE")
14+
inline operator fun <T> StableWrapper<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
15+
16+
@Suppress("NOTHING_TO_INLINE")
17+
@Composable
18+
inline fun <T> rememberStableWrapperOf(value: T): StableWrapper<T> = remember(value) { StableWrapper(value) }

androidApp/src/main/java/com/hoc081098/github_search_kmm/android/compose_utils/rememberFlowWithLifecycle.kt

Lines changed: 0 additions & 84 deletions
This file was deleted.

0 commit comments

Comments
 (0)