From b00289f33b4eb7b4a353f5a89c795fca9c5bf19d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petrus=20Nguy=E1=BB=85n=20Th=C3=A1i=20H=E1=BB=8Dc?= Date: Wed, 7 Feb 2024 18:02:20 +0700 Subject: [PATCH] prepare for release: dokka, license, targets, detekt (#28) * lifecycle: supports targets tvosX64() tvosSimulatorArm64() tvosArm64() watchosArm32() watchosArm64() watchosX64() watchosSimulatorArm64() * lifecycle: supports targets tvosX64() tvosSimulatorArm64() tvosArm64() watchosArm32() watchosArm64() watchosX64() watchosSimulatorArm64() * lifecycle: supports targets tvosX64() tvosSimulatorArm64() tvosArm64() watchosArm32() watchosArm64() watchosX64() watchosSimulatorArm64() * add rememberCloseableOnRoute * add rememberCloseableOnRoute * add rememberCloseableOnRoute * replace DestinationId with StackEntryId * fix dokka * org.gradle.jvmargs=-Xmx8g * POM_INCEPTION_YEAR=2024 * fully qualified import for WeakReference https://github.com/Kotlin/dokka/issues/3403 * fix dokka * dokka: suppress all internal packages * dokka: suppress all internal packages * LifecycleControllerEffect to non-internal pkg * externalDocumentationLink { url = URL("https://hoc081098.github.io/kmp-viewmodel/docs/0.x/API/") packageListUrl = URL("https://hoc081098.github.io/kmp-viewmodel/docs/0.x/API/package-list") } * fix dokka * LifecycleDestroyedException * LifecycleDestroyedException * license * license * docs * org.gradle.jvmargs=-Xmx4g * update CI * dokka * InternalNavigationApi * InternalNavigationApi * InternalNavigationApi * dump * dump * detekt * detekt * update ci [skip ci] * TODO: Issue https://github.com/Kotlin/dokka/issues/3368 and https://github.com/Kotlin/dokka/issues/2037 * changelog [skip ci] --- .github/workflows/build.yml | 58 +++++- .github/workflows/publish-release.yml | 2 +- CHANGELOG.md | 14 +- README.md | 1 + detekt.yml | 65 +++---- docs/multiplatform.md | 5 +- gradle.properties | 2 +- .../api/android/khonshu-navigation-core.api | 34 +++- .../api/jvm/khonshu-navigation-core.api | 34 +++- khonshu-navigation-core/build.gradle.kts | 22 ++- .../internal/DestinationId.android.kt | 16 ++ .../internal/OnBackPressedCallback.android.kt | 16 ++ .../OnBackPressedDispatcherOwner.android.kt | 17 ++ .../internal/VisibleForTesting.android.kt | 16 ++ .../navigation/Serializable.commonJvm.kt | 16 ++ .../internal/trySendBlocking.commonJvm.kt | 16 ++ .../solivagant/navigation/EXTRA_ROUTE.kt | 17 +- .../navigation/InternalNavigationApi.kt | 26 +++ .../solivagant/navigation/NavDestination.kt | 17 +- .../navigation/NavEventNavigator.kt | 17 +- .../solivagant/navigation/NavRoute.kt | 16 ++ .../solivagant/navigation/NavigationSetup.kt | 28 ++- .../solivagant/navigation/ResultOwner.kt | 17 +- .../solivagant/navigation/Serializable.kt | 16 ++ .../DelegatingOnBackPressedCallback.kt | 16 ++ .../navigation/internal/DestinationId.kt | 33 ++++ .../internal/InternalNavigationApi.kt | 9 - .../navigation/internal/NavEvent.kt | 17 ++ .../navigation/internal/NavEventCollector.kt | 17 ++ .../navigation/internal/NavigationExecutor.kt | 89 +++++++++- .../internal/NavigationExecutorStore.kt | 17 ++ .../internal/OnBackPressedCallback.kt | 18 ++ .../internal/OnBackPressedDispatcherOwner.kt | 17 ++ .../navigation/internal/VisibleForTesting.kt | 16 ++ .../navigation/internal/trySendBlocking.kt | 16 ++ .../solivagant/navigation/requireRoute.kt | 17 +- .../navigation/internal/trySendBlocking.js.kt | 16 ++ .../internal/trySendBlocking.native.kt | 16 ++ .../internal/DestinationId.nonAndroid.kt | 16 ++ .../OnBackPressedCallback.nonAndroid.kt | 16 ++ ...OnBackPressedDispatcherOwner.nonAndroid.kt | 17 ++ .../internal/VisibleForTesting.nonAndroid.kt | 16 ++ .../navigation/Serializable.nonJvm.kt | 16 ++ lifecycle/build.gradle.kts | 21 ++- .../hoc081098/solivagant/lifecycle/android.kt | 16 ++ .../solivagant/lifecycle/internal/mapState.kt | 16 ++ .../internal/AtomicReference.commonJvm.kt | 20 ++- .../solivagant/lifecycle/Lifecycle.kt | 16 ++ .../solivagant/lifecycle/LifecycleOwner.kt | 16 ++ .../lifecycle/LifecycleOwnerRegistry.kt | 16 ++ .../lifecycle/LocalLifecycleOwner.kt | 15 ++ .../compose/collectAsStateWithLifecycle.kt | 16 ++ .../lifecycle/compose/currentStateAsState.kt | 16 ++ .../lifecycle/compose/lifecycleEffects.kt | 16 ++ .../lifecycle/internal/AtomicReference.kt | 15 ++ .../solivagant/lifecycle/repeatOnLifecycle.kt | 16 ++ .../lifecycle/withLifecycleState.kt | 16 ++ .../lifecycle/internal/AtomicReference.js.kt | 16 ++ .../internal/AtomicReference.native.kt | 16 ++ navigation/api/android/navigation.api | 4 + navigation/api/jvm/navigation.api | 12 +- navigation/build.gradle.kts | 28 ++- .../StackEntryViewModelStoreOwner.android.kt | 16 ++ .../rememberPlatformLifecycleOwner.android.kt | 16 ++ .../savedStateHandleAndroidSupport.android.kt | 16 ++ .../internal/WeakReference.commonJvm.kt | 16 ++ .../solivagant/navigation/NavHost.kt | 34 +++- .../navigation/internal/MultiStack.kt | 95 ++++++++-- .../internal/MultiStackNavigationExecutor.kt | 73 ++++++-- .../MultiStackNavigationExecutorBuilder.kt | 32 ++++ .../solivagant/navigation/internal/Stack.kt | 51 +++++- .../navigation/internal/StackEntry.kt | 40 ++++- .../internal/StackEntryLifecycleOwner.kt | 17 ++ .../internal/StackEntryViewModelStoreOwner.kt | 16 ++ .../navigation/internal/StoreViewModel.kt | 46 ++++- .../navigation/internal/WeakReference.kt | 16 ++ .../rememberPlatformLifecycleOwner.kt | 16 ++ .../savedStateHandleAndroidSupport.kt | 16 ++ .../navigation/rememberCloseableOnRoute.kt | 63 +++++++ .../navigation/AppLifecycleOwner.kt | 7 - .../navigation/AppLifecycleOwner.kt | 23 +++ ...memberPlatformLifecycleOwner.iosAndTvOs.kt | 17 ++ .../navigation/internal/WeakReference.js.kt | 17 ++ .../rememberPlatformLifecycleOwner.js.kt | 23 ++- .../navigation/LifecycleControllerEffect.kt | 162 +++++++++++++++++ .../rememberPlatformLifecycleOwner.jvm.kt | 165 ++---------------- .../rememberPlatformLifecycleOwner.macos.kt | 16 ++ .../internal/WeakReference.native.kt | 16 ++ .../navigation/SavedStateSupport.kt | 16 ++ ...tackEntryViewModelStoreOwner.nonAndroid.kt | 16 ++ ...vedStateHandleAndroidSupport.nonAndroid.kt | 16 ++ .../com/hoc081098/solivagant/sample/main.kt | 2 +- .../sample/products/ProductsScreen.kt | 95 ++++++---- .../search_products/SearchProductsScreen.kt | 51 +++--- .../solivagant/sample/simple/main.kt | 2 +- .../simple/ui/home/profile/ProfileTab.kt | 5 +- .../sample/simple/ui/login/LoginScreen.kt | 21 +++ .../simple/ui/login/LoginScreenRoute.kt | 2 +- scripts/update_docs_url.sh | 2 +- 99 files changed, 2068 insertions(+), 375 deletions(-) create mode 100644 khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/InternalNavigationApi.kt delete mode 100644 khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/InternalNavigationApi.kt create mode 100644 navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/rememberCloseableOnRoute.kt delete mode 100644 navigation/src/iosAndTvOs/kotlin/com/hoc081098/solivagant/navigation/AppLifecycleOwner.kt create mode 100644 navigation/src/iosAndTvOsMain/kotlin/com/hoc081098/solivagant/navigation/AppLifecycleOwner.kt rename navigation/src/{iosAndTvOs => iosAndTvOsMain}/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.iosAndTvOs.kt (92%) create mode 100644 navigation/src/jvmMain/kotlin/com/hoc081098/solivagant/navigation/LifecycleControllerEffect.kt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 22760ddd..6a807dcc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,7 +64,7 @@ jobs: run: chmod +x ./gradlew - name: Build - run: ./gradlew :lifecycle:assemble :khonshu-navigation-core:assemble :navigation:assemble --stacktrace + run: ./gradlew :lifecycle:build :khonshu-navigation-core:build :navigation:build --stacktrace - name: Kover Xml Report run: ./gradlew :koverXmlReport @@ -79,15 +79,63 @@ jobs: name: test-report path: build/reports/tests/allTests/ + checks: + name: Checks (spotless, detekt and binary-compatibility-validator) + strategy: + matrix: + os: [ macos-11 ] + runs-on: ${{ matrix.os }} + timeout-minutes: 45 + if: ${{ github.repository == 'hoc081098/solivagant' }} + steps: + - uses: actions/checkout@v3 + + - name: Set up JDK + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: '17' + + - name: Cache gradle, wrapper and buildSrc + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ matrix.os }}-gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}-${{ hashFiles('**/buildSrc/**/*.kt') }} + restore-keys: | + ${{ matrix.os }}-gradle- + - name: Cache konan + uses: actions/cache@v3 + with: + path: | + ~/.konan/cache + ~/.konan/dependencies + ~/.konan/kotlin-native-macos* + ~/.konan/kotlin-native-mingw* + ~/.konan/kotlin-native-windows* + ~/.konan/kotlin-native-linux* + ~/.konan/kotlin-native-prebuilt-macos* + ~/.konan/kotlin-native-prebuilt-mingw* + ~/.konan/kotlin-native-prebuilt-windows* + ~/.konan/kotlin-native-prebuilt-linux* + key: ${{ matrix.os }}-konan-${{ hashFiles('**/*.gradle*') }} + restore-keys: | + ${{ matrix.os }}-konan- + - name: Make gradlew executable + run: chmod +x ./gradlew + + - name: spotlessCheck, detekt and apiCheck + run: ./gradlew spotlessCheck detekt apiCheck --stacktrace + publish: - needs: [ build ] - # if: ${{ github.ref == 'refs/heads/master' && github.repository == 'hoc081098/solivagant' }} - if: ${{ false }} + needs: [ build, checks ] + if: ${{ github.ref == 'refs/heads/master' && github.repository == 'hoc081098/solivagant' }} strategy: matrix: os: [ macos-11 ] runs-on: ${{ matrix.os }} - timeout-minutes: 30 + timeout-minutes: 45 steps: - name: Checkout uses: actions/checkout@v3 diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 176a0a9c..6981e934 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -77,7 +77,7 @@ jobs: run: chmod +x ./gradlew - name: Build release - run: ./gradlew :viewmodel:assemble :viewmodel-savedstate:assemble :viewmodel-compose:assemble + run: ./gradlew :lifecycle:assemble :khonshu-navigation-core:assemble :navigation:assemble --stacktrace - name: Publish release run: ./gradlew publish --stacktrace diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bfcc99b..3bdf0916 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,19 @@ ## [Unreleased] - TBD -## [0.0.1] - Feb 11, 2023 +## [0.0.1] - Feb 7, 2024 -- Initial release. +- Initial release of `solivagant` 🔆. + A Compose Multiplatform Navigation - 🌸 Pragmatic, type safety navigation for Compose Multiplatform. + Based on [Freeletics Khonshu Navigation](https://freeletics.github.io/khonshu/navigation/get-started/). -[Unreleased]: https://github.com/hoc081098/solivagant/compare/0.6.1...HEAD +- Dependencies + - [Kotlin `1.9.22`](https://github.com/JetBrains/kotlin/releases/tag/v1.9.22). + - [JetBrains Compose Multiplatform `1.5.12`](https://github.com/JetBrains/compose-multiplatform/releases/tag/v1.5.12). + - [KMP ViewModel `0.6.2`](https://github.com/hoc081098/kmp-viewmodel/releases/tag/0.6.2). + - [KotlinX Coroutines `1.7.3`](https://github.com/Kotlin/kotlinx.coroutines/releases/tag/1.7.3). + - [KotlinX Collections Immutable `0.3.7`](https://github.com/Kotlin/kotlinx.collections.immutable/releases/tag/v0.3.7). +[Unreleased]: https://github.com/hoc081098/solivagant/compare/0.0.1...HEAD [0.0.1]: https://github.com/hoc081098/solivagant/releases/tag/0.0.1 diff --git a/README.md b/README.md index 6cf0bd25..2420b5f4 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,7 @@ navigator.navigateBackTo(inclusive = false) - [ ] Review supported targets - [ ] Polish and improve the implementation and the public API - [ ] Support transition when navigating +- [ ] Support more targets such as wasm, watchOS, tvOS, etc... ## License diff --git a/detekt.yml b/detekt.yml index 5c1c17cc..e8822084 100644 --- a/detekt.yml +++ b/detekt.yml @@ -2,10 +2,10 @@ build: maxIssues: 0 excludeCorrectable: false weights: - # complexity: 2 - # LongParameterList: 1 - # style: 1 - # comments: 1 + # complexity: 2 + # LongParameterList: 1 + # style: 1 + # comments: 1 config: validation: true @@ -34,11 +34,11 @@ processors: console-reports: active: true exclude: - - 'ProjectStatisticsReport' - - 'ComplexityReport' - - 'NotificationReport' - - 'FindingsReport' - - 'FileBasedFindingsReport' + - 'ProjectStatisticsReport' + - 'ComplexityReport' + - 'NotificationReport' + - 'FindingsReport' + - 'FileBasedFindingsReport' # - 'LiteFindingsReport' output-reports: @@ -66,7 +66,7 @@ comments: endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' KDocReferencesNonPublicProperty: active: false - excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] OutdatedDocumentation: active: false matchTypeParameters: true @@ -74,7 +74,7 @@ comments: allowParamOnConstructorProperties: false UndocumentedPublicClass: active: false - excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] searchInNestedClass: true searchInInnerClass: true searchInInnerObject: true @@ -82,11 +82,11 @@ comments: searchInProtectedClass: false UndocumentedPublicFunction: active: false - excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] searchProtectedFunction: false UndocumentedPublicProperty: active: false - excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] searchProtectedProperty: false complexity: @@ -121,7 +121,7 @@ complexity: - 'with' LabeledExpression: active: false - ignoredLabels: [] + ignoredLabels: [ ] LargeClass: active: true threshold: 600 @@ -132,9 +132,9 @@ complexity: active: true functionThreshold: 6 constructorThreshold: 7 - ignoreDefaultParameters: false + ignoreDefaultParameters: true ignoreDataClasses: true - ignoreAnnotatedParameter: [] + ignoreAnnotatedParameter: [ ] MethodOverloading: active: false threshold: 6 @@ -158,14 +158,14 @@ complexity: active: false StringLiteralDuplication: active: false - excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] threshold: 3 ignoreAnnotation: true excludeStringsWithLessThan5Characters: true ignoreStringsRegex: '$^' TooManyFunctions: active: true - excludes: ['**/test/**', '**/*Test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludes: [ '**/test/**', '**/*Test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] thresholdInFiles: 11 thresholdInClasses: 11 thresholdInInterfaces: 11 @@ -240,7 +240,7 @@ exceptions: - 'toString' InstanceOfCheckForException: active: true - excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] NotImplementedDeclaration: active: false ObjectExtendsThrowable: @@ -266,7 +266,7 @@ exceptions: active: false ThrowingExceptionsWithoutMessageOrCause: active: true - excludes: ['**/test/**', '**/*Test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludes: [ '**/test/**', '**/*Test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] exceptions: - 'ArrayIndexOutOfBoundsException' - 'Exception' @@ -281,7 +281,7 @@ exceptions: active: true TooGenericExceptionCaught: active: true - excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] exceptionNames: - 'ArrayIndexOutOfBoundsException' - 'Error' @@ -319,7 +319,7 @@ naming: enumEntryPattern: '[A-Z][_a-zA-Z0-9]*' ForbiddenClassName: active: false - forbiddenName: [] + forbiddenName: [ ] FunctionMaxLength: active: false maximumFunctionNameLength: 30 @@ -389,10 +389,10 @@ performance: threshold: 3 ForEachOnRange: active: true - excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] SpreadOperator: active: true - excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] UnnecessaryPartOfBinaryExpression: active: false UnnecessaryTemporaryInstantiation: @@ -445,7 +445,7 @@ potential-bugs: - 'kotlin.sequences.Sequence' - 'kotlinx.coroutines.flow.*Flow' - 'java.util.stream.*Stream' - ignoreFunctionCall: [] + ignoreFunctionCall: [ ] ImplicitDefaultLocale: active: true ImplicitUnitReturnType: @@ -459,13 +459,13 @@ potential-bugs: active: true LateinitUsage: active: false - excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] ignoreOnClassesPattern: '' MapGetWithNotNullAssertionOperator: active: true MissingPackageDeclaration: active: false - excludes: ['**/*.kts'] + excludes: [ '**/*.kts' ] NullCheckOnMutableProperty: active: false NullableToStringCall: @@ -484,7 +484,7 @@ potential-bugs: active: true UnsafeCallOnNullableType: active: true - excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] UnsafeCast: active: true UnusedUnaryOperator: @@ -531,7 +531,7 @@ style: active: false ForbiddenImport: active: false - imports: [] + imports: [ ] forbiddenPatterns: '' ForbiddenMethodCall: active: false @@ -542,7 +542,7 @@ style: value: 'kotlin.io.println' ForbiddenSuppress: active: false - rules: [] + rules: [ ] ForbiddenVoid: active: true ignoreOverridden: false @@ -551,13 +551,13 @@ style: active: true ignoreOverridableFunction: true ignoreActualFunction: true - excludedFunctions: [] + excludedFunctions: [ ] LoopWithTooManyJumpStatements: active: true maxJumpCount: 1 MagicNumber: active: true - excludes: ['**/test/**', '**/*Test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.kts'] + excludes: [ '**/test/**', '**/*Test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.kts' ] ignoreNumbers: - '-1' - '0' @@ -674,6 +674,7 @@ style: UnusedPrivateMember: active: true allowedNames: '(_|ignored|expected|serialVersionUID|[a-zA-Z]+Preview)' + ignoreAnnotated: [ 'Preview', 'androidx.compose.ui.tooling.preview.Preview' ] UseAnyOrNoneInsteadOfFind: active: true UseArrayLiteralsInAnnotations: diff --git a/docs/multiplatform.md b/docs/multiplatform.md index f941682e..e3e656b3 100644 --- a/docs/multiplatform.md +++ b/docs/multiplatform.md @@ -3,7 +3,7 @@ ## Supported targets - `android`. -- `jvm` (must add `kotlinx-coroutines-swing`/`kotlinx-coroutines-javafx` to your dependencies to +- `jvm` (`Desktop`) (must add `kotlinx-coroutines-swing`/`kotlinx-coroutines-javafx` to your dependencies to make sure `Dispatchers.Main` available). > [!NOTE] @@ -13,8 +13,7 @@ > If you are using `JetBrains Compose Multiplatform` and targeting `Desktop`, you should provide `org.jetbrains.kotlinx:kotlinx-coroutines-swing`. - `js` (`IR`). + - `Darwin` targets: - `iosArm64`, `iosX64`, `iosSimulatorArm64`. - - `watchosArm32`, `watchosArm64`, `watchosX64`, `watchosSimulatorArm64`. - - `tvosX64`, `tvosSimulatorArm64`, `tvosArm64`. - `macosX64`, `macosArm64`. diff --git a/gradle.properties b/gradle.properties index 06277406..4beed132 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,7 +26,7 @@ kotlin.incremental=true GROUP=io.github.hoc081098 # HEY! If you change the major version here be sure to update publish-release.yaml doc target folder! VERSION_NAME=0.0.1-SNAPSHOT -POM_INCEPTION_YEAR=2023 +POM_INCEPTION_YEAR=2024 POM_URL=https://github.com/hoc081098/solivagant POM_SCM_URL=https://github.com/hoc081098/solivagant diff --git a/khonshu-navigation-core/api/android/khonshu-navigation-core.api b/khonshu-navigation-core/api/android/khonshu-navigation-core.api index 07b4840b..49ae3c75 100644 --- a/khonshu-navigation-core/api/android/khonshu-navigation-core.api +++ b/khonshu-navigation-core/api/android/khonshu-navigation-core.api @@ -24,6 +24,9 @@ public final class com/hoc081098/solivagant/navigation/InitialValue$Creator : an public synthetic fun newArray (I)[Ljava/lang/Object; } +public abstract interface annotation class com/hoc081098/solivagant/navigation/InternalNavigationApi : java/lang/annotation/Annotation { +} + public abstract interface class com/hoc081098/solivagant/navigation/NavDestination { } @@ -132,6 +135,9 @@ public final class com/hoc081098/solivagant/navigation/ScreenDestination : com/h public fun getId ()Lcom/hoc081098/solivagant/navigation/internal/DestinationId; } +public abstract interface annotation class com/hoc081098/solivagant/navigation/internal/DelicateNavigationApi : java/lang/annotation/Annotation { +} + public final class com/hoc081098/solivagant/navigation/internal/DestinationId : android/os/Parcelable { public static final field $stable I public static final field CREATOR Landroid/os/Parcelable$Creator; @@ -159,9 +165,6 @@ public final class com/hoc081098/solivagant/navigation/internal/DestinationIdKt public static final fun getDestinationId (Lcom/hoc081098/solivagant/navigation/BaseRoute;)Lcom/hoc081098/solivagant/navigation/internal/DestinationId; } -public abstract interface annotation class com/hoc081098/solivagant/navigation/internal/InternalNavigationApi : java/lang/annotation/Annotation { -} - public abstract interface class com/hoc081098/solivagant/navigation/internal/NavEvent { } @@ -238,11 +241,12 @@ public final class com/hoc081098/solivagant/navigation/internal/NavEvent$UpEvent } public abstract interface class com/hoc081098/solivagant/navigation/internal/NavigationExecutor : com/hoc081098/solivagant/navigation/Navigator { - public abstract fun extra (Lcom/hoc081098/solivagant/navigation/internal/DestinationId;)Ljava/io/Serializable; - public abstract fun routeFor (Lcom/hoc081098/solivagant/navigation/internal/DestinationId;)Lcom/hoc081098/solivagant/navigation/BaseRoute; - public abstract fun savedStateHandleFactoryFor (Lcom/hoc081098/solivagant/navigation/internal/DestinationId;)Lcom/hoc081098/kmp/viewmodel/SavedStateHandleFactory; - public abstract fun savedStateHandleFor (Lcom/hoc081098/solivagant/navigation/internal/DestinationId;)Landroidx/lifecycle/SavedStateHandle; - public abstract fun storeFor (Lcom/hoc081098/solivagant/navigation/internal/DestinationId;)Lcom/hoc081098/solivagant/navigation/internal/NavigationExecutor$Store; + public abstract fun extra-3IqVRSk (Ljava/lang/String;)Ljava/io/Serializable; + public abstract fun savedStateHandleFactoryFor-3IqVRSk (Ljava/lang/String;)Lcom/hoc081098/kmp/viewmodel/SavedStateHandleFactory; + public abstract fun savedStateHandleFor-3IqVRSk (Ljava/lang/String;)Landroidx/lifecycle/SavedStateHandle; + public abstract fun stackEntryIdFor-l9GXND0 (Lcom/hoc081098/solivagant/navigation/BaseRoute;)Ljava/lang/String; + public abstract fun stackEntryIdFor-l9GXND0 (Lcom/hoc081098/solivagant/navigation/internal/DestinationId;)Ljava/lang/String; + public abstract fun storeFor-3IqVRSk (Ljava/lang/String;)Lcom/hoc081098/solivagant/navigation/internal/NavigationExecutor$Store; } public abstract interface class com/hoc081098/solivagant/navigation/internal/NavigationExecutor$Store { @@ -266,3 +270,17 @@ public final class com/hoc081098/solivagant/navigation/internal/OnBackPressedDis public static final fun currentBackPressedDispatcher (Landroidx/compose/runtime/Composer;I)Lcom/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner; } +public final class com/hoc081098/solivagant/navigation/internal/StackEntryId { + public static final synthetic fun box-impl (Ljava/lang/String;)Lcom/hoc081098/solivagant/navigation/internal/StackEntryId; + public static fun constructor-impl (Ljava/lang/String;)Ljava/lang/String; + public fun equals (Ljava/lang/Object;)Z + public static fun equals-impl (Ljava/lang/String;Ljava/lang/Object;)Z + public static final fun equals-impl0 (Ljava/lang/String;Ljava/lang/String;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public static fun hashCode-impl (Ljava/lang/String;)I + public fun toString ()Ljava/lang/String; + public static fun toString-impl (Ljava/lang/String;)Ljava/lang/String; + public final synthetic fun unbox-impl ()Ljava/lang/String; +} + diff --git a/khonshu-navigation-core/api/jvm/khonshu-navigation-core.api b/khonshu-navigation-core/api/jvm/khonshu-navigation-core.api index 0c7010b3..bb7e28a2 100644 --- a/khonshu-navigation-core/api/jvm/khonshu-navigation-core.api +++ b/khonshu-navigation-core/api/jvm/khonshu-navigation-core.api @@ -16,6 +16,9 @@ public final class com/hoc081098/solivagant/navigation/EXTRA_ROUTEKt { public static final field EXTRA_ROUTE Ljava/lang/String; } +public abstract interface annotation class com/hoc081098/solivagant/navigation/InternalNavigationApi : java/lang/annotation/Annotation { +} + public abstract interface class com/hoc081098/solivagant/navigation/NavDestination { } @@ -113,6 +116,9 @@ public final class com/hoc081098/solivagant/navigation/ScreenDestination : com/h public fun getId ()Lcom/hoc081098/solivagant/navigation/internal/DestinationId; } +public abstract interface annotation class com/hoc081098/solivagant/navigation/internal/DelicateNavigationApi : java/lang/annotation/Annotation { +} + public final class com/hoc081098/solivagant/navigation/internal/DestinationId : com/hoc081098/kmp/viewmodel/parcelable/Parcelable { public static final field $stable I public final field route Lkotlin/reflect/KClass; @@ -129,9 +135,6 @@ public final class com/hoc081098/solivagant/navigation/internal/DestinationIdKt public static final fun getDestinationId (Lcom/hoc081098/solivagant/navigation/BaseRoute;)Lcom/hoc081098/solivagant/navigation/internal/DestinationId; } -public abstract interface annotation class com/hoc081098/solivagant/navigation/internal/InternalNavigationApi : java/lang/annotation/Annotation { -} - public abstract interface class com/hoc081098/solivagant/navigation/internal/NavEvent { } @@ -208,11 +211,12 @@ public final class com/hoc081098/solivagant/navigation/internal/NavEvent$UpEvent } public abstract interface class com/hoc081098/solivagant/navigation/internal/NavigationExecutor : com/hoc081098/solivagant/navigation/Navigator { - public abstract fun extra (Lcom/hoc081098/solivagant/navigation/internal/DestinationId;)Ljava/io/Serializable; - public abstract fun routeFor (Lcom/hoc081098/solivagant/navigation/internal/DestinationId;)Lcom/hoc081098/solivagant/navigation/BaseRoute; - public abstract fun savedStateHandleFactoryFor (Lcom/hoc081098/solivagant/navigation/internal/DestinationId;)Lcom/hoc081098/kmp/viewmodel/SavedStateHandleFactory; - public abstract fun savedStateHandleFor (Lcom/hoc081098/solivagant/navigation/internal/DestinationId;)Lcom/hoc081098/kmp/viewmodel/SavedStateHandle; - public abstract fun storeFor (Lcom/hoc081098/solivagant/navigation/internal/DestinationId;)Lcom/hoc081098/solivagant/navigation/internal/NavigationExecutor$Store; + public abstract fun extra-3IqVRSk (Ljava/lang/String;)Ljava/io/Serializable; + public abstract fun savedStateHandleFactoryFor-3IqVRSk (Ljava/lang/String;)Lcom/hoc081098/kmp/viewmodel/SavedStateHandleFactory; + public abstract fun savedStateHandleFor-3IqVRSk (Ljava/lang/String;)Lcom/hoc081098/kmp/viewmodel/SavedStateHandle; + public abstract fun stackEntryIdFor-l9GXND0 (Lcom/hoc081098/solivagant/navigation/BaseRoute;)Ljava/lang/String; + public abstract fun stackEntryIdFor-l9GXND0 (Lcom/hoc081098/solivagant/navigation/internal/DestinationId;)Ljava/lang/String; + public abstract fun storeFor-3IqVRSk (Ljava/lang/String;)Lcom/hoc081098/solivagant/navigation/internal/NavigationExecutor$Store; } public abstract interface class com/hoc081098/solivagant/navigation/internal/NavigationExecutor$Store { @@ -249,3 +253,17 @@ public final class com/hoc081098/solivagant/navigation/internal/OnBackPressedDis public static final fun currentBackPressedDispatcher (Landroidx/compose/runtime/Composer;I)Lcom/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner; } +public final class com/hoc081098/solivagant/navigation/internal/StackEntryId { + public static final synthetic fun box-impl (Ljava/lang/String;)Lcom/hoc081098/solivagant/navigation/internal/StackEntryId; + public static fun constructor-impl (Ljava/lang/String;)Ljava/lang/String; + public fun equals (Ljava/lang/Object;)Z + public static fun equals-impl (Ljava/lang/String;Ljava/lang/Object;)Z + public static final fun equals-impl0 (Ljava/lang/String;Ljava/lang/String;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public static fun hashCode-impl (Ljava/lang/String;)I + public fun toString ()Ljava/lang/String; + public static fun toString-impl (Ljava/lang/String;)Ljava/lang/String; + public final synthetic fun unbox-impl ()Ljava/lang/String; +} + diff --git a/khonshu-navigation-core/build.gradle.kts b/khonshu-navigation-core/build.gradle.kts index b0e5cd16..c7c98837 100644 --- a/khonshu-navigation-core/build.gradle.kts +++ b/khonshu-navigation-core/build.gradle.kts @@ -31,6 +31,10 @@ kotlin { vendor.set(JvmVendorSpec.AZUL) } + // Supports targets that have MainCoroutineDispatcher (following kmp-viewmodel artifact) + // Also constrained by https://github.com/JetBrains/compose-multiplatform-core/blob/71ccb291b6fc5d840da05cef108ae11384bfe584/compose/ui/ui/build.gradle#L142-L150 + // Ref: https://github.com/JetBrains/compose-multiplatform-core/blob/9806d785bf33e25b0dda4853d492b319cf9a819f/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeMultiplatformExtensionImpl.kt#L171-L176 + androidTarget { publishAllLibraryVariants() @@ -168,7 +172,7 @@ kotlin { sourceSets.configureEach { languageSettings { - optIn("com.hoc081098.solivagant.navigation.internal.InternalNavigationApi") + optIn("com.hoc081098.solivagant.navigation.InternalNavigationApi") } } } @@ -207,14 +211,26 @@ mavenPublishing { signAllPublications() } -tasks.withType().configureEach { +tasks.withType().configureEach { dokkaSourceSets { configureEach { externalDocumentationLink("https://kotlinlang.org/api/kotlinx.coroutines/") + // TODO: Issue https://github.com/Kotlin/dokka/issues/3368 and https://github.com/Kotlin/dokka/issues/2037 + externalDocumentationLink( + url = "https://hoc081098.github.io/kmp-viewmodel/docs/0.x/API/", + packageListUrl = "https://hoc081098.github.io/kmp-viewmodel/docs/0.x/API/package-list", + ) + + perPackageOption { + // Will match all .internal packages and sub-packages, regardless of module. + matchingRegex.set(""".*\.internal.*""") + suppress.set(true) + } + sourceLink { localDirectory.set(projectDir.resolve("src")) - remoteUrl.set(URL("https://github.com/hoc081098/solivagant/tree/master/viewmodel-compose/src")) + remoteUrl.set(URL("https://github.com/hoc081098/solivagant/tree/master/khonshu-navigation-core/src")) remoteLineSuffix.set("#L") } } diff --git a/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/DestinationId.android.kt b/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/DestinationId.android.kt index d01e61cb..eb26b53d 100644 --- a/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/DestinationId.android.kt +++ b/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/DestinationId.android.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import android.os.Parcel diff --git a/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedCallback.android.kt b/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedCallback.android.kt index 9d5ea734..ebb2cc03 100644 --- a/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedCallback.android.kt +++ b/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedCallback.android.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal public actual typealias OnBackPressedCallback = androidx.activity.OnBackPressedCallback diff --git a/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner.android.kt b/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner.android.kt index 0af83a46..0019ad46 100644 --- a/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner.android.kt +++ b/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner.android.kt @@ -1,8 +1,25 @@ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.hoc081098.solivagant.navigation.internal import androidx.activity.compose.LocalOnBackPressedDispatcherOwner import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.hoc081098.solivagant.navigation.InternalNavigationApi @InternalNavigationApi public actual class OnBackPressedDispatcherOwner( diff --git a/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/VisibleForTesting.android.kt b/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/VisibleForTesting.android.kt index 208969f5..ad8d2991 100644 --- a/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/VisibleForTesting.android.kt +++ b/khonshu-navigation-core/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/VisibleForTesting.android.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal @Suppress("ACTUAL_WITHOUT_EXPECT") // internal expect is not matched with internal typealias to public type diff --git a/khonshu-navigation-core/src/commonJvmMain/kotlin/com/hoc081098/solivagant/navigation/Serializable.commonJvm.kt b/khonshu-navigation-core/src/commonJvmMain/kotlin/com/hoc081098/solivagant/navigation/Serializable.commonJvm.kt index eaf732f4..4f9a58b1 100644 --- a/khonshu-navigation-core/src/commonJvmMain/kotlin/com/hoc081098/solivagant/navigation/Serializable.commonJvm.kt +++ b/khonshu-navigation-core/src/commonJvmMain/kotlin/com/hoc081098/solivagant/navigation/Serializable.commonJvm.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation public actual typealias Serializable = java.io.Serializable diff --git a/khonshu-navigation-core/src/commonJvmMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.commonJvm.kt b/khonshu-navigation-core/src/commonJvmMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.commonJvm.kt index 28a3d4ae..30c8b87e 100644 --- a/khonshu-navigation-core/src/commonJvmMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.commonJvm.kt +++ b/khonshu-navigation-core/src/commonJvmMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.commonJvm.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import kotlinx.coroutines.channels.ChannelResult diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/EXTRA_ROUTE.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/EXTRA_ROUTE.kt index 076a6b55..fd4cbc43 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/EXTRA_ROUTE.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/EXTRA_ROUTE.kt @@ -1,7 +1,22 @@ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.hoc081098.solivagant.navigation import androidx.compose.runtime.Stable -import com.hoc081098.solivagant.navigation.internal.InternalNavigationApi @InternalNavigationApi @Stable diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/InternalNavigationApi.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/InternalNavigationApi.kt new file mode 100644 index 00000000..e6421756 --- /dev/null +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/InternalNavigationApi.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hoc081098.solivagant.navigation + +/** + * Code marked with [InternalNavigationApi] has no guarantees about API stability and can be changed + * at any time. + */ +@RequiresOptIn +@Retention(AnnotationRetention.BINARY) +@MustBeDocumented +public annotation class InternalNavigationApi diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavDestination.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavDestination.kt index bbf0c9a0..2c74de20 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavDestination.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavDestination.kt @@ -1,8 +1,23 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation import androidx.compose.runtime.Composable import com.hoc081098.solivagant.navigation.internal.DestinationId -import com.hoc081098.solivagant.navigation.internal.InternalNavigationApi /** * A destination that can be navigated to. See `NavHost` for how to configure a `NavGraph` with it. diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavEventNavigator.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavEventNavigator.kt index 819901f3..9e920ef3 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavEventNavigator.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavEventNavigator.kt @@ -1,10 +1,25 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation import com.hoc081098.kmp.viewmodel.MainThread import com.hoc081098.kmp.viewmodel.parcelable.Parcelable import com.hoc081098.solivagant.navigation.internal.DelegatingOnBackPressedCallback import com.hoc081098.solivagant.navigation.internal.DestinationId -import com.hoc081098.solivagant.navigation.internal.InternalNavigationApi import com.hoc081098.solivagant.navigation.internal.NavEvent import com.hoc081098.solivagant.navigation.internal.NavEvent.BackEvent import com.hoc081098.solivagant.navigation.internal.NavEvent.BackToEvent diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavRoute.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavRoute.kt index d65bdf29..00fa9764 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavRoute.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavRoute.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation import androidx.compose.runtime.Immutable diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavigationSetup.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavigationSetup.kt index a075b1b9..e7ae43ad 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavigationSetup.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavigationSetup.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation import androidx.compose.runtime.Composable @@ -11,7 +27,7 @@ import com.hoc081098.solivagant.lifecycle.Lifecycle import com.hoc081098.solivagant.lifecycle.LifecycleOwner import com.hoc081098.solivagant.lifecycle.LocalLifecycleOwner import com.hoc081098.solivagant.lifecycle.repeatOnLifecycle -import com.hoc081098.solivagant.navigation.internal.InternalNavigationApi +import com.hoc081098.solivagant.navigation.internal.DelicateNavigationApi import com.hoc081098.solivagant.navigation.internal.NavEvent import com.hoc081098.solivagant.navigation.internal.NavigationExecutor import com.hoc081098.solivagant.navigation.internal.VisibleForTesting @@ -72,6 +88,7 @@ internal suspend fun NavEventNavigator.collectAndHandleNavEvents( } } +@OptIn(DelicateNavigationApi::class) private fun NavigationExecutor.navigateTo( event: NavEvent, ) { @@ -105,7 +122,9 @@ private fun NavigationExecutor.navigateTo( } is NavEvent.DestinationResultEvent<*> -> { - savedStateHandleFor(event.key.destinationId)[event.key.requestKey] = event.result + @Suppress("DEPRECATION") + val id = stackEntryIdFor(event.key.destinationId) + savedStateHandleFor(id)[event.key.requestKey] = event.result } is NavEvent.MultiNavEvent -> { @@ -114,11 +133,14 @@ private fun NavigationExecutor.navigateTo( } } +@OptIn(DelicateNavigationApi::class) @VisibleForTesting internal suspend fun NavigationExecutor.collectAndHandleNavigationResults( request: NavigationResultRequest, ) { - val savedStateHandle = savedStateHandleFor(request.key.destinationId) + @Suppress("DEPRECATION") + val id = stackEntryIdFor(request.key.destinationId) + val savedStateHandle = savedStateHandleFor(id) savedStateHandle.getStateFlow(request.key.requestKey, InitialValue) .collect { if (it != InitialValue) { diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/ResultOwner.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/ResultOwner.kt index ded32ccc..b14ede80 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/ResultOwner.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/ResultOwner.kt @@ -1,9 +1,24 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation import com.hoc081098.kmp.viewmodel.parcelable.Parcelable import com.hoc081098.kmp.viewmodel.parcelable.Parcelize import com.hoc081098.solivagant.navigation.internal.DestinationId -import com.hoc081098.solivagant.navigation.internal.InternalNavigationApi import com.hoc081098.solivagant.navigation.internal.trySendBlocking import dev.drewhamilton.poko.Poko import kotlinx.coroutines.channels.Channel diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/Serializable.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/Serializable.kt index 5ffe627f..54de5c42 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/Serializable.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/Serializable.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation public expect interface Serializable diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/DelegatingOnBackPressedCallback.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/DelegatingOnBackPressedCallback.kt index 5623ab0e..b3101889 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/DelegatingOnBackPressedCallback.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/DelegatingOnBackPressedCallback.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal internal class DelegatingOnBackPressedCallback : OnBackPressedCallback(false) { diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/DestinationId.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/DestinationId.kt index 7fb32f39..fc89c877 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/DestinationId.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/DestinationId.kt @@ -1,3 +1,35 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import androidx.compose.runtime.Immutable @@ -7,6 +39,7 @@ import com.hoc081098.kmp.viewmodel.parcelable.Parceler import com.hoc081098.kmp.viewmodel.parcelable.Parcelize import com.hoc081098.kmp.viewmodel.parcelable.WriteWith import com.hoc081098.solivagant.navigation.BaseRoute +import com.hoc081098.solivagant.navigation.InternalNavigationApi import kotlin.jvm.JvmField import kotlin.reflect.KClass diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/InternalNavigationApi.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/InternalNavigationApi.kt deleted file mode 100644 index 6283f007..00000000 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/InternalNavigationApi.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.hoc081098.solivagant.navigation.internal - -/** - * Code marked with [InternalNavigationApi] has no guarantees about API stability and can be changed - * at any time. - */ -@RequiresOptIn -@Retention(AnnotationRetention.BINARY) -public annotation class InternalNavigationApi diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavEvent.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavEvent.kt index 7bb3d55d..90852d8a 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavEvent.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavEvent.kt @@ -1,7 +1,24 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.kmp.viewmodel.parcelable.Parcelable import com.hoc081098.solivagant.navigation.BaseRoute +import com.hoc081098.solivagant.navigation.InternalNavigationApi import com.hoc081098.solivagant.navigation.NavRoot import com.hoc081098.solivagant.navigation.NavRoute import com.hoc081098.solivagant.navigation.NavigationResultRequest diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavEventCollector.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavEventCollector.kt index e12c075b..16957397 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavEventCollector.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavEventCollector.kt @@ -1,6 +1,23 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.solivagant.navigation.BaseRoute +import com.hoc081098.solivagant.navigation.InternalNavigationApi import com.hoc081098.solivagant.navigation.NavRoot import com.hoc081098.solivagant.navigation.NavRoute import com.hoc081098.solivagant.navigation.Navigator diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavigationExecutor.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavigationExecutor.kt index c7bab936..26159a33 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavigationExecutor.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavigationExecutor.kt @@ -1,19 +1,98 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.kmp.viewmodel.SavedStateHandle import com.hoc081098.kmp.viewmodel.SavedStateHandleFactory import com.hoc081098.solivagant.navigation.BaseRoute +import com.hoc081098.solivagant.navigation.InternalNavigationApi import com.hoc081098.solivagant.navigation.Navigator import com.hoc081098.solivagant.navigation.Serializable +import kotlin.jvm.JvmInline import kotlin.reflect.KClass +@Retention(value = AnnotationRetention.BINARY) +@RequiresOptIn( + level = RequiresOptIn.Level.WARNING, + message = "This is a delicate API and its use requires care." + + " Make sure you fully read and understand documentation of the declaration that is marked as a delicate API.", +) +public annotation class DelicateNavigationApi + +/** + * A unique identifier for an entry in the navigation stack. + */ +@InternalNavigationApi +@JvmInline +public value class StackEntryId(public val value: String) + +/** + * An internal API for navigation. + */ @InternalNavigationApi public interface NavigationExecutor : Navigator { - public fun routeFor(destinationId: DestinationId): T - public fun savedStateHandleFor(destinationId: DestinationId): SavedStateHandle - public fun savedStateHandleFactoryFor(destinationId: DestinationId): SavedStateHandleFactory - public fun storeFor(destinationId: DestinationId): Store - public fun extra(destinationId: DestinationId): Serializable + /** + * Find the [StackEntryId] by the given [route]. + */ + @DelicateNavigationApi + public fun stackEntryIdFor(route: BaseRoute): StackEntryId + + /** + * Find the [StackEntryId] by the given [destinationId]. + */ + @DelicateNavigationApi + @Deprecated("Should not use destinationId directly, use route instead.") + public fun stackEntryIdFor(destinationId: DestinationId<*>): StackEntryId + + /** + * Returns the [SavedStateHandle] for the given [id]. + */ + public fun savedStateHandleFor(id: StackEntryId): SavedStateHandle + + /** + * Returns the [SavedStateHandleFactory] for the given [id]. + */ + public fun savedStateHandleFactoryFor(id: StackEntryId): SavedStateHandleFactory + + /** + * Returns the [Store] for the given [id]. + */ + public fun storeFor(id: StackEntryId): Store + + /** + * Returns the extra data for the given [id]. + */ + public fun extra(id: StackEntryId): Serializable @InternalNavigationApi public interface Store { diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavigationExecutorStore.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavigationExecutorStore.kt index 58c091c2..cdd6c1b9 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavigationExecutorStore.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/NavigationExecutorStore.kt @@ -1,6 +1,23 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.kmp.viewmodel.Closeable +import com.hoc081098.solivagant.navigation.InternalNavigationApi import kotlin.reflect.KClass @InternalNavigationApi diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedCallback.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedCallback.kt index 77e60786..afc3725a 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedCallback.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedCallback.kt @@ -1,6 +1,24 @@ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.kmp.viewmodel.MainThread +import com.hoc081098.solivagant.navigation.InternalNavigationApi @InternalNavigationApi public expect abstract class OnBackPressedCallback(enabled: Boolean) { diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner.kt index eac5bcd7..ea5f70a9 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner.kt @@ -1,6 +1,23 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import androidx.compose.runtime.Composable +import com.hoc081098.solivagant.navigation.InternalNavigationApi @InternalNavigationApi public expect class OnBackPressedDispatcherOwner { diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/VisibleForTesting.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/VisibleForTesting.kt index 2ca80f9c..e3da0151 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/VisibleForTesting.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/VisibleForTesting.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal @MustBeDocumented diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.kt index 484aa4cd..00a10e1b 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import kotlinx.coroutines.channels.ChannelResult diff --git a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/requireRoute.kt b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/requireRoute.kt index 8b6d51c6..995bf8fd 100644 --- a/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/requireRoute.kt +++ b/khonshu-navigation-core/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/requireRoute.kt @@ -1,7 +1,22 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation import com.hoc081098.kmp.viewmodel.SavedStateHandle -import com.hoc081098.solivagant.navigation.internal.InternalNavigationApi public fun SavedStateHandle.requireRoute(): T { return requireNotNull(get(EXTRA_ROUTE)) { diff --git a/khonshu-navigation-core/src/jsMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.js.kt b/khonshu-navigation-core/src/jsMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.js.kt index af6a62da..6baed150 100644 --- a/khonshu-navigation-core/src/jsMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.js.kt +++ b/khonshu-navigation-core/src/jsMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.js.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import kotlinx.coroutines.channels.ChannelResult diff --git a/khonshu-navigation-core/src/nativeMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.native.kt b/khonshu-navigation-core/src/nativeMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.native.kt index 28a3d4ae..30c8b87e 100644 --- a/khonshu-navigation-core/src/nativeMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.native.kt +++ b/khonshu-navigation-core/src/nativeMain/kotlin/com/hoc081098/solivagant/navigation/internal/trySendBlocking.native.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import kotlinx.coroutines.channels.ChannelResult diff --git a/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/DestinationId.nonAndroid.kt b/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/DestinationId.nonAndroid.kt index 99b83ccb..14b8f272 100644 --- a/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/DestinationId.nonAndroid.kt +++ b/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/DestinationId.nonAndroid.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.kmp.viewmodel.parcelable.Parceler diff --git a/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedCallback.nonAndroid.kt b/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedCallback.nonAndroid.kt index 890013fd..86bcaba9 100644 --- a/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedCallback.nonAndroid.kt +++ b/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedCallback.nonAndroid.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.kmp.viewmodel.MainThread diff --git a/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner.nonAndroid.kt b/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner.nonAndroid.kt index 7c618963..bc7064f3 100644 --- a/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner.nonAndroid.kt +++ b/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/OnBackPressedDispatcherOwner.nonAndroid.kt @@ -1,6 +1,23 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import androidx.compose.runtime.Composable +import com.hoc081098.solivagant.navigation.InternalNavigationApi @InternalNavigationApi public actual class OnBackPressedDispatcherOwner { diff --git a/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/VisibleForTesting.nonAndroid.kt b/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/VisibleForTesting.nonAndroid.kt index 4a39a8e6..69c00a61 100644 --- a/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/VisibleForTesting.nonAndroid.kt +++ b/khonshu-navigation-core/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/VisibleForTesting.nonAndroid.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal @MustBeDocumented diff --git a/khonshu-navigation-core/src/nonJvmMain/kotlin/com/hoc081098/solivagant/navigation/Serializable.nonJvm.kt b/khonshu-navigation-core/src/nonJvmMain/kotlin/com/hoc081098/solivagant/navigation/Serializable.nonJvm.kt index 83754f48..8f804671 100644 --- a/khonshu-navigation-core/src/nonJvmMain/kotlin/com/hoc081098/solivagant/navigation/Serializable.nonJvm.kt +++ b/khonshu-navigation-core/src/nonJvmMain/kotlin/com/hoc081098/solivagant/navigation/Serializable.nonJvm.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation public actual interface Serializable diff --git a/lifecycle/build.gradle.kts b/lifecycle/build.gradle.kts index 137388d0..1ae5f7f5 100644 --- a/lifecycle/build.gradle.kts +++ b/lifecycle/build.gradle.kts @@ -28,6 +28,10 @@ kotlin { vendor.set(JvmVendorSpec.AZUL) } + // Supports targets that have MainCoroutineDispatcher (following kmp-viewmodel artifact) + // Also constrained by https://github.comhttps://github.com/JetBrains/compose-multiplatform-core/blob/71ccb291b6fc5d840da05cef108ae11384bfe584/compose/runtime/runtime/build.gradle#L72-L84 + // Ref: https://github.com/JetBrains/compose-multiplatform-core/blob/9806d785bf33e25b0dda4853d492b319cf9a819f/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeMultiplatformExtensionImpl.kt#L171-L176 + androidTarget { publishAllLibraryVariants() @@ -64,6 +68,15 @@ kotlin { macosX64() macosArm64() + tvosX64() + tvosSimulatorArm64() + tvosArm64() + + watchosArm32() + watchosArm64() + watchosX64() + watchosSimulatorArm64() + applyDefaultHierarchyTemplate() sourceSets { @@ -194,11 +207,17 @@ mavenPublishing { signAllPublications() } -tasks.withType().configureEach { +tasks.withType().configureEach { dokkaSourceSets { configureEach { externalDocumentationLink("https://kotlinlang.org/api/kotlinx.coroutines/") + perPackageOption { + // Will match all .internal packages and sub-packages, regardless of module. + matchingRegex.set(""".*\.internal.*""") + suppress.set(true) + } + sourceLink { localDirectory.set(projectDir.resolve("src")) remoteUrl.set(URL("https://github.com/hoc081098/solivagant/tree/master/lifecycle/src")) diff --git a/lifecycle/src/androidMain/kotlin/com/hoc081098/solivagant/lifecycle/android.kt b/lifecycle/src/androidMain/kotlin/com/hoc081098/solivagant/lifecycle/android.kt index 5f7beca8..9b07013a 100644 --- a/lifecycle/src/androidMain/kotlin/com/hoc081098/solivagant/lifecycle/android.kt +++ b/lifecycle/src/androidMain/kotlin/com/hoc081098/solivagant/lifecycle/android.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.lifecycle import androidx.lifecycle.Lifecycle as AndroidXLifecycle diff --git a/lifecycle/src/androidMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/mapState.kt b/lifecycle/src/androidMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/mapState.kt index 56e5650e..b947a340 100644 --- a/lifecycle/src/androidMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/mapState.kt +++ b/lifecycle/src/androidMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/mapState.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.lifecycle.internal import kotlinx.coroutines.flow.FlowCollector diff --git a/lifecycle/src/commonJvmMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.commonJvm.kt b/lifecycle/src/commonJvmMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.commonJvm.kt index b6444b24..bb0a08a7 100644 --- a/lifecycle/src/commonJvmMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.commonJvm.kt +++ b/lifecycle/src/commonJvmMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.commonJvm.kt @@ -1,7 +1,21 @@ -package com.hoc081098.solivagant.lifecycle.internal +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -import java.util.concurrent.atomic.AtomicReference +package com.hoc081098.solivagant.lifecycle.internal // TODO: https://youtrack.jetbrains.com/issue/KT-37316 @Suppress("ACTUAL_WITHOUT_EXPECT") // internal expect is not matched with internal typealias to public type -internal actual typealias AtomicReference = AtomicReference +internal actual typealias AtomicReference = java.util.concurrent.atomic.AtomicReference diff --git a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/Lifecycle.kt b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/Lifecycle.kt index 796e9aa1..cfcd0dc8 100644 --- a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/Lifecycle.kt +++ b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/Lifecycle.kt @@ -30,6 +30,22 @@ * limitations under the License. */ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.lifecycle import com.hoc081098.solivagant.lifecycle.Lifecycle.Event diff --git a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/LifecycleOwner.kt b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/LifecycleOwner.kt index b5d52722..c022a346 100644 --- a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/LifecycleOwner.kt +++ b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/LifecycleOwner.kt @@ -30,6 +30,22 @@ * limitations under the License. */ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.lifecycle /** diff --git a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/LifecycleOwnerRegistry.kt b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/LifecycleOwnerRegistry.kt index 8192eb85..149045d0 100644 --- a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/LifecycleOwnerRegistry.kt +++ b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/LifecycleOwnerRegistry.kt @@ -14,6 +14,22 @@ * limitations under the License. */ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.lifecycle import androidx.compose.runtime.Composable diff --git a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/LocalLifecycleOwner.kt b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/LocalLifecycleOwner.kt index 9d5aa36e..32749d8c 100644 --- a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/LocalLifecycleOwner.kt +++ b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/LocalLifecycleOwner.kt @@ -1,3 +1,18 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.hoc081098.solivagant.lifecycle import androidx.compose.runtime.Composable diff --git a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/compose/collectAsStateWithLifecycle.kt b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/compose/collectAsStateWithLifecycle.kt index 89ce8501..f6421342 100644 --- a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/compose/collectAsStateWithLifecycle.kt +++ b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/compose/collectAsStateWithLifecycle.kt @@ -14,6 +14,22 @@ * limitations under the License. */ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.lifecycle.compose import androidx.compose.runtime.Composable diff --git a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/compose/currentStateAsState.kt b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/compose/currentStateAsState.kt index d1f0e2e3..e8c3361d 100644 --- a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/compose/currentStateAsState.kt +++ b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/compose/currentStateAsState.kt @@ -14,6 +14,22 @@ * limitations under the License. */ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.lifecycle.compose import androidx.compose.runtime.Composable diff --git a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/compose/lifecycleEffects.kt b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/compose/lifecycleEffects.kt index 5e0b7bef..505c07de 100644 --- a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/compose/lifecycleEffects.kt +++ b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/compose/lifecycleEffects.kt @@ -14,6 +14,22 @@ * limitations under the License. */ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + @file:Suppress("TooManyFunctions") package com.hoc081098.solivagant.lifecycle.compose diff --git a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.kt b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.kt index 414bcf5c..1390f54f 100644 --- a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.kt +++ b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.kt @@ -1,3 +1,18 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.hoc081098.solivagant.lifecycle.internal internal expect class AtomicReference(value: T) { diff --git a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/repeatOnLifecycle.kt b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/repeatOnLifecycle.kt index d9423a89..a5402dc1 100644 --- a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/repeatOnLifecycle.kt +++ b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/repeatOnLifecycle.kt @@ -14,6 +14,22 @@ * limitations under the License. */ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.lifecycle import com.hoc081098.solivagant.lifecycle.Lifecycle.Cancellable diff --git a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/withLifecycleState.kt b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/withLifecycleState.kt index d3486e3a..55288a46 100644 --- a/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/withLifecycleState.kt +++ b/lifecycle/src/commonMain/kotlin/com/hoc081098/solivagant/lifecycle/withLifecycleState.kt @@ -14,6 +14,22 @@ * limitations under the License. */ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.lifecycle import com.hoc081098.solivagant.lifecycle.internal.AtomicReference diff --git a/lifecycle/src/jsMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.js.kt b/lifecycle/src/jsMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.js.kt index 9e94d0e7..ab31f1fd 100644 --- a/lifecycle/src/jsMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.js.kt +++ b/lifecycle/src/jsMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.js.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.lifecycle.internal internal actual class AtomicReference actual constructor(value: T) { diff --git a/lifecycle/src/nativeMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.native.kt b/lifecycle/src/nativeMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.native.kt index 9ce243f4..b4401153 100644 --- a/lifecycle/src/nativeMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.native.kt +++ b/lifecycle/src/nativeMain/kotlin/com/hoc081098/solivagant/lifecycle/internal/AtomicReference.native.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.lifecycle.internal internal actual class AtomicReference actual constructor(value: T) { diff --git a/navigation/api/android/navigation.api b/navigation/api/android/navigation.api index 11a71dee..a7090bb2 100644 --- a/navigation/api/android/navigation.api +++ b/navigation/api/android/navigation.api @@ -2,3 +2,7 @@ public final class com/hoc081098/solivagant/navigation/NavHostKt { public static final fun NavHost (Lcom/hoc081098/solivagant/navigation/NavRoot;Lkotlinx/collections/immutable/ImmutableSet;Landroidx/compose/ui/Modifier;Lcom/hoc081098/solivagant/navigation/NavEventNavigator;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V } +public final class com/hoc081098/solivagant/navigation/RememberCloseableOnRouteKt { + public static final fun rememberCloseableOnRoute (Lcom/hoc081098/solivagant/navigation/BaseRoute;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)Ljava/io/Closeable; +} + diff --git a/navigation/api/jvm/navigation.api b/navigation/api/jvm/navigation.api index a06d1f53..bf133128 100644 --- a/navigation/api/jvm/navigation.api +++ b/navigation/api/jvm/navigation.api @@ -1,7 +1,15 @@ +public final class com/hoc081098/solivagant/navigation/LifecycleControllerEffectKt { + public static final fun LifecycleControllerEffect (Lcom/hoc081098/solivagant/lifecycle/LifecycleRegistry;Landroidx/compose/ui/window/WindowState;Landroidx/compose/runtime/Composer;I)V +} + public final class com/hoc081098/solivagant/navigation/NavHostKt { public static final fun NavHost (Lcom/hoc081098/solivagant/navigation/NavRoot;Lkotlinx/collections/immutable/ImmutableSet;Landroidx/compose/ui/Modifier;Lcom/hoc081098/solivagant/navigation/NavEventNavigator;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V } +public final class com/hoc081098/solivagant/navigation/RememberCloseableOnRouteKt { + public static final fun rememberCloseableOnRoute (Lcom/hoc081098/solivagant/navigation/BaseRoute;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)Ljava/io/Closeable; +} + public final class com/hoc081098/solivagant/navigation/SavedStateSupport : androidx/compose/runtime/saveable/SaveableStateRegistry, com/hoc081098/kmp/viewmodel/SavedStateHandleFactory, com/hoc081098/kmp/viewmodel/ViewModelStoreOwner { public static final field $stable I public fun ()V @@ -14,7 +22,3 @@ public final class com/hoc081098/solivagant/navigation/SavedStateSupport : andro public fun registerProvider (Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Landroidx/compose/runtime/saveable/SaveableStateRegistry$Entry; } -public final class com/hoc081098/solivagant/navigation/internal/RememberPlatformLifecycleOwner_jvmKt { - public static final fun LifecycleControllerEffect (Lcom/hoc081098/solivagant/lifecycle/LifecycleRegistry;Landroidx/compose/ui/window/WindowState;Landroidx/compose/runtime/Composer;I)V -} - diff --git a/navigation/build.gradle.kts b/navigation/build.gradle.kts index 21250a35..57ddaea7 100644 --- a/navigation/build.gradle.kts +++ b/navigation/build.gradle.kts @@ -31,6 +31,10 @@ kotlin { vendor.set(JvmVendorSpec.AZUL) } + // Supports targets that have MainCoroutineDispatcher (following kmp-viewmodel artifact) + // Also constrained by https://github.com/JetBrains/compose-multiplatform-core/blob/71ccb291b6fc5d840da05cef108ae11384bfe584/compose/ui/ui/build.gradle#L142-L150 + // Ref: https://github.com/JetBrains/compose-multiplatform-core/blob/9806d785bf33e25b0dda4853d492b319cf9a819f/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeMultiplatformExtensionImpl.kt#L171-L176 + androidTarget { publishAllLibraryVariants() @@ -165,7 +169,7 @@ kotlin { dependsOn(nonJvmTest) } - val iosAndTvOs by creating { + val iosAndTvOsMain by creating { dependsOn(appleMain.get()) } val iosAndTvOsTest by creating { @@ -173,14 +177,14 @@ kotlin { } iosMain { - dependsOn(iosAndTvOs) + dependsOn(iosAndTvOsMain) } iosTest { dependsOn(iosAndTvOsTest) } tvosMain { - dependsOn(iosAndTvOs) + dependsOn(iosAndTvOsMain) } tvosTest { dependsOn(iosAndTvOsTest) @@ -195,7 +199,7 @@ kotlin { sourceSets.configureEach { languageSettings { - optIn("com.hoc081098.solivagant.navigation.internal.InternalNavigationApi") + optIn("com.hoc081098.solivagant.navigation.InternalNavigationApi") } } } @@ -234,14 +238,26 @@ mavenPublishing { signAllPublications() } -tasks.withType().configureEach { +tasks.withType().configureEach { dokkaSourceSets { configureEach { externalDocumentationLink("https://kotlinlang.org/api/kotlinx.coroutines/") + // TODO: Issue https://github.com/Kotlin/dokka/issues/3368 and https://github.com/Kotlin/dokka/issues/2037 + externalDocumentationLink( + url = "https://hoc081098.github.io/kmp-viewmodel/docs/0.x/API/", + packageListUrl = "https://hoc081098.github.io/kmp-viewmodel/docs/0.x/API/package-list", + ) + + perPackageOption { + // Will match all .internal packages and sub-packages, regardless of module. + matchingRegex.set(""".*\.internal.*""") + suppress.set(true) + } + sourceLink { localDirectory.set(projectDir.resolve("src")) - remoteUrl.set(URL("https://github.com/hoc081098/solivagant/tree/master/viewmodel-compose/src")) + remoteUrl.set(URL("https://github.com/hoc081098/solivagant/tree/master/navigation/src")) remoteLineSuffix.set("#L") } } diff --git a/navigation/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryViewModelStoreOwner.android.kt b/navigation/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryViewModelStoreOwner.android.kt index 2817cb45..0bea94f9 100644 --- a/navigation/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryViewModelStoreOwner.android.kt +++ b/navigation/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryViewModelStoreOwner.android.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.kmp.viewmodel.InternalKmpViewModelApi diff --git a/navigation/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.android.kt b/navigation/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.android.kt index 9e916330..50c49e0a 100644 --- a/navigation/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.android.kt +++ b/navigation/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.android.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import androidx.compose.runtime.Composable diff --git a/navigation/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/savedStateHandleAndroidSupport.android.kt b/navigation/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/savedStateHandleAndroidSupport.android.kt index b87d9a6e..222d7eb3 100644 --- a/navigation/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/savedStateHandleAndroidSupport.android.kt +++ b/navigation/src/androidMain/kotlin/com/hoc081098/solivagant/navigation/internal/savedStateHandleAndroidSupport.android.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import android.annotation.SuppressLint diff --git a/navigation/src/commonJvmMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.commonJvm.kt b/navigation/src/commonJvmMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.commonJvm.kt index 2095ed29..903ce030 100644 --- a/navigation/src/commonJvmMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.commonJvm.kt +++ b/navigation/src/commonJvmMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.commonJvm.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal @Suppress("ACTUAL_WITHOUT_EXPECT") // TODO: https://youtrack.jetbrains.com/issue/KT-37316 diff --git a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavHost.kt b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavHost.kt index bf5b4658..31dbb1ce 100644 --- a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavHost.kt +++ b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/NavHost.kt @@ -1,3 +1,35 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation import androidx.compose.foundation.layout.Box @@ -122,7 +154,7 @@ private fun Show( CompositionLocalProvider( LocalViewModelStoreOwner provides viewModelStoreOwner, - LocalSavedStateHandleFactory provides executor.savedStateHandleFactoryFor(entry.destinationId), + LocalSavedStateHandleFactory provides executor.savedStateHandleFactoryFor(entry.id), LocalLifecycleOwner provides entry.lifecycleOwner, ) { saveableStateHolder.SaveableStateProvider(entry.id.value) { diff --git a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/MultiStack.kt b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/MultiStack.kt index aa9b1e8a..6384363d 100644 --- a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/MultiStack.kt +++ b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/MultiStack.kt @@ -1,3 +1,35 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import androidx.compose.runtime.MutableState @@ -18,7 +50,7 @@ internal class MultiStack( private var startStack: Stack, private var currentStack: Stack, private val destinations: List>, - private val onStackEntryRemoved: (StackEntry.Id) -> Unit, + private val onStackEntryRemoved: (StackEntryId) -> Unit, private val idGenerator: () -> String, ) { private val visibleEntryState: MutableState>> = @@ -35,9 +67,41 @@ internal class MultiStack( private var hostLifecycleState: Lifecycle.State = Lifecycle.State.INITIALIZED + @Suppress("ReturnCount") + fun entryFor(route: T): StackEntry? { + val entry = currentStack.entryFor(route) + if (entry != null) { + return entry + } + + // the root of the default back stack is always on the back stack + if (startStack.rootEntry.route == route) { + @Suppress("UNCHECKED_CAST") + return startStack.rootEntry as StackEntry + } + + return null + } + + @Suppress("ReturnCount") + fun entryFor(id: StackEntryId): StackEntry? { + val entry = currentStack.entryFor(id) + if (entry != null) { + return entry + } + + // the root of the default back stack is always on the back stack + if (startStack.rootEntry.id == id) { + @Suppress("UNCHECKED_CAST") + return startStack.rootEntry as StackEntry + } + + return null + } + @Suppress("ReturnCount") fun entryFor(destinationId: DestinationId): StackEntry? { - val entry = currentStack.entryFor(destinationId) + val entry = currentStack.entryFor(destinationId) if (entry != null) { return entry } @@ -52,7 +116,7 @@ internal class MultiStack( } private fun getBackStack(root: NavRoot): Stack? { - return allStacks.find { it.id == root.destinationId } + return allStacks.find { it.destinationId == root.destinationId } } private fun createBackStack(root: NavRoot): Stack { @@ -79,7 +143,7 @@ internal class MultiStack( } private fun canNavigateBack(): Boolean { - return currentStack.id != startStack.id || !currentStack.isAtRoot + return currentStack.destinationId != startStack.destinationId || !currentStack.isAtRoot } fun push(route: NavRoute) { @@ -94,7 +158,7 @@ internal class MultiStack( fun pop() { if (currentStack.isAtRoot) { - check(currentStack.id != startStack.id) { + check(currentStack.destinationId != startStack.destinationId) { "Can't navigate back from the root of the start back stack" } removeBackStack(currentStack) @@ -119,8 +183,9 @@ internal class MultiStack( fun push(root: NavRoot, clearTargetStack: Boolean) { val stack = getBackStack(root) + currentStack = if (stack != null) { - check(currentStack.id != stack.id) { + check(currentStack.destinationId != stack.destinationId) { "$root is already the current stack" } if (clearTargetStack) { @@ -132,7 +197,7 @@ internal class MultiStack( } else { createBackStack(root) } - if (stack?.id == startStack.id) { + if (stack?.destinationId == startStack.destinationId) { startStack = currentStack } updateVisibleDestinations() @@ -140,8 +205,8 @@ internal class MultiStack( fun resetToRoot(root: NavRoot) { when (root.destinationId) { - startStack.id -> { - if (currentStack.id != startStack.id) { + startStack.destinationId -> { + if (currentStack.destinationId != startStack.destinationId) { removeBackStack(currentStack) } removeBackStack(startStack) @@ -150,7 +215,7 @@ internal class MultiStack( currentStack = newStack } - currentStack.id -> { + currentStack.destinationId -> { removeBackStack(currentStack) val newStack = createBackStack(root) currentStack = newStack @@ -184,7 +249,7 @@ internal class MultiStack( fun saveState(): Map { return mapOf( SAVED_STATE_ALL_STACKS to ArrayList(allStacks.map { it.saveState() }), - SAVED_STATE_CURRENT_STACK to currentStack.id, + SAVED_STATE_CURRENT_STACK to currentStack.destinationId, ) } @@ -197,7 +262,7 @@ internal class MultiStack( fun createWith( root: NavRoot, destinations: List>, - onStackEntryRemoved: (StackEntry.Id) -> Unit, + onStackEntryRemoved: (StackEntryId) -> Unit, getHostLifecycleState: () -> Lifecycle.State, idGenerator: () -> String = { uuid4().toString() }, ): MultiStack { @@ -224,7 +289,7 @@ internal class MultiStack( bundle: Map, destinations: List>, getHostLifecycleState: () -> Lifecycle.State, - onStackEntryRemoved: (StackEntry.Id) -> Unit, + onStackEntryRemoved: (StackEntryId) -> Unit, idGenerator: () -> String = { uuid4().toString() }, ): MultiStack { @Suppress("UNCHECKED_CAST") @@ -239,8 +304,8 @@ internal class MultiStack( idGenerator = idGenerator, ) } - val startStack = allStacks.first { it.id == root.destinationId } - val currentStack = allStacks.first { it.id.route == currentStackId.route } + val startStack = allStacks.first { it.destinationId == root.destinationId } + val currentStack = allStacks.first { it.destinationId.route == currentStackId.route } return MultiStack( allStacks = allStacks, startStack = startStack, diff --git a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/MultiStackNavigationExecutor.kt b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/MultiStackNavigationExecutor.kt index ac7a9456..29c6bbae 100644 --- a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/MultiStackNavigationExecutor.kt +++ b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/MultiStackNavigationExecutor.kt @@ -1,3 +1,35 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import androidx.compose.runtime.State @@ -72,38 +104,49 @@ internal class MultiStackNavigationExecutor( onRootChanged(root) } - override fun routeFor(destinationId: DestinationId): T { - return entryFor(destinationId).route - } + @DelicateNavigationApi + override fun stackEntryIdFor(route: BaseRoute): StackEntryId = entryFor(route).id + + @DelicateNavigationApi + @Deprecated("Should not use destinationId directly, use route instead.") + override fun stackEntryIdFor(destinationId: DestinationId<*>): StackEntryId = entryFor(destinationId).id - override fun savedStateHandleFor(destinationId: DestinationId): SavedStateHandle { - val entry = entryFor(destinationId) + override fun savedStateHandleFor(id: StackEntryId): SavedStateHandle { + val entry = entryFor(id) return viewModel.provideSavedStateHandle(entry.id, entry.route) } - override fun savedStateHandleFactoryFor(destinationId: DestinationId): SavedStateHandleFactory { - val entry = entryFor(destinationId) + override fun savedStateHandleFactoryFor(id: StackEntryId): SavedStateHandleFactory { + val entry = entryFor(id) return viewModel.provideSavedStateHandleFactory(entry.id, entry.route) } - override fun storeFor(destinationId: DestinationId): NavigationExecutor.Store { - val entry = entryFor(destinationId) - return storeFor(entry.id) + override fun storeFor(id: StackEntryId): NavigationExecutor.Store { + val entry = entryFor(id) + return viewModel.provideStore(entry.id) } - override fun extra(destinationId: DestinationId): Serializable { - val entry = entryFor(destinationId) + override fun extra(id: StackEntryId): Serializable { + val entry = entryFor(id) return entry.destination.extra!! } - internal fun storeFor(entryId: StackEntry.Id): NavigationExecutor.Store { - return viewModel.provideStore(entryId) + //region Find StackEntry by id or route or destinationId + private fun entryFor(id: StackEntryId): StackEntry { + return stack.entryFor(id) + ?: error("Route with id=$id not found on back stack") + } + + private fun entryFor(route: T): StackEntry { + return stack.entryFor(route) + ?: error("Route $route not found on back stack") } private fun entryFor(destinationId: DestinationId): StackEntry { return stack.entryFor(destinationId) - ?: error("Route $destinationId not found on back stack") + ?: error("Route with destinationId=$destinationId not found on back stack") } + //endregion fun setLifecycleOwner(lifecycleOwner: LifecycleOwner?) { _lifecycleOwner.value = lifecycleOwner diff --git a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/MultiStackNavigationExecutorBuilder.kt b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/MultiStackNavigationExecutorBuilder.kt index abececab..c7799e0f 100644 --- a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/MultiStackNavigationExecutorBuilder.kt +++ b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/MultiStackNavigationExecutorBuilder.kt @@ -1,3 +1,35 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import androidx.compose.runtime.Composable diff --git a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/Stack.kt b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/Stack.kt index ccb5d4be..b8539bff 100644 --- a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/Stack.kt +++ b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/Stack.kt @@ -1,3 +1,35 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.benasher44.uuid.uuid4 @@ -10,10 +42,11 @@ import com.hoc081098.solivagant.navigation.ScreenDestination import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.adapters.ImmutableListAdapter +@Suppress("TooManyFunctions") internal class Stack private constructor( initialStack: List>, private val destinations: List>, - private val onStackEntryRemoved: (StackEntry.Id) -> Unit, + private val onStackEntryRemoved: (StackEntryId) -> Unit, private val getHostLifecycleState: () -> Lifecycle.State, private val idGenerator: () -> String, ) { @@ -22,10 +55,20 @@ internal class Stack private constructor( it.addAll(initialStack) } - val id: DestinationId<*> get() = rootEntry.destinationId + val destinationId: DestinationId<*> get() = rootEntry.destinationId val rootEntry: StackEntry<*> get() = stack.first() val isAtRoot: Boolean get() = !stack.last().removable + @Suppress("UNCHECKED_CAST") + fun entryFor(id: StackEntryId): StackEntry? { + return stack.findLast { it.id == id } as StackEntry? + } + + @Suppress("UNCHECKED_CAST") + fun entryFor(route: T): StackEntry? { + return stack.findLast { it.route == route } as StackEntry? + } + @Suppress("UNCHECKED_CAST") fun entryFor(destinationId: DestinationId): StackEntry? { return stack.findLast { it.destinationId == destinationId } as StackEntry? @@ -117,7 +160,7 @@ internal class Stack private constructor( fun createWith( root: NavRoot, destinations: List>, - onStackEntryRemoved: (StackEntry.Id) -> Unit, + onStackEntryRemoved: (StackEntryId) -> Unit, getHostLifecycleState: () -> Lifecycle.State, idGenerator: () -> String = { uuid4().toString() }, ): Stack { @@ -139,7 +182,7 @@ internal class Stack private constructor( fun fromState( bundle: Map>, destinations: List>, - onStackEntryRemoved: (StackEntry.Id) -> Unit, + onStackEntryRemoved: (StackEntryId) -> Unit, getHostLifecycleState: () -> Lifecycle.State, idGenerator: () -> String = { uuid4().toString() }, ): Stack { diff --git a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntry.kt b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntry.kt index caa6fca7..23ccf974 100644 --- a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntry.kt +++ b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntry.kt @@ -1,3 +1,35 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import androidx.compose.runtime.Immutable @@ -7,12 +39,11 @@ import com.hoc081098.solivagant.navigation.ContentDestination import com.hoc081098.solivagant.navigation.NavRoot import com.hoc081098.solivagant.navigation.NavRoute import dev.drewhamilton.poko.Poko -import kotlin.jvm.JvmInline @Poko @Immutable internal class StackEntry private constructor( - val id: Id, + val id: StackEntryId, val route: T, val destination: ContentDestination, val lifecycleOwner: StackEntryLifecycleOwner, @@ -28,9 +59,6 @@ internal class StackEntry private constructor( is NavRoot -> false } - @JvmInline - value class Id(val value: String) - companion object { inline fun create( route: T, @@ -46,7 +74,7 @@ internal class StackEntry private constructor( ) return StackEntry( - id = Id(idGenerator()), + id = StackEntryId(idGenerator()), route = route, destination = destination, lifecycleOwner = StackEntryLifecycleOwner( diff --git a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryLifecycleOwner.kt b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryLifecycleOwner.kt index 55b937ee..743b3221 100644 --- a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryLifecycleOwner.kt +++ b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryLifecycleOwner.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.solivagant.lifecycle.Lifecycle @@ -8,6 +24,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +@Suppress("TooManyFunctions") private class StackEntryLifecycle : Lifecycle { private val _currentStateFlow = MutableStateFlow(State.INITIALIZED) private var _state: State = _currentStateFlow.value diff --git a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryViewModelStoreOwner.kt b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryViewModelStoreOwner.kt index e6023efe..783e7d52 100644 --- a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryViewModelStoreOwner.kt +++ b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryViewModelStoreOwner.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.kmp.viewmodel.ViewModelStore diff --git a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StoreViewModel.kt b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StoreViewModel.kt index 8a03f3a2..193cd0a2 100644 --- a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StoreViewModel.kt +++ b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/StoreViewModel.kt @@ -1,3 +1,35 @@ +/* + * Copyright 2021 Freeletics GmbH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.kmp.viewmodel.SavedStateHandle @@ -12,9 +44,9 @@ import com.hoc081098.solivagant.navigation.NavRoot internal class StoreViewModel( internal val globalSavedStateHandle: SavedStateHandle, ) : ViewModel() { - private val stores = mutableMapOf() - private val savedStateHandles = mutableMapOf() - private val savedStateHandleFactories = mutableMapOf() + private val stores = mutableMapOf() + private val savedStateHandles = mutableMapOf() + private val savedStateHandleFactories = mutableMapOf() private var stack: MultiStack? = null private var executor: MultiStackNavigationExecutor? = null @@ -25,24 +57,24 @@ internal class StoreViewModel( } } - internal fun provideStore(id: StackEntry.Id): NavigationExecutor.Store { + internal fun provideStore(id: StackEntryId): NavigationExecutor.Store { return stores.getOrPut(id) { NavigationExecutorStore() } } - internal fun provideSavedStateHandle(id: StackEntry.Id, route: BaseRoute): SavedStateHandle { + internal fun provideSavedStateHandle(id: StackEntryId, route: BaseRoute): SavedStateHandle { return savedStateHandles.getOrPut(id) { createSavedStateHandleAndSetSavedStateProvider(id.value, globalSavedStateHandle) .apply { this[EXTRA_ROUTE] = route } } } - internal fun provideSavedStateHandleFactory(id: StackEntry.Id, route: BaseRoute): SavedStateHandleFactory { + internal fun provideSavedStateHandleFactory(id: StackEntryId, route: BaseRoute): SavedStateHandleFactory { return savedStateHandleFactories.getOrPut(id) { SavedStateHandleFactory { provideSavedStateHandle(id, route) } } } - private fun removeEntry(id: StackEntry.Id) { + private fun removeEntry(id: StackEntryId) { val store = stores.remove(id) store?.close() diff --git a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.kt b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.kt index cec92e56..f1dbdbb0 100644 --- a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.kt +++ b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal internal expect class WeakReference constructor(referred: T) { diff --git a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.kt b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.kt index b7a95809..1ecd0cf3 100644 --- a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.kt +++ b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import androidx.compose.runtime.Composable diff --git a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/savedStateHandleAndroidSupport.kt b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/savedStateHandleAndroidSupport.kt index 8bbd9750..e9924228 100644 --- a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/savedStateHandleAndroidSupport.kt +++ b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/internal/savedStateHandleAndroidSupport.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.kmp.viewmodel.SavedStateHandle diff --git a/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/rememberCloseableOnRoute.kt b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/rememberCloseableOnRoute.kt new file mode 100644 index 00000000..9162486e --- /dev/null +++ b/navigation/src/commonMain/kotlin/com/hoc081098/solivagant/navigation/rememberCloseableOnRoute.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hoc081098.solivagant.navigation + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisallowComposableCalls +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState +import com.hoc081098.kmp.viewmodel.Closeable +import com.hoc081098.solivagant.navigation.internal.DelicateNavigationApi +import kotlin.reflect.KClass + +/** + * Remember a [Closeable] on the route. + * + * The [Closeable] will be created by [factory] once at the first access. + * It will be closed when the [route] is removed from the back stack. + */ +@OptIn(DelicateNavigationApi::class) +@Composable +public fun rememberCloseableOnRoute( + route: BaseRoute, + type: KClass, + factory: () -> T, +): T { + val executor = LocalNavigationExecutor.current + val currentFactory by rememberUpdatedState(factory) + + return remember(executor, route) { + // Don't use getOrCreate(key = type, factory = currentFactory) because it can refer to the old factory. + // `{ currentFactory() }` is the right way. + executor + .storeFor(executor.stackEntryIdFor(route)) + .getOrCreate(key = type) { currentFactory() } + } +} + +/** + * Remember a [Closeable] on the route. + * + * The [Closeable] will be created by [factory] once at the first access. + * It will be closed when the [route] is removed from the back stack. + */ +@Composable +public inline fun rememberCloseableOnRoute( + route: BaseRoute, + noinline factory: @DisallowComposableCalls () -> T, +): T = rememberCloseableOnRoute(route, T::class, factory) diff --git a/navigation/src/iosAndTvOs/kotlin/com/hoc081098/solivagant/navigation/AppLifecycleOwner.kt b/navigation/src/iosAndTvOs/kotlin/com/hoc081098/solivagant/navigation/AppLifecycleOwner.kt deleted file mode 100644 index 38a87792..00000000 --- a/navigation/src/iosAndTvOs/kotlin/com/hoc081098/solivagant/navigation/AppLifecycleOwner.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.hoc081098.solivagant.navigation - -import com.hoc081098.solivagant.lifecycle.LifecycleOwner -import com.hoc081098.solivagant.navigation.internal.AppLifecycleOwnerImpl - -@Suppress("FunctionName") // Factory function -public fun AppLifecycleOwner(): LifecycleOwner = AppLifecycleOwnerImpl() diff --git a/navigation/src/iosAndTvOsMain/kotlin/com/hoc081098/solivagant/navigation/AppLifecycleOwner.kt b/navigation/src/iosAndTvOsMain/kotlin/com/hoc081098/solivagant/navigation/AppLifecycleOwner.kt new file mode 100644 index 00000000..642cef14 --- /dev/null +++ b/navigation/src/iosAndTvOsMain/kotlin/com/hoc081098/solivagant/navigation/AppLifecycleOwner.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hoc081098.solivagant.navigation + +import com.hoc081098.solivagant.lifecycle.LifecycleOwner +import com.hoc081098.solivagant.navigation.internal.AppLifecycleOwnerImpl + +@Suppress("FunctionName") // Factory function +public fun AppLifecycleOwner(): LifecycleOwner = AppLifecycleOwnerImpl() diff --git a/navigation/src/iosAndTvOs/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.iosAndTvOs.kt b/navigation/src/iosAndTvOsMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.iosAndTvOs.kt similarity index 92% rename from navigation/src/iosAndTvOs/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.iosAndTvOs.kt rename to navigation/src/iosAndTvOsMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.iosAndTvOs.kt index e9eacbc4..d2437f98 100644 --- a/navigation/src/iosAndTvOs/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.iosAndTvOs.kt +++ b/navigation/src/iosAndTvOsMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.iosAndTvOs.kt @@ -1,3 +1,20 @@ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import androidx.compose.runtime.Composable diff --git a/navigation/src/jsMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.js.kt b/navigation/src/jsMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.js.kt index ac193be4..2ecc8af2 100644 --- a/navigation/src/jsMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.js.kt +++ b/navigation/src/jsMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.js.kt @@ -1,3 +1,20 @@ + +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal internal actual class WeakReference actual constructor(referred: T) { diff --git a/navigation/src/jsMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.js.kt b/navigation/src/jsMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.js.kt index edec0a99..e2d12411 100644 --- a/navigation/src/jsMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.js.kt +++ b/navigation/src/jsMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.js.kt @@ -1,16 +1,29 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import com.hoc081098.solivagant.lifecycle.Lifecycle import com.hoc081098.solivagant.lifecycle.LifecycleOwner import com.hoc081098.solivagant.lifecycle.LifecycleRegistry -private class DefaultJsLifecycleOwner : LifecycleOwner { +private object DefaultJsLifecycleOwner : LifecycleOwner { override val lifecycle: Lifecycle = LifecycleRegistry(initialState = Lifecycle.State.RESUMED) } @Composable -internal actual fun rememberPlatformLifecycleOwner(): LifecycleOwner { - return remember { DefaultJsLifecycleOwner() } -} +internal actual fun rememberPlatformLifecycleOwner(): LifecycleOwner = DefaultJsLifecycleOwner diff --git a/navigation/src/jvmMain/kotlin/com/hoc081098/solivagant/navigation/LifecycleControllerEffect.kt b/navigation/src/jvmMain/kotlin/com/hoc081098/solivagant/navigation/LifecycleControllerEffect.kt new file mode 100644 index 00000000..b84963ad --- /dev/null +++ b/navigation/src/jvmMain/kotlin/com/hoc081098/solivagant/navigation/LifecycleControllerEffect.kt @@ -0,0 +1,162 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hoc081098.solivagant.navigation + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.runtime.snapshotFlow +import androidx.compose.ui.window.WindowState +import com.hoc081098.solivagant.lifecycle.Lifecycle +import com.hoc081098.solivagant.lifecycle.LifecycleDestroyedException +import com.hoc081098.solivagant.lifecycle.LifecycleRegistry +import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch + +@Composable +public fun LifecycleControllerEffect( + lifecycleRegistry: LifecycleRegistry, + windowState: WindowState, +) { + val leavedComposition = remember(lifecycleRegistry) { MutableStateFlow(false) } + + LaunchedEffect(lifecycleRegistry, windowState) { + // Cancel this effect when the composition leaves + launch(start = CoroutineStart.UNDISPATCHED) { + leavedComposition.first { it } + this@LaunchedEffect.cancel() + } + + // Wait the first state is not INITIALIZED + when (lifecycleRegistry.currentStateFlow.first { it != Lifecycle.State.INITIALIZED }) { + Lifecycle.State.DESTROYED -> + throw LifecycleDestroyedException() + + Lifecycle.State.INITIALIZED -> + error("Can not happen") + + Lifecycle.State.CREATED, + Lifecycle.State.STARTED, + Lifecycle.State.RESUMED, + -> Unit + } + + snapshotFlow { windowState.isMinimized } + .collect { isMinimized -> + if ( + lifecycleRegistry.currentState == Lifecycle.State.DESTROYED || + leavedComposition.value + ) { + throw LifecycleDestroyedException() + } + + if (isMinimized) { + moveToStopped(lifecycleRegistry) + } else { + moveToResumed(lifecycleRegistry) + } + } + } + + DisposableEffect(lifecycleRegistry) { + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_CREATE) + + onDispose { + leavedComposition.value = true + moveToDestroyed(lifecycleRegistry) + } + } +} + +private fun moveToDestroyed(lifecycleRegistry: LifecycleRegistry) { + when (lifecycleRegistry.currentState) { + Lifecycle.State.INITIALIZED -> { + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_CREATE) + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_DESTROY) + } + + Lifecycle.State.CREATED -> { + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_DESTROY) + } + + Lifecycle.State.STARTED -> { + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_STOP) + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_DESTROY) + } + + Lifecycle.State.RESUMED -> { + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_PAUSE) + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_STOP) + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_DESTROY) + } + + Lifecycle.State.DESTROYED -> + Unit + } +} + +private fun moveToResumed(lifecycleRegistry: LifecycleRegistry) { + when (lifecycleRegistry.currentState) { + Lifecycle.State.INITIALIZED -> { + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_CREATE) + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_START) + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_RESUME) + } + + Lifecycle.State.CREATED -> { + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_START) + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_RESUME) + } + + Lifecycle.State.STARTED -> { + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_RESUME) + } + + Lifecycle.State.RESUMED -> + Unit + + Lifecycle.State.DESTROYED -> + throw LifecycleDestroyedException() + } +} + +private fun moveToStopped(lifecycleRegistry: LifecycleRegistry) { + when (lifecycleRegistry.currentState) { + Lifecycle.State.INITIALIZED -> { + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_CREATE) + } + + Lifecycle.State.CREATED -> + Unit + + Lifecycle.State.STARTED -> { + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_STOP) + } + + Lifecycle.State.RESUMED -> { + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_PAUSE) + lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_STOP) + } + + Lifecycle.State.DESTROYED -> + throw LifecycleDestroyedException() + } +} diff --git a/navigation/src/jvmMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.jvm.kt b/navigation/src/jvmMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.jvm.kt index 0de63636..87c61156 100644 --- a/navigation/src/jvmMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.jvm.kt +++ b/navigation/src/jvmMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.jvm.kt @@ -1,158 +1,29 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.remember -import androidx.compose.runtime.snapshotFlow -import androidx.compose.ui.window.WindowState import com.hoc081098.solivagant.lifecycle.Lifecycle import com.hoc081098.solivagant.lifecycle.LifecycleOwner import com.hoc081098.solivagant.lifecycle.LifecycleRegistry -import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.cancel -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.launch - -private class DestroyedLifecycleException : CancellationException("Lifecycle was destroyed") - -@Composable -public fun LifecycleControllerEffect(lifecycleRegistry: LifecycleRegistry, windowState: WindowState) { - val leavedComposition = remember(lifecycleRegistry) { MutableStateFlow(false) } - - LaunchedEffect(lifecycleRegistry, windowState) { - // Cancel this effect when the composition leaves - launch(start = CoroutineStart.UNDISPATCHED) { - leavedComposition - .filter { it } - .collect { this@LaunchedEffect.cancel() } - } - - // Wait the first state is not INITIALIZED - when (lifecycleRegistry.currentStateFlow.first { it != Lifecycle.State.INITIALIZED }) { - Lifecycle.State.DESTROYED -> - throw DestroyedLifecycleException() - - Lifecycle.State.INITIALIZED -> - error("Can not happen") - - Lifecycle.State.CREATED, - Lifecycle.State.STARTED, - Lifecycle.State.RESUMED, - -> - Unit - } - - snapshotFlow { windowState.isMinimized } - .collect { isMinimized -> - if ( - lifecycleRegistry.currentState == Lifecycle.State.DESTROYED || - leavedComposition.value - ) { - throw DestroyedLifecycleException() - } - - if (isMinimized) { - moveToStop(lifecycleRegistry) - } else { - moveToResumed(lifecycleRegistry) - } - } - } - - DisposableEffect(lifecycleRegistry) { - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_CREATE) - - onDispose { - leavedComposition.value = true - moveToDestroyed(lifecycleRegistry) - } - } -} - -private fun moveToDestroyed(lifecycleRegistry: LifecycleRegistry) { - when (lifecycleRegistry.currentState) { - Lifecycle.State.INITIALIZED -> { - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_CREATE) - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_DESTROY) - } - - Lifecycle.State.CREATED -> { - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_DESTROY) - } - - Lifecycle.State.STARTED -> { - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_STOP) - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_DESTROY) - } - Lifecycle.State.RESUMED -> { - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_PAUSE) - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_STOP) - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_DESTROY) - } - - Lifecycle.State.DESTROYED -> - Unit - } -} - -private fun moveToResumed(lifecycleRegistry: LifecycleRegistry) { - when (lifecycleRegistry.currentState) { - Lifecycle.State.INITIALIZED -> { - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_CREATE) - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_START) - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_RESUME) - } - - Lifecycle.State.CREATED -> { - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_START) - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_RESUME) - } - - Lifecycle.State.STARTED -> { - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_RESUME) - } - - Lifecycle.State.RESUMED -> - Unit - - Lifecycle.State.DESTROYED -> - throw DestroyedLifecycleException() - } -} - -private fun moveToStop(lifecycleRegistry: LifecycleRegistry) { - when (lifecycleRegistry.currentState) { - Lifecycle.State.INITIALIZED -> { - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_CREATE) - } - - Lifecycle.State.CREATED -> - Unit - - Lifecycle.State.STARTED -> { - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_STOP) - } - - Lifecycle.State.RESUMED -> { - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_PAUSE) - lifecycleRegistry.onStateChanged(Lifecycle.Event.ON_STOP) - } - - Lifecycle.State.DESTROYED -> - throw DestroyedLifecycleException() - } -} - -private class DefaultDesktopLifecycleOwner : LifecycleOwner { +private object DefaultDesktopLifecycleOwner : LifecycleOwner { override val lifecycle: Lifecycle = LifecycleRegistry(initialState = Lifecycle.State.RESUMED) } @Composable -internal actual fun rememberPlatformLifecycleOwner(): LifecycleOwner { - return remember { DefaultDesktopLifecycleOwner() } -} +internal actual fun rememberPlatformLifecycleOwner(): LifecycleOwner = DefaultDesktopLifecycleOwner diff --git a/navigation/src/macosMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.macos.kt b/navigation/src/macosMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.macos.kt index 9d0f66d8..0a016c59 100644 --- a/navigation/src/macosMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.macos.kt +++ b/navigation/src/macosMain/kotlin/com/hoc081098/solivagant/navigation/internal/rememberPlatformLifecycleOwner.macos.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import androidx.compose.runtime.Composable diff --git a/navigation/src/nativeMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.native.kt b/navigation/src/nativeMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.native.kt index fe388e6a..2fb810ad 100644 --- a/navigation/src/nativeMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.native.kt +++ b/navigation/src/nativeMain/kotlin/com/hoc081098/solivagant/navigation/internal/WeakReference.native.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import kotlin.experimental.ExperimentalNativeApi diff --git a/navigation/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/SavedStateSupport.kt b/navigation/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/SavedStateSupport.kt index 331cb039..3d9d4494 100644 --- a/navigation/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/SavedStateSupport.kt +++ b/navigation/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/SavedStateSupport.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation import androidx.compose.runtime.saveable.SaveableStateRegistry diff --git a/navigation/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryViewModelStoreOwner.nonAndroid.kt b/navigation/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryViewModelStoreOwner.nonAndroid.kt index b8a60fc2..a1e675cd 100644 --- a/navigation/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryViewModelStoreOwner.nonAndroid.kt +++ b/navigation/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/StackEntryViewModelStoreOwner.nonAndroid.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.kmp.viewmodel.ViewModelStore diff --git a/navigation/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/savedStateHandleAndroidSupport.nonAndroid.kt b/navigation/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/savedStateHandleAndroidSupport.nonAndroid.kt index 3944b584..7aa9f28b 100644 --- a/navigation/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/savedStateHandleAndroidSupport.nonAndroid.kt +++ b/navigation/src/nonAndroidMain/kotlin/com/hoc081098/solivagant/navigation/internal/savedStateHandleAndroidSupport.nonAndroid.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Petrus Nguyễn Thái Học + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hoc081098.solivagant.navigation.internal import com.hoc081098.kmp.viewmodel.SavedStateHandle diff --git a/samples/sample/desktop/src/commonMain/kotlin/com/hoc081098/solivagant/sample/main.kt b/samples/sample/desktop/src/commonMain/kotlin/com/hoc081098/solivagant/sample/main.kt index 3fbe0bb8..7efeb60c 100644 --- a/samples/sample/desktop/src/commonMain/kotlin/com/hoc081098/solivagant/sample/main.kt +++ b/samples/sample/desktop/src/commonMain/kotlin/com/hoc081098/solivagant/sample/main.kt @@ -14,8 +14,8 @@ import com.hoc081098.kmp.viewmodel.compose.LocalViewModelStoreOwner import com.hoc081098.solivagant.lifecycle.LifecycleOwnerProvider import com.hoc081098.solivagant.lifecycle.LifecycleRegistry import com.hoc081098.solivagant.lifecycle.rememberLifecycleOwner +import com.hoc081098.solivagant.navigation.LifecycleControllerEffect import com.hoc081098.solivagant.navigation.SavedStateSupport -import com.hoc081098.solivagant.navigation.internal.LifecycleControllerEffect import com.hoc081098.solivagant.sample.common.OnLifecycleEventWithBuilder import io.github.aakira.napier.Napier diff --git a/samples/sample/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/products/ProductsScreen.kt b/samples/sample/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/products/ProductsScreen.kt index 0e500de7..d84b3309 100644 --- a/samples/sample/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/products/ProductsScreen.kt +++ b/samples/sample/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/products/ProductsScreen.kt @@ -1,10 +1,11 @@ package com.hoc081098.solivagant.sample.products +import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.pullrefresh.rememberPullRefreshState +import androidx.compose.material3.Surface import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -19,30 +20,30 @@ import com.hoc081098.solivagant.sample.common.ErrorMessageAndRetryButton import com.hoc081098.solivagant.sample.common.LoadingIndicator import com.hoc081098.solivagant.sample.common.OnLifecycleEventWithBuilder import com.hoc081098.solivagant.sample.common.PlatformToastManager +import com.hoc081098.solivagant.sample.common.ProductItemUi import com.hoc081098.solivagant.sample.common.ProductItemsList import io.github.aakira.napier.Napier import kotlinx.coroutines.launch -@OptIn(ExperimentalMaterialApi::class) @Suppress("ReturnCount", "ModifierReused", "LongMethod") @Composable fun ProductsScreen( modifier: Modifier = Modifier, viewModel: ProductsViewModel = koinKmpViewModel(), ) { - DisposableEffect(viewModel) { - if (!viewModel.stateFlow.value.hasContent) { - viewModel.dispatch(ProductsAction.Load) + val state by viewModel.stateFlow.collectAsStateWithLifecycle() + val dispatch: (ProductsAction) -> Unit = remember(viewModel) { viewModel::dispatch } + + OnLifecycleEventWithBuilder(dispatch) { + onResume { + if (!state.hasContent) { + dispatch(ProductsAction.Load) + } } - onDispose { } - } - OnLifecycleEventWithBuilder { onEach { event -> Napier.d("[ProductsScreen] event=$event") } } - val state by viewModel.stateFlow.collectAsStateWithLifecycle() - val scope = rememberCoroutineScope() val lazyListState = rememberLazyListState() val currentLazyListState by rememberUpdatedState(lazyListState) @@ -67,33 +68,55 @@ fun ProductsScreen( } viewModel.eventFlow.CollectWithLifecycleEffect(collector = eventHandler) - if (state.isLoading) { - LoadingIndicator(modifier = modifier) - return - } - - state.error?.let { error -> - ErrorMessageAndRetryButton( - modifier = modifier, - onRetry = { viewModel.dispatch(ProductsAction.Load) }, - errorMessage = error.message ?: "Unknown error", - ) - return - } - - val products = state.products.ifEmpty { - EmptyProducts(modifier = modifier) - return - } - ProductItemsList( + ListContent( modifier = modifier, - products = products, - pullRefreshState = rememberPullRefreshState( - refreshing = state.isRefreshing, - onRefresh = { viewModel.dispatch(ProductsAction.Refresh) }, - ), - isRefreshing = state.isRefreshing, + state = state, lazyListState = lazyListState, - onItemClick = { viewModel.dispatch(ProductsAction.NavigateToProductDetail(it.id)) }, + onRetry = { dispatch(ProductsAction.Load) }, + onRefresh = { dispatch(ProductsAction.Refresh) }, + onItemClick = { dispatch(ProductsAction.NavigateToProductDetail(it.id)) }, ) } + +@OptIn(ExperimentalMaterialApi::class) +@Composable +private fun ListContent( + state: ProductsState, + onItemClick: (ProductItemUi) -> Unit, + onRetry: () -> Unit, + onRefresh: () -> Unit, + modifier: Modifier = Modifier, + lazyListState: LazyListState = rememberLazyListState(), +) { + Surface(modifier = modifier) { + when { + state.isLoading -> { + LoadingIndicator() + } + + state.error != null -> { + ErrorMessageAndRetryButton( + onRetry = onRetry, + errorMessage = state.error?.message ?: "Unknown error", + ) + } + + state.products.isEmpty() -> { + EmptyProducts() + } + + else -> { + ProductItemsList( + products = state.products, + pullRefreshState = rememberPullRefreshState( + refreshing = state.isRefreshing, + onRefresh = onRefresh, + ), + isRefreshing = state.isRefreshing, + lazyListState = lazyListState, + onItemClick = onItemClick, + ) + } + } + } +} diff --git a/samples/sample/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/search_products/SearchProductsScreen.kt b/samples/sample/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/search_products/SearchProductsScreen.kt index 36f85b09..fdf81381 100644 --- a/samples/sample/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/search_products/SearchProductsScreen.kt +++ b/samples/sample/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/search_products/SearchProductsScreen.kt @@ -91,34 +91,31 @@ private fun ListContent( onItemClick: (ProductItemUi) -> Unit, modifier: Modifier = Modifier, ) { - if (state.isLoading) { - LoadingIndicator( - modifier = modifier, - ) - return - } + when { + state.isLoading -> { + LoadingIndicator(modifier = modifier) + } - state.error?.let { error -> - ErrorMessageAndRetryButton( - modifier = modifier, - onRetry = { }, - errorMessage = error.message ?: "Unknown error", - ) - return - } + state.error != null -> { + ErrorMessageAndRetryButton( + modifier = modifier, + onRetry = { }, + errorMessage = state.error.message ?: "Unknown error", + ) + } - val products = state.products.ifEmpty { - EmptyProducts( - modifier = modifier, - ) - return - } + state.products.isEmpty() -> { + EmptyProducts(modifier = modifier) + } - ProductItemsList( - modifier = Modifier.fillMaxSize(), - products = products, - isRefreshing = false, - pullRefreshState = null, - onItemClick = onItemClick, - ) + else -> { + ProductItemsList( + modifier = modifier.fillMaxSize(), + products = state.products, + isRefreshing = false, + pullRefreshState = null, + onItemClick = onItemClick, + ) + } + } } diff --git a/samples/simple/desktop/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/main.kt b/samples/simple/desktop/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/main.kt index ccb4a24b..ee75346c 100644 --- a/samples/simple/desktop/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/main.kt +++ b/samples/simple/desktop/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/main.kt @@ -16,8 +16,8 @@ import com.hoc081098.solivagant.lifecycle.LifecycleRegistry import com.hoc081098.solivagant.lifecycle.LocalLifecycleOwner import com.hoc081098.solivagant.lifecycle.compose.currentStateAsState import com.hoc081098.solivagant.lifecycle.rememberLifecycleOwner +import com.hoc081098.solivagant.navigation.LifecycleControllerEffect import com.hoc081098.solivagant.navigation.SavedStateSupport -import com.hoc081098.solivagant.navigation.internal.LifecycleControllerEffect fun main() { startKoinCommon() diff --git a/samples/simple/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/ui/home/profile/ProfileTab.kt b/samples/simple/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/ui/home/profile/ProfileTab.kt index e0711222..7f942811 100644 --- a/samples/simple/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/ui/home/profile/ProfileTab.kt +++ b/samples/simple/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/ui/home/profile/ProfileTab.kt @@ -31,7 +31,10 @@ import org.koin.core.parameter.parametersOf internal fun ProfileTab( modifier: Modifier = Modifier, viewModel: ProfileTabViewModel = koinKmpViewModel( - parameters = { parametersOf(1998, "hoc081098") }, + parameters = { + @Suppress("MagicNumber") + parametersOf(1998, "hoc081098") + }, ), ) { var savableCount by rememberSaveable { mutableIntStateOf(0) } diff --git a/samples/simple/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/ui/login/LoginScreen.kt b/samples/simple/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/ui/login/LoginScreen.kt index 20773f73..8023eb83 100644 --- a/samples/simple/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/ui/login/LoginScreen.kt +++ b/samples/simple/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/ui/login/LoginScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember @@ -21,14 +22,28 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import com.hoc081098.kmp.viewmodel.Closeable import com.hoc081098.kmp.viewmodel.koin.compose.koinKmpViewModel import com.hoc081098.solivagant.lifecycle.LocalLifecycleOwner import com.hoc081098.solivagant.lifecycle.compose.collectAsStateWithLifecycle import com.hoc081098.solivagant.lifecycle.compose.currentStateAsState +import com.hoc081098.solivagant.navigation.rememberCloseableOnRoute import com.hoc081098.solivagant.sample.simple.common.debugDescription +import io.github.aakira.napier.Napier + +private class LoginScreenDemoCloseable : Closeable { + init { + Napier.d("$debugDescription::init") + } + + fun doSomething() = Napier.d("$debugDescription::doSomething") + + override fun close() = Napier.d("$debugDescription::close") +} @Composable internal fun LoginScreen( + route: LoginScreenRoute, modifier: Modifier = Modifier, viewModel: LoginViewModel = koinKmpViewModel(), ) { @@ -36,6 +51,12 @@ internal fun LoginScreen( val savedStateHandleCount by viewModel.countStateFlow.collectAsStateWithLifecycle() val lifecycleState by LocalLifecycleOwner.current.lifecycle.currentStateAsState() + val loginScreenDemoCloseable = rememberCloseableOnRoute( + route = route, + factory = ::LoginScreenDemoCloseable, + ) + SideEffect { loginScreenDemoCloseable.doSomething() } + Surface( modifier = modifier.fillMaxSize(), color = Color.Green.copy(alpha = 0.2f), diff --git a/samples/simple/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/ui/login/LoginScreenRoute.kt b/samples/simple/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/ui/login/LoginScreenRoute.kt index e3927e24..99566e5d 100644 --- a/samples/simple/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/ui/login/LoginScreenRoute.kt +++ b/samples/simple/shared/src/commonMain/kotlin/com/hoc081098/solivagant/sample/simple/ui/login/LoginScreenRoute.kt @@ -12,4 +12,4 @@ import kotlin.jvm.JvmField data object LoginScreenRoute : NavRoot @JvmField -val LoginScreenDestination: NavDestination = ScreenDestination { LoginScreen() } +val LoginScreenDestination: NavDestination = ScreenDestination { LoginScreen(route = it) } diff --git a/scripts/update_docs_url.sh b/scripts/update_docs_url.sh index ce1318b4..894d17dc 100644 --- a/scripts/update_docs_url.sh +++ b/scripts/update_docs_url.sh @@ -5,7 +5,7 @@ input=$1 if [[ "$input" == "snapshot" ]]; then brew install gnu-sed - gsed -i 's/]: https:\/\/hoc081098.github.io\/kmp-viewmodel\/docs\/0.x/]: https:\/\/hoc081098.github.io\/kmp-viewmodel\/docs\/latest/g' docs/index.md + gsed -i 's/]: https:\/\/hoc081098.github.io\/solivagant\/docs\/0.x/]: https:\/\/hoc081098.github.io\/solivagant\/docs\/latest/g' docs/index.md echo "Updated index.md file with snapshot version." else echo "Invalid input: $input"