diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 076d56e..dfc9ab0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,7 +41,7 @@ jobs: uses: actions/setup-java@v2 with: distribution: 'adopt' - java-version: 11 + java-version: 21 - name: "Set Release Version Env" run: | echo "RELEASE_VERSION=${GITHUB_REF##*/v}" >> $GITHUB_ENV diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f5e7bec..dca59c9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,6 +12,6 @@ jobs: uses: actions/setup-java@v2 with: distribution: 'adopt' - java-version: 11 + java-version: 21 - name: Unit Test run: ./gradlew testDebugUnitTest diff --git a/Sample/app/build.gradle b/Sample/app/build.gradle deleted file mode 100644 index 64a5dcf..0000000 --- a/Sample/app/build.gradle +++ /dev/null @@ -1,49 +0,0 @@ -plugins { - id 'com.android.application' - id 'kotlin-android' -} - -android { - namespace "com.veepee.sample" - - defaultConfig { - applicationId "com.veepee.sample" - minSdkVersion 21 - targetSdkVersion 33 - compileSdk 33 - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = '1.8' - } -} - -dependencies { - - implementation libs.lang.kotlin - implementation libs.androidx.core - implementation libs.androidx.appcompat - implementation libs.material - implementation libs.androidx.constraint.layout - - testImplementation libs.test.junit - - implementation project(":feature_a") - implementation project(":feature_b") - implementation project(":login") - implementation project(":routes") -} diff --git a/Sample/app/build.gradle.kts b/Sample/app/build.gradle.kts new file mode 100644 index 0000000..70cbd20 --- /dev/null +++ b/Sample/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.compose.compiler) +} + +android { + namespace = "com.veepee.sample" + + defaultConfig { + minSdk = 21 + targetSdk = 34 + compileSdk = 34 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } + buildFeatures { + compose = true + } +} + +dependencies { + testImplementation(libs.test.junit) + + implementation(project(":feature_a")) + implementation(project(":feature_b")) + implementation(project(":login")) + implementation(project(":routes")) + implementation(libs.androidx.design) + implementation(libs.androidx.compose.material) +} diff --git a/Sample/app/proguard-rules.pro b/Sample/app/proguard-rules.pro index f1b4245..2f9dc5a 100644 --- a/Sample/app/proguard-rules.pro +++ b/Sample/app/proguard-rules.pro @@ -1,6 +1,6 @@ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. +# proguardFiles setting in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html diff --git a/Sample/app/src/main/java/com/veepee/sample/MainActivity.kt b/Sample/app/src/main/java/com/veepee/sample/MainActivity.kt index 5c0401a..eaea952 100644 --- a/Sample/app/src/main/java/com/veepee/sample/MainActivity.kt +++ b/Sample/app/src/main/java/com/veepee/sample/MainActivity.kt @@ -18,12 +18,13 @@ package com.veepee.sample import android.os.Bundle import android.view.View import androidx.appcompat.app.AppCompatActivity -import com.veepee.routes.create +import com.veepee.routes.Schemas import com.veepee.routes.feature_a.ActivityALink import com.veepee.routes.feature_b.ActivityBLink import com.veepee.routes.feature_b.ActivityBParameter import com.veepee.routes.router import com.veepee.vpcore.route.link.deeplink.UriDeepLink +import com.veepee.vpcore.route.link.deeplink.UriParameter class MainActivity : AppCompatActivity() { @@ -32,7 +33,7 @@ class MainActivity : AppCompatActivity() { setContentView(R.layout.activity_main) val uri = intent.data if (uri != null) { - val deepLink = UriDeepLink.create(uri) + val deepLink = UriDeepLink(UriParameter(uri), Schemas.MyApp) router.route(this, deepLink) finish() } diff --git a/Sample/app/src/main/java/com/veepee/sample/SampleApplication.kt b/Sample/app/src/main/java/com/veepee/sample/SampleApplication.kt index 4d7e302..8a3b9b6 100644 --- a/Sample/app/src/main/java/com/veepee/sample/SampleApplication.kt +++ b/Sample/app/src/main/java/com/veepee/sample/SampleApplication.kt @@ -47,9 +47,9 @@ class SampleApplication : Application() { add(FeatureADeepLinkMapper) add(LoginDeepLinkMapper) - add(DeepLinkAuthenticationInterceptor) - add(ActivityLinkAuthenticationInterceptor) - add(FragmentLinkAuthenticationInterceptor) + add(0, DeepLinkAuthenticationInterceptor) + add(0, ActivityLinkAuthenticationInterceptor) + add(0, FragmentLinkAuthenticationInterceptor) add(FeatureBComposableNameMapper) } } diff --git a/Sample/build.gradle b/Sample/build.gradle deleted file mode 100644 index 4cdc04b..0000000 --- a/Sample/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. -buildscript { - ext.kotlin_version = "1.8.20" - repositories { - google() - mavenCentral() - } - dependencies { - classpath "com.android.tools.build:gradle:8.0.1" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -tasks.register('clean', Delete) { - delete rootProject.buildDir -} diff --git a/Sample/build.gradle.kts b/Sample/build.gradle.kts new file mode 100644 index 0000000..119965d --- /dev/null +++ b/Sample/build.gradle.kts @@ -0,0 +1,5 @@ +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.android.library) apply false + alias(libs.plugins.kotlin.android) apply false +} diff --git a/Sample/feature_a/build.gradle b/Sample/feature_a/build.gradle index 71c167d..e2b24cd 100644 --- a/Sample/feature_a/build.gradle +++ b/Sample/feature_a/build.gradle @@ -1,14 +1,16 @@ plugins { - id 'com.android.library' - id 'kotlin-android' + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.compose.compiler) } android { namespace "com.veepee.feature.a" + defaultConfig { minSdkVersion 21 - targetSdkVersion 33 - compileSdk 33 + targetSdkVersion 34 + compileSdk 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -17,33 +19,24 @@ android { buildTypes { release { minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = "17" } + buildFeatures { compose true } - - composeOptions { - kotlinCompilerExtensionVersion '1.4.6' - } } dependencies { - - implementation libs.lang.kotlin - implementation libs.androidx.core - implementation libs.androidx.appcompat - implementation libs.material - implementation libs.androidx.constraint.layout - implementation libs.androidx.fragment implementation project(":routes") - implementation libs.androidx.compose.foundation + implementation(libs.androidx.compose.foundation) + implementation(libs.androidx.appcompat) } diff --git a/Sample/feature_b/build.gradle b/Sample/feature_b/build.gradle index fc20fa8..fd68f62 100644 --- a/Sample/feature_b/build.gradle +++ b/Sample/feature_b/build.gradle @@ -1,6 +1,7 @@ plugins { - id 'com.android.library' - id 'kotlin-android' + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.compose.compiler) } android { @@ -8,8 +9,8 @@ android { defaultConfig { minSdkVersion 21 - targetSdkVersion 33 - compileSdk 33 + targetSdkVersion 34 + compileSdk 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -22,29 +23,21 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = '17' } + buildFeatures { compose true } - - composeOptions { - kotlinCompilerExtensionVersion '1.4.6' - } } dependencies { - implementation libs.lang.kotlin - implementation libs.androidx.core - implementation libs.androidx.appcompat - implementation libs.material - implementation libs.androidx.constraint.layout - implementation libs.androidx.fragment implementation project(":routes") - implementation libs.androidx.compose.foundation + implementation(libs.androidx.compose.foundation) + implementation(libs.androidx.appcompat) } diff --git a/Sample/feature_b/src/main/java/com/veepee/feature/b/routes/FeatureBComposableNameMapper.kt b/Sample/feature_b/src/main/java/com/veepee/feature/b/routes/FeatureBComposableNameMapper.kt index b554061..dfaba3b 100644 --- a/Sample/feature_b/src/main/java/com/veepee/feature/b/routes/FeatureBComposableNameMapper.kt +++ b/Sample/feature_b/src/main/java/com/veepee/feature/b/routes/FeatureBComposableNameMapper.kt @@ -23,6 +23,7 @@ import androidx.compose.ui.Modifier import com.veepee.routes.feature_b.ComposableBNames import com.veepee.routes.feature_b.FeatureBComposableEvent import com.veepee.routes.feature_b.FeatureBComposableLink +import com.veepee.vpcore.route.link.compose.ComposableEvent import com.veepee.vpcore.route.link.compose.ComposableLink import com.veepee.vpcore.route.link.compose.ComposableNameMapper import com.veepee.vpcore.route.link.compose.events.LocalLinkRouterEventHandler @@ -33,15 +34,15 @@ object FeatureBComposableNameMapper : ComposableNameMapper { @Composable override fun Map( - composableLink: ComposableLink, + link: ComposableLink, modifier: Modifier ) { val handler = LocalLinkRouterEventHandler.current - when (composableLink) { + when (link) { is FeatureBComposableLink -> BasicText( - composableLink.parameter.message, + link.parameter.message, modifier.clickable { - handler.publish(FeatureBComposableEvent(composableLink.parameter.message.length)) + handler.publish(FeatureBComposableEvent(link.parameter.message.length)) }) } } diff --git a/Sample/gradle/wrapper/gradle-wrapper.jar b/Sample/gradle/wrapper/gradle-wrapper.jar index c1962a7..e644113 100644 Binary files a/Sample/gradle/wrapper/gradle-wrapper.jar and b/Sample/gradle/wrapper/gradle-wrapper.jar differ diff --git a/Sample/gradle/wrapper/gradle-wrapper.properties b/Sample/gradle/wrapper/gradle-wrapper.properties index 37aef8d..a441313 100644 --- a/Sample/gradle/wrapper/gradle-wrapper.properties +++ b/Sample/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/Sample/gradlew b/Sample/gradlew index aeb74cb..b740cf1 100755 --- a/Sample/gradlew +++ b/Sample/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -83,7 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -130,10 +131,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -141,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -149,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -198,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/Sample/gradlew.bat b/Sample/gradlew.bat index 6689b85..7101f8e 100644 --- a/Sample/gradlew.bat +++ b/Sample/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/Sample/login/build.gradle b/Sample/login/build.gradle index eda3697..37de0fa 100644 --- a/Sample/login/build.gradle +++ b/Sample/login/build.gradle @@ -1,6 +1,7 @@ plugins { - id 'com.android.library' - id 'kotlin-android' + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.compose.compiler) id 'kotlin-parcelize' } @@ -9,8 +10,8 @@ android { defaultConfig { minSdkVersion 21 - targetSdkVersion 33 - compileSdk 33 + targetSdkVersion 34 + compileSdk 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -23,21 +24,21 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = '17' + } + buildFeatures { + compose true } } dependencies { - implementation libs.lang.kotlin - implementation libs.androidx.core - implementation libs.androidx.appcompat - implementation libs.material - implementation libs.androidx.constraint.layout - implementation libs.androidx.fragment implementation project(":routes") + implementation(libs.androidx.compose.foundation) + implementation(libs.androidx.appcompat) + implementation(libs.androidx.fragment) } diff --git a/Sample/routes/build.gradle b/Sample/routes/build.gradle index b86e9b1..f0bb4ab 100644 --- a/Sample/routes/build.gradle +++ b/Sample/routes/build.gradle @@ -1,6 +1,7 @@ plugins { - id 'com.android.library' - id 'kotlin-android' + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.compose.compiler) id 'kotlin-parcelize' } @@ -9,34 +10,30 @@ android { defaultConfig { minSdkVersion 21 - targetSdkVersion 33 - compileSdk 33 + targetSdkVersion 34 + compileSdk 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles "consumer-rules.pro" } buildTypes { release { minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = '17' + } + buildFeatures { + compose true } } dependencies { - - implementation libs.lang.kotlin - implementation libs.androidx.core - implementation libs.androidx.appcompat - implementation libs.material - - api 'com.veepee.vpcore.link-router:link-router:0.3.0' + implementation(libs.androidx.compose.foundation) + api("com.veepee.vpcore.link-router:link-router:0.5.3") } diff --git a/Sample/routes/src/main/java/com/veepee/routes/Schemas.kt b/Sample/routes/src/main/java/com/veepee/routes/Schemas.kt index b5133cd..2e05e06 100644 --- a/Sample/routes/src/main/java/com/veepee/routes/Schemas.kt +++ b/Sample/routes/src/main/java/com/veepee/routes/Schemas.kt @@ -16,7 +16,9 @@ package com.veepee.routes import com.veepee.vpcore.route.link.deeplink.Scheme +import kotlinx.parcelize.Parcelize +@Parcelize enum class Schemas(override val value: String) : Scheme { MyApp("MyApp") } diff --git a/Sample/routes/src/main/java/com/veepee/routes/UriDeepLinkExtensions.kt b/Sample/routes/src/main/java/com/veepee/routes/UriDeepLinkExtensions.kt deleted file mode 100644 index 64b23fa..0000000 --- a/Sample/routes/src/main/java/com/veepee/routes/UriDeepLinkExtensions.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2021, Veepee - * - * Permission to use, copy, modify, and/or distribute this software for any purpose - * with or without fee is hereby granted, provided that the above copyright notice - * and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - * THIS SOFTWARE. - */ -package com.veepee.routes - -import android.net.Uri -import com.veepee.vpcore.route.link.deeplink.UriDeepLink -import com.veepee.vpcore.route.link.deeplink.UriParameter - -fun UriDeepLink.Companion.create(uri: Uri): UriDeepLink = - UriDeepLink(UriParameter(uri)) { scheme -> Schemas.valueOf(scheme) } diff --git a/Sample/routes/src/main/java/com/veepee/routes/feature_b/FeatureBComposableLink.kt b/Sample/routes/src/main/java/com/veepee/routes/feature_b/FeatureBComposableLink.kt index 6f9c717..81f3f25 100644 --- a/Sample/routes/src/main/java/com/veepee/routes/feature_b/FeatureBComposableLink.kt +++ b/Sample/routes/src/main/java/com/veepee/routes/feature_b/FeatureBComposableLink.kt @@ -16,7 +16,7 @@ package com.veepee.routes.feature_b import com.veepee.vpcore.route.link.compose.ComposableEvent -import com.veepee.vpcore.route.link.compose.ComposableLinkWithEvent +import com.veepee.vpcore.route.link.compose.ComposableLink import com.veepee.vpcore.route.link.compose.ComposableName import com.veepee.vpcore.route.link.compose.ComposableParameter @@ -26,7 +26,7 @@ enum class ComposableBNames : ComposableName { data class FeatureBComposableLink( override val parameter: FeatureBComposableParameter -) : ComposableLinkWithEvent { +) : ComposableLink { override val composableName: ComposableBNames = ComposableBNames.ComposableB constructor(message: String) : this(FeatureBComposableParameter(message)) diff --git a/Sample/settings.gradle b/Sample/settings.gradle deleted file mode 100644 index 3b142cf..0000000 --- a/Sample/settings.gradle +++ /dev/null @@ -1,35 +0,0 @@ -rootProject.name = "sample" -include ':app' -include ':feature_a' -include ':feature_b' -include ':login' - -includeBuild('../') { - dependencySubstitution { - substitute module('com.veepee.vpcore.link-router:link-router') using project(':library') - } -} - -include ':routes' - - -dependencyResolutionManagement { - versionCatalogs { - libs { - def kotlinVersion = version('koltin', "1.8.20") - library('lang.kotlin', 'org.jetbrains.kotlin', 'kotlin-stdlib').versionRef(kotlinVersion) - library('androidx.core', 'androidx.core', 'core').versionRef(version('core', '1.10.0')) - library('androidx.appcompat', 'androidx.appcompat', 'appcompat').versionRef(version('appcompat', '1.6.1')) - library('androidx.fragment', 'androidx.fragment', 'fragment').versionRef(version('fragment', '1.5.7')) - library('androidx.constraint.layout', 'androidx.constraintlayout', 'constraintlayout').versionRef(version('constanstlayout', '2.0.4')) - library('material', 'com.google.android.material', 'material').versionRef(version('material', '1.6.0')) - library('test.junit', 'junit', 'junit').versionRef(version('junit', '4.13.1')) - library('test.androidx.test.core', 'androidx.test', 'core-ktx').versionRef(version('core-test', '1.4.0')) - library('test.robolectric', 'org.robolectric', 'robolectric').versionRef(version('robolectric', '4.8.1')) - library('test.mockito.inline', 'org.mockito', 'mockito-inline').versionRef(version('mockito-inline', '3.11.2')) - library('test.mockito.kotlin', 'org.mockito.kotlin', 'mockito-kotlin').versionRef(version('mockito-kotlin', '3.2.0')) - def composeVersion = version('compose', '1.4.2') - library('androidx.compose.foundation', 'androidx.compose.foundation', 'foundation').versionRef(composeVersion) - } - } -} diff --git a/Sample/settings.gradle.kts b/Sample/settings.gradle.kts new file mode 100644 index 0000000..530c5b3 --- /dev/null +++ b/Sample/settings.gradle.kts @@ -0,0 +1,33 @@ +rootProject.name = "sample" +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} + +include(":app") +include(":feature_a") +include(":feature_b") +include(":login") +include(":routes") +includeBuild("../") { + dependencySubstitution { + substitute(module("com.veepee.vpcore.link-router:link-router")).using(project(":library")) + } +} + diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 4cdc04b..0000000 --- a/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. -buildscript { - ext.kotlin_version = "1.8.20" - repositories { - google() - mavenCentral() - } - dependencies { - classpath "com.android.tools.build:gradle:8.0.1" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -tasks.register('clean', Delete) { - delete rootProject.buildDir -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..ccface1 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,6 @@ +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.android.library) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.compose.compiler) apply false +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..2ecf0ae --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,138 @@ +## Generated by $ ./gradlew refreshVersionsCatalog + +[bundles] + + +[plugins] + +android-application = { id = "com.android.application", version.ref = "agp" } +android-library = { id = "com.android.library", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +axion = { id = "pl.allegro.tech.build.axion-release", version.ref = "axion" } +play-services = { id = "com.google.gms.google-services", version.ref = "playservices_plugin" } +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } + +[versions] + +# Android +android_material = "1.12.0" +androidx_activity = "1.9.0" +androidx_annotation = "1.8.0" +androidx_appcompat = "1.7.0" +androidx_cardview = "1.0.0" +androidx_constraintlayout = "2.1.4" +androidx_core = "1.13.1" +androidx_fragment = "1.8.1" +androidx_lifecycle = "2.8.3" +androidx_lifecycle_extensions = "2.2.0" +androidx_recyclerview = "1.3.2" + +# Compose +compose = "1.6.8" +kotlinCollections = "0.3.7" +androidx_compose_material = "1.6.8" +androidx_compose_foundation = "1.6.8" +constraintlayout = "1.0.1" +androidx_compose_activity = "1.9.0" +coroutines = "1.8.1" +dagger = "2.51.1" +mockitoKotlin = "5.2.1" +okhttp = "4.12.0" +desugarJdkLibs = "2.0.4" + +# Plugin +agp = "8.5.0" +kotlin = "2.0.0" +ksp = "2.0.0-1.0.22" +axion = "1.17.2" +playservices_plugin = "4.4.2" +detekt = "1.23.6" +# Test +test_androidx_orchestrator = "1.5.0" +test_androidx_test = "1.6.1" +test_androidx_test_junit = "1.2.1" +test_androidx_test_runner = "1.6.1" +test_espresso = "3.6.1" +test_hamcrest = "2.2" +test_junit = "4.13.2" +test_mockk = "1.13.8" +test_robolectric = "4.12.2" +test_rxidler = "0.11.0" +log4j = "2.0.13" + +junit = "1.2.1" + +[libraries] + +# Architecture +androidx_lifecycle_base = { module = "androidx.lifecycle:lifecycle-extensions", version.ref = "androidx_lifecycle_extensions" } +androidx_lifecycle_livedata_core = { module = "androidx.lifecycle:lifecycle-livedata-core", version.ref = "androidx_lifecycle" } +androidx_lifecycle_livedata = { module = "androidx.lifecycle:lifecycle-livedata", version.ref = "androidx_lifecycle" } +androidx_lifecycle_lifecycle_compiler = { module = "androidx.lifecycle:lifecycle-compiler", version.ref = "androidx_lifecycle" } +androidx_lifecycle_runtime = { module = "androidx.lifecycle:lifecycle-runtime", version.ref = "androidx_lifecycle" } +androidx_lifecycle_viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel", version.ref = "androidx_lifecycle" } +androidx_lifecycle_runtime_compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidx_lifecycle" } + +# Compose +androidx_compose_foundation = { module = "androidx.compose.foundation:foundation", version.ref = "androidx_compose_foundation" } +androidx_compose_material = { module = "androidx.compose.material:material", version.ref = "androidx_compose_material" } +androidx_compose_runtime = { module = "androidx.compose.runtime:runtime", version.ref = "compose" } +androidx_compose_runtime_livedata = { module = "androidx.compose.runtime:runtime-livedata", version.ref = "compose" } + +androidx_compose_ui = { module = "androidx.compose.ui:ui", version.ref = "compose" } +androidx_compose_ui_tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" } +androidx_compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview", version.ref = "compose" } +androidx_compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest", version.ref = "compose" } +lang_kotlin_collections = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinCollections" } +androidx_compose_constraintlayout = { module = "androidx.constraintlayout:constraintlayout-compose", version.ref = "constraintlayout" } +androidx_compose_activity = { module = "androidx.activity:activity-compose", version.ref = "androidx_compose_activity" } + +# Injection +injection_dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" } +injection_dagger_processor = { module = "com.google.dagger:dagger-compiler", version.ref = "dagger" } + +# Lang +lang_coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" } +lang_coroutines_android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" } +lang_kotlin = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" } +log4j = { module = "org.slf4j:slf4j-simple", version.ref = "log4j" } + + +# Support +androidx_activity = { module = "androidx.activity:activity", version.ref = "androidx_activity" } +androidx_core = { module = "androidx.core:core", version.ref = "androidx_core" } +androidx_annotations = { module = "androidx.annotation:annotation", version.ref = "androidx_annotation" } +androidx_appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx_appcompat" } +androidx_cardview = { module = "androidx.cardview:cardview", version.ref = "androidx_cardview" } +androidx_constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidx_constraintlayout" } +androidx_design = { module = "com.google.android.material:material", version.ref = "android_material" } +androidx_fragment = { module = "androidx.fragment:fragment", version.ref = "androidx_fragment" } +androidx_recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "androidx_recyclerview" } + +# Test +test_mockito_kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version.ref = "mockitoKotlin" } +test_androidx_compose_ui = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "compose" } +test_espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "test_espresso" } +test_espresso_contrib = { module = "androidx.test.espresso:espresso-contrib", version.ref = "test_espresso" } +test_espresso_intents = { module = "androidx.test.espresso:espresso-intents", version.ref = "test_espresso" } +test_espresso_web = { module = "androidx.test.espresso:espresso-web", version.ref = "test_espresso" } +test_hamcrest = { module = "org.hamcrest:hamcrest-core", version.ref = "test_hamcrest" } +test_junit = { module = "junit:junit", version.ref = "test_junit" } +test_rxidler = { module = "com.squareup.rx.idler:rx2-idler", version.ref = "test_rxidler" } +test_androidx_core = { module = "androidx.test:core", version.ref = "test_androidx_test" } +test_androidx_orchestrator = { module = "androidx.test:orchestrator", version.ref = "test_androidx_orchestrator" } +test_androidx_rules = { module = "androidx.test:rules", version.ref = "test_androidx_test" } +test_androidx_runner = { module = "androidx.test:runner", version.ref = "test_androidx_test_runner" } +test_kotlintestjunit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } +test_mockk = { module = "io.mockk:mockk", version.ref = "test_mockk" } +test_mockwebserver = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "okhttp" } +test_robolectric = { module = "org.robolectric:robolectric", version.ref = "test_robolectric" } + +# Dependencies of the included buidsystem/plugins +android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "agp" } +axion-gradlePlugin = { group = "pl.allegro.tech.build", name = "axion-release-plugin", version.ref = "axion" } +ksp-gradlePlugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } +detekt-gradlePlugin = { group = "io.gitlab.arturbosch.detekt", name = "detekt-gradle-plugin", version.ref = "detekt" } +android-desugarJdkLibs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "desugarJdkLibs" } +junit = { group = "androidx.test.ext", name = "junit", version.ref = "junit" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index c1962a7..e644113 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37aef8d..a441313 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 3984daa..b740cf1 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -69,24 +69,25 @@ app_path=$0 # Need this for daisy-chained symlinks. while -APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path -[ -h "$app_path" ] + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] do -ls=$( ls -ld "$app_path" ) -link=${ls#*' -> '} -case $link in #( -/*) app_path=$link ;; #( -*) app_path=$APP_HOME$link ;; -esac + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. - MAX_FD=maximum +MAX_FD=maximum warn () { echo "$*" @@ -105,55 +106,58 @@ msys=false darwin=false nonstop=false case "$( uname )" in #( -CYGWIN* ) cygwin=true ;; #( -Darwin* ) darwin=true ;; #( -MSYS* | MINGW* ) msys=true ;; #( -NONSTOP* ) nonstop=true ;; + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then -if [ -x "$JAVA_HOME/jre/sh/java" ] ; then -# IBM's JDK on AIX uses strange locations for the executables + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java -else -JAVACMD=$JAVA_HOME/bin/java -fi -if [ ! -x "$JAVACMD" ] ; then + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the - location of your Java installation." -fi +location of your Java installation." + fi else -JAVACMD=java -which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the - location of your Java installation." +location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then -case $MAX_FD in #( -max*) -# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. -# shellcheck disable=SC3045 -MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" -esac -case $MAX_FD in #( -'' | soft) :;; #( -*) -# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. -# shellcheck disable=SC3045 -ulimit -n "$MAX_FD" || -warn "Could not set maximum file descriptor limit to $MAX_FD" -esac - fi + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line @@ -165,17 +169,17 @@ esac # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) -CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) -JAVACMD=$( cygpath --unix "$JAVACMD" ) + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# Now convert the arguments - kludge to limit ourselves to /bin/sh -for arg do -if -case $arg in #( --*) false ;; # don't mess with options #( -/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac @@ -198,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 6689b85..7101f8e 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/library/build.gradle b/library/build.gradle index 0ac3347..7c5edb6 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,6 +1,7 @@ plugins { - id 'com.android.library' - id 'kotlin-android' + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.compose.compiler) id 'kotlin-parcelize' id 'maven-publish' } @@ -9,8 +10,8 @@ android { namespace = "com.veepee.vpcore.link.route" defaultConfig { minSdkVersion 21 - targetSdkVersion 33 - compileSdk 33 + targetSdkVersion 34 + compileSdk 34 aarMetadata { minCompileSdk = 21 } @@ -26,19 +27,16 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = '17' } buildFeatures { compose true } - composeOptions { - kotlinCompilerExtensionVersion '1.4.6' - } testOptions { unitTests { @@ -62,11 +60,9 @@ dependencies { testImplementation libs.test.junit testImplementation libs.test.robolectric - testImplementation libs.test.mockito.inline - testImplementation libs.test.mockito.kotlin - testImplementation libs.test.androidx.test.core - - testImplementation libs.androidx.compose.ui.test + testImplementation libs.test.mockk + testImplementation libs.test.androidx.core + testImplementation libs.test.androidx.compose.ui testImplementation libs.androidx.compose.ui.test.manifest } diff --git a/library/proguard-rules.pro b/library/proguard-rules.pro index f1b4245..2f9dc5a 100644 --- a/library/proguard-rules.pro +++ b/library/proguard-rules.pro @@ -1,6 +1,6 @@ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. +# proguardFiles setting in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html diff --git a/library/src/main/java/com/veepee/vpcore/route/BundleExtensions.kt b/library/src/main/java/com/veepee/vpcore/route/BundleExtensions.kt index f3592e2..fb0978e 100644 --- a/library/src/main/java/com/veepee/vpcore/route/BundleExtensions.kt +++ b/library/src/main/java/com/veepee/vpcore/route/BundleExtensions.kt @@ -18,41 +18,44 @@ package com.veepee.vpcore.route import android.app.Activity import android.content.Intent import android.os.Bundle +import androidx.core.content.IntentCompat +import androidx.core.os.BundleCompat import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.lifecycle.LifecycleOwner import com.veepee.vpcore.route.link.Parameter import com.veepee.vpcore.route.link.ParcelableParameter -internal val LINK_PARAMETER = "${Parameter::class.java.name}.LINK_PARAMETER" -internal val LINK_PARAMETER_REQUEST_KEY = "${LINK_PARAMETER}_REQUEST_KEY" +val LINK_PARAMETER = "${Parameter::class.java.name}.LINK_PARAMETER" +val LINK_PARAMETER_REQUEST_KEY = "${LINK_PARAMETER}_REQUEST_KEY" -fun Activity.requireLinkParameter(): T { +inline fun Activity.requireLinkParameter(): T { return intent.requireLinkParameter() } -fun Intent.requireLinkParameter(): T { +inline fun Intent.requireLinkParameter(): T { return getLinkParameter()!! } -fun Intent.getLinkParameter(): T? { - return getParcelableExtra(LINK_PARAMETER) +inline fun Intent.getLinkParameter(): T? { + return IntentCompat.getParcelableExtra(this, LINK_PARAMETER, T::class.java) } -fun Bundle.requireLinkParameter(): T { +inline fun Bundle.requireLinkParameter(): T { return getLinkParameter()!! } -fun Bundle.getLinkParameter(): T? { - return getParcelable(LINK_PARAMETER) +inline fun Bundle.getLinkParameter(): T? { + return BundleCompat.getParcelable(this, LINK_PARAMETER, T::class.java) } -fun Fragment.requireLinkParameter(): T { +inline fun Fragment.requireLinkParameter(): T { return getLinkParameter()!! } -fun Fragment.getLinkParameter(): T? { - return arguments?.getParcelable(LINK_PARAMETER) +inline fun Fragment.getLinkParameter(): T? { + val args = arguments ?: return null + return BundleCompat.getParcelable(args, LINK_PARAMETER, T::class.java) } fun FragmentManager.setLinkParameterResult( @@ -62,10 +65,10 @@ fun FragmentManager.setLinkParameterResult( setFragmentResult(requestKey, parameter.asBundle()) } -fun FragmentManager.setLinkParameterResultListener( +inline fun FragmentManager.setLinkParameterResultListener( requestKey: String = LINK_PARAMETER_REQUEST_KEY, lifecycleOwner: LifecycleOwner, - listener: (T) -> Unit + crossinline listener: (T) -> Unit ) { setFragmentResultListener( requestKey, diff --git a/library/src/main/java/com/veepee/vpcore/route/LinkRouter.kt b/library/src/main/java/com/veepee/vpcore/route/LinkRouter.kt index d8f7d31..6a32669 100644 --- a/library/src/main/java/com/veepee/vpcore/route/LinkRouter.kt +++ b/library/src/main/java/com/veepee/vpcore/route/LinkRouter.kt @@ -49,16 +49,16 @@ interface LinkRouter : interface Builder { fun add(activityNameMapper: ActivityNameMapper): Builder - fun add(activityLinkInterceptor: ActivityLinkInterceptor): Builder + fun add(priority : Int, activityLinkInterceptor: ActivityLinkInterceptor): Builder fun add(fragmentNameMapper: FragmentNameMapper): Builder - fun add(fragmentLinkInterceptor: FragmentLinkInterceptor): Builder + fun add(priority : Int, fragmentLinkInterceptor: FragmentLinkInterceptor): Builder fun add(deepLinkMapper: DeepLinkMapper): Builder - fun add(deepLinkInterceptor: DeepLinkInterceptor): Builder + fun add(priority : Int, deepLinkInterceptor: DeepLinkInterceptor): Builder - fun add(composableLinkInterceptor: ComposableLinkInterceptor): Builder fun add(composableNameMapper: ComposableNameMapper): Builder + fun add(priority : Int, composableLinkInterceptor: ComposableLinkInterceptor): Builder fun newBuilder(): Builder fun build(): LinkRouter @@ -97,8 +97,8 @@ class LinkRouterBuilder( return this } - override fun add(activityLinkInterceptor: ActivityLinkInterceptor): LinkRouter.Builder { - activityLinkRouterBuilder.add(activityLinkInterceptor) + override fun add(priority : Int, activityLinkInterceptor: ActivityLinkInterceptor): LinkRouter.Builder { + activityLinkRouterBuilder.add(priority, activityLinkInterceptor) return this } @@ -107,8 +107,8 @@ class LinkRouterBuilder( return this } - override fun add(fragmentLinkInterceptor: FragmentLinkInterceptor): LinkRouter.Builder { - fragmentLinkRouterBuilder.add(fragmentLinkInterceptor) + override fun add(priority : Int, fragmentLinkInterceptor: FragmentLinkInterceptor): LinkRouter.Builder { + fragmentLinkRouterBuilder.add(priority, fragmentLinkInterceptor) return this } @@ -117,8 +117,8 @@ class LinkRouterBuilder( return this } - override fun add(deepLinkInterceptor: DeepLinkInterceptor): LinkRouter.Builder { - deepLinkRouterBuilder.add(deepLinkInterceptor) + override fun add(priority : Int, deepLinkInterceptor: DeepLinkInterceptor): LinkRouter.Builder { + deepLinkRouterBuilder.add(priority, deepLinkInterceptor) return this } @@ -127,8 +127,8 @@ class LinkRouterBuilder( return this } - override fun add(composableLinkInterceptor: ComposableLinkInterceptor): LinkRouter.Builder { - composableLinkRouterBuilder.add(composableLinkInterceptor) + override fun add(priority : Int, composableLinkInterceptor: ComposableLinkInterceptor): LinkRouter.Builder { + composableLinkRouterBuilder.add(priority, composableLinkInterceptor) return this } diff --git a/library/src/main/java/com/veepee/vpcore/route/link/activity/ActivityLinkRouter.kt b/library/src/main/java/com/veepee/vpcore/route/link/activity/ActivityLinkRouter.kt index c477477..f6aea37 100644 --- a/library/src/main/java/com/veepee/vpcore/route/link/activity/ActivityLinkRouter.kt +++ b/library/src/main/java/com/veepee/vpcore/route/link/activity/ActivityLinkRouter.kt @@ -26,7 +26,7 @@ interface ActivityLinkRouter { fun intentFor(context: Context, activityLink: ActivityLink): Intent interface Builder { - fun add(activityLinkInterceptor: ActivityLinkInterceptor): Builder + fun add(priority: Int, activityLinkInterceptor: ActivityLinkInterceptor): Builder fun add(activityNameMapper: ActivityNameMapper): Builder fun newBuilder(): Builder fun build(): ActivityLinkRouter @@ -35,7 +35,7 @@ interface ActivityLinkRouter { class ActivityLinkRouterBuilder( private val activityNameMappersRegistry: MutableSet> = mutableSetOf(), - private val activityLinkInterceptorsRegistry: MutableList = mutableListOf() + private val activityLinkInterceptorsRegistry: MutableMap> = mutableMapOf() ) : ActivityLinkRouter.Builder { override fun add(activityNameMapper: ActivityNameMapper): ActivityLinkRouter.Builder { @@ -43,22 +43,27 @@ class ActivityLinkRouterBuilder( return this } - override fun add(activityLinkInterceptor: ActivityLinkInterceptor): ActivityLinkRouter.Builder { - activityLinkInterceptorsRegistry.add(activityLinkInterceptor) + override fun add(priority: Int, activityLinkInterceptor: ActivityLinkInterceptor): ActivityLinkRouter.Builder { + val interceptors = activityLinkInterceptorsRegistry.getOrDefault(priority, emptyList()) + .toMutableList() + .apply { + add(activityLinkInterceptor) + } + activityLinkInterceptorsRegistry[priority] = interceptors return this } override fun newBuilder(): ActivityLinkRouter.Builder { return ActivityLinkRouterBuilder( activityNameMappersRegistry.toMutableSet(), - activityLinkInterceptorsRegistry.toMutableList() + activityLinkInterceptorsRegistry.toMutableMap() ) } override fun build(): ActivityLinkRouter { return ActivityLinkRouterImpl( activityNameMappersRegistry.toSet(), - ChainFactoryImpl(activityLinkInterceptorsRegistry.toList()) + ChainFactoryImpl(activityLinkInterceptorsRegistry.toSortedMap().values.flatten()) ) } } diff --git a/library/src/main/java/com/veepee/vpcore/route/link/compose/ComposableLink.kt b/library/src/main/java/com/veepee/vpcore/route/link/compose/ComposableLink.kt index de5c2d6..82b1a8e 100644 --- a/library/src/main/java/com/veepee/vpcore/route/link/compose/ComposableLink.kt +++ b/library/src/main/java/com/veepee/vpcore/route/link/compose/ComposableLink.kt @@ -19,8 +19,7 @@ import com.veepee.vpcore.route.link.Event import com.veepee.vpcore.route.link.Link import com.veepee.vpcore.route.link.Parameter -interface ComposableLinkWithEvent : ComposableLink -interface ComposableLink : Link { +interface ComposableLink : Link { val composableName: T override val parameter: ComposableParameter? } @@ -29,4 +28,4 @@ interface ComposableParameter : Parameter interface ComposableEvent : Event -object NoEvent : ComposableEvent +object NoComposableEvent : ComposableEvent diff --git a/library/src/main/java/com/veepee/vpcore/route/link/compose/ComposableLinkRouter.kt b/library/src/main/java/com/veepee/vpcore/route/link/compose/ComposableLinkRouter.kt index 889a5ed..b60b469 100644 --- a/library/src/main/java/com/veepee/vpcore/route/link/compose/ComposableLinkRouter.kt +++ b/library/src/main/java/com/veepee/vpcore/route/link/compose/ComposableLinkRouter.kt @@ -24,14 +24,14 @@ import com.veepee.vpcore.route.link.interceptor.ChainFactoryImpl interface ComposableLinkRouter { @Composable - fun ComposeFor(composableLink: ComposableLink, modifier: Modifier) + fun ComposeFor(link: ComposableLink, modifier: Modifier) @Composable - fun ComposeFor(composableLink: ComposableLink) + fun ComposeFor(link: ComposableLink) interface Builder { - fun add(composableLinkInterceptor: ComposableLinkInterceptor): Builder fun add(composableNameMapper: ComposableNameMapper): Builder + fun add(priority: Int, composableLinkInterceptor: ComposableLinkInterceptor): Builder fun newBuilder(): Builder fun build(): ComposableLinkRouter } @@ -39,11 +39,19 @@ interface ComposableLinkRouter { class ComposeLinkRouterBuilder( private val composableNameMappersRegistry: MutableSet> = mutableSetOf(), - private val composableLinkInterceptorsRegistry: MutableList = mutableListOf() + private val composableLinkInterceptorsRegistry: MutableMap> = mutableMapOf() ) : ComposableLinkRouter.Builder { - override fun add(composableLinkInterceptor: ComposableLinkInterceptor): ComposableLinkRouter.Builder { - composableLinkInterceptorsRegistry.add(composableLinkInterceptor) + override fun add( + priority: Int, + composableLinkInterceptor: ComposableLinkInterceptor + ): ComposableLinkRouter.Builder { + val interceptors = composableLinkInterceptorsRegistry.getOrDefault(priority, emptyList()) + .toMutableList() + .apply { + add(composableLinkInterceptor) + } + composableLinkInterceptorsRegistry[priority] = interceptors return this } @@ -55,14 +63,14 @@ class ComposeLinkRouterBuilder( override fun newBuilder(): ComposableLinkRouter.Builder { return ComposeLinkRouterBuilder( composableNameMappersRegistry.toMutableSet(), - composableLinkInterceptorsRegistry.toMutableList() + composableLinkInterceptorsRegistry.toMutableMap() ) } override fun build(): ComposableLinkRouter { return ComposableLinkRouterImpl( composableNameMappersRegistry.toSet(), - ChainFactoryImpl(composableLinkInterceptorsRegistry.toList()) + ChainFactoryImpl(composableLinkInterceptorsRegistry.toSortedMap().values.flatten()) ) } } @@ -70,7 +78,7 @@ class ComposeLinkRouterBuilder( @Suppress("UNCHECKED_CAST") internal class ComposableLinkRouterImpl( composableNameMappers: Set>, - private val chainFactory: ChainFactory, ComposableLink> + private val chainFactory: ChainFactory, ComposableLink> ) : ComposableLinkRouter { private val composableLinkMapper = @@ -81,19 +89,19 @@ internal class ComposableLinkRouterImpl( }.toMap() @Composable - override fun ComposeFor(composableLink: ComposableLink) { - ComposeFor(composableLink = composableLink, modifier = Modifier) + override fun ComposeFor(link: ComposableLink) { + ComposeFor(link = link, modifier = Modifier) } @Composable - override fun ComposeFor(composableLink: ComposableLink, modifier: Modifier) { + override fun ComposeFor(link: ComposableLink, modifier: Modifier) { val chain = chainFactory.create() - val mapper = composableLinkMapper[composableLink.composableName] - ?: throw NoComposableNameMapperException(composableLink) - val newComposableLink = chain.next(mapper, composableLink) - if (newComposableLink != composableLink) { + val mapper = composableLinkMapper[link.composableName] + ?: throw NoComposableNameMapperException(link) + val newComposableLink = chain.next(mapper, link) + if (newComposableLink != link) { return ComposeFor(newComposableLink, modifier) } - mapper.Map(composableLink, modifier) + mapper.Map(link, modifier) } } diff --git a/library/src/main/java/com/veepee/vpcore/route/link/compose/ComposableNameMapper.kt b/library/src/main/java/com/veepee/vpcore/route/link/compose/ComposableNameMapper.kt index 4a2f454..b474803 100644 --- a/library/src/main/java/com/veepee/vpcore/route/link/compose/ComposableNameMapper.kt +++ b/library/src/main/java/com/veepee/vpcore/route/link/compose/ComposableNameMapper.kt @@ -22,5 +22,5 @@ interface ComposableNameMapper { val supportedNames: Array @Composable - fun Map(composableLink: ComposableLink, modifier: Modifier) + fun Map(link: ComposableLink, modifier: Modifier) } diff --git a/library/src/main/java/com/veepee/vpcore/route/link/compose/LinkRouterContainer.kt b/library/src/main/java/com/veepee/vpcore/route/link/compose/LinkRouterContainer.kt index 98aa8d3..64ee737 100644 --- a/library/src/main/java/com/veepee/vpcore/route/link/compose/LinkRouterContainer.kt +++ b/library/src/main/java/com/veepee/vpcore/route/link/compose/LinkRouterContainer.kt @@ -56,17 +56,20 @@ fun ComposableLinkRouterContainer( } @Composable -fun ComposableFor(link: ComposableLink, modifier: Modifier = Modifier) { - LocalComposableLinkRouter.current.ComposeFor(composableLink = link, modifier) +fun ComposableFor(link: ComposableLink, modifier: Modifier = Modifier) { + ComposableFor(link = link, modifier) {} } @Composable inline fun ComposableFor( - link: ComposableLinkWithEvent, + link: ComposableLink, modifier: Modifier = Modifier, noinline onEvent: (Event) -> Unit ) { - LinkRouterEventHandlerContainer(onEvent = onEvent) { - ComposableFor(link = link, modifier = modifier) - } + LinkRouterEventHandlerContainer( + onEvent = onEvent, + content = { + LocalComposableLinkRouter.current.ComposeFor(link = link, modifier) + } + ) } diff --git a/library/src/main/java/com/veepee/vpcore/route/link/compose/NoComposableNameMapperException.kt b/library/src/main/java/com/veepee/vpcore/route/link/compose/NoComposableNameMapperException.kt index 0849d8a..c275bd3 100644 --- a/library/src/main/java/com/veepee/vpcore/route/link/compose/NoComposableNameMapperException.kt +++ b/library/src/main/java/com/veepee/vpcore/route/link/compose/NoComposableNameMapperException.kt @@ -15,5 +15,5 @@ */ package com.veepee.vpcore.route.link.compose -internal class NoComposableNameMapperException(composableLink: ComposableLink) : +internal class NoComposableNameMapperException(composableLink: ComposableLink) : IllegalArgumentException("$composableLink has no registered ComposableNameMapper registered for it.") diff --git a/library/src/main/java/com/veepee/vpcore/route/link/compose/chain/ComposableLinkInterceptor.kt b/library/src/main/java/com/veepee/vpcore/route/link/compose/chain/ComposableLinkInterceptor.kt index 5f00f72..a816a66 100644 --- a/library/src/main/java/com/veepee/vpcore/route/link/compose/chain/ComposableLinkInterceptor.kt +++ b/library/src/main/java/com/veepee/vpcore/route/link/compose/chain/ComposableLinkInterceptor.kt @@ -15,10 +15,11 @@ */ package com.veepee.vpcore.route.link.compose.chain +import com.veepee.vpcore.route.link.compose.ComposableEvent import com.veepee.vpcore.route.link.compose.ComposableLink import com.veepee.vpcore.route.link.compose.ComposableName import com.veepee.vpcore.route.link.compose.ComposableNameMapper import com.veepee.vpcore.route.link.interceptor.LinkInterceptor interface ComposableLinkInterceptor : - LinkInterceptor, ComposableLink> + LinkInterceptor, ComposableLink> diff --git a/library/src/main/java/com/veepee/vpcore/route/link/deeplink/DeepLink.kt b/library/src/main/java/com/veepee/vpcore/route/link/deeplink/DeepLink.kt index 5aa1e45..d519682 100644 --- a/library/src/main/java/com/veepee/vpcore/route/link/deeplink/DeepLink.kt +++ b/library/src/main/java/com/veepee/vpcore/route/link/deeplink/DeepLink.kt @@ -23,6 +23,6 @@ interface DeepLink : Link, Parcelable { val authority: String } -interface Scheme { +interface Scheme : Parcelable { val value: String } diff --git a/library/src/main/java/com/veepee/vpcore/route/link/deeplink/DeepLinkRouter.kt b/library/src/main/java/com/veepee/vpcore/route/link/deeplink/DeepLinkRouter.kt index 265c538..a777d74 100644 --- a/library/src/main/java/com/veepee/vpcore/route/link/deeplink/DeepLinkRouter.kt +++ b/library/src/main/java/com/veepee/vpcore/route/link/deeplink/DeepLinkRouter.kt @@ -26,7 +26,7 @@ interface DeepLinkRouter { interface Builder { fun add(deepLinkMapper: DeepLinkMapper): Builder - fun add(deepLinkInterceptor: DeepLinkInterceptor): Builder + fun add(priority: Int, deepLinkInterceptor: DeepLinkInterceptor): Builder fun newBuilder(): Builder fun build(activityLinkRouter: ActivityLinkRouter): DeepLinkRouter fun setStackBuilderFactory(stackBuilderFactory: StackBuilderFactory): Builder @@ -35,7 +35,7 @@ interface DeepLinkRouter { class DeepLinkRouterBuilder( private val deepLinkMappersRegistry: MutableSet> = mutableSetOf(), - private val deepLinkInterceptorsRegistry: MutableList = mutableListOf() + private val deepLinkInterceptorsRegistry: MutableMap> = mutableMapOf() ) : DeepLinkRouter.Builder { private var stackBuilderFactory: StackBuilderFactory = StackBuilderFactoryImpl() override fun add(deepLinkMapper: DeepLinkMapper): DeepLinkRouter.Builder { @@ -43,8 +43,11 @@ class DeepLinkRouterBuilder( return this } - override fun add(deepLinkInterceptor: DeepLinkInterceptor): DeepLinkRouter.Builder { - deepLinkInterceptorsRegistry.add(deepLinkInterceptor) + override fun add(priority: Int, deepLinkInterceptor: DeepLinkInterceptor): DeepLinkRouter.Builder { + val interceptors = deepLinkInterceptorsRegistry.getOrDefault(priority, emptyList()) + .toMutableList() + .apply { add(deepLinkInterceptor) } + deepLinkInterceptorsRegistry[priority] = interceptors return this } @@ -56,7 +59,7 @@ class DeepLinkRouterBuilder( override fun newBuilder(): DeepLinkRouter.Builder { return DeepLinkRouterBuilder( deepLinkMappersRegistry.toMutableSet(), - deepLinkInterceptorsRegistry.toMutableList() + deepLinkInterceptorsRegistry.toMutableMap() ) } @@ -65,7 +68,7 @@ class DeepLinkRouterBuilder( initialDeepLinkMappers = deepLinkMappersRegistry.toSet(), activityLinkRouter = activityLinkRouter, stackBuilderFactory = stackBuilderFactory, - chainFactory = ChainFactoryImpl(deepLinkInterceptorsRegistry.toList()) + chainFactory = ChainFactoryImpl(deepLinkInterceptorsRegistry.toSortedMap().values.flatten()) ) } } diff --git a/library/src/main/java/com/veepee/vpcore/route/link/deeplink/UriDeepLink.kt b/library/src/main/java/com/veepee/vpcore/route/link/deeplink/UriDeepLink.kt index b3822ec..181c623 100644 --- a/library/src/main/java/com/veepee/vpcore/route/link/deeplink/UriDeepLink.kt +++ b/library/src/main/java/com/veepee/vpcore/route/link/deeplink/UriDeepLink.kt @@ -23,20 +23,12 @@ import kotlinx.parcelize.Parcelize @Parcelize data class UriDeepLink( override val parameter: UriParameter, - private val schemeFactory: (scheme: String) -> Scheme + override val scheme: Scheme ) : DeepLink { - constructor( - uri: Uri, - schemeFactory: (scheme: String) -> Scheme - ) : this(UriParameter(uri), schemeFactory) - constructor( - url: String, - schemeFactory: (scheme: String) -> Scheme - ) : this(Uri.parse(url), schemeFactory) + constructor(uri: Uri, scheme: Scheme) : this(UriParameter(uri), scheme) - @IgnoredOnParcel - override val scheme: Scheme = schemeFactory(parameter.uri.scheme!!) + constructor(url: String, scheme: Scheme) : this(UriParameter(Uri.parse(url)), scheme) @IgnoredOnParcel override val authority: String = parameter.uri.authority!! @@ -60,8 +52,8 @@ data class UriParameter(val uri: Uri) : ParcelableParameter { val pathSegments: List = uri.pathSegments ?: emptyList() private fun Uri.queryMap(): Map { - return queryParameterNames.map { queryParameter -> - queryParameter to getQueryParameter(queryParameter)!! - }.toMap() + return queryParameterNames.associateWith { queryParameter -> + getQueryParameter(queryParameter)!! + } } } diff --git a/library/src/main/java/com/veepee/vpcore/route/link/fragment/FragmentLinkRouter.kt b/library/src/main/java/com/veepee/vpcore/route/link/fragment/FragmentLinkRouter.kt index 24a3b9b..cbebcd2 100644 --- a/library/src/main/java/com/veepee/vpcore/route/link/fragment/FragmentLinkRouter.kt +++ b/library/src/main/java/com/veepee/vpcore/route/link/fragment/FragmentLinkRouter.kt @@ -29,7 +29,7 @@ interface FragmentLinkRouter { interface Builder { fun add(fragmentNameMapper: FragmentNameMapper): Builder - fun add(fragmentLinkInterceptor: FragmentLinkInterceptor): Builder + fun add(priority: Int, fragmentLinkInterceptor: FragmentLinkInterceptor): Builder fun newBuilder(): Builder fun build(): FragmentLinkRouter } @@ -37,12 +37,17 @@ interface FragmentLinkRouter { class FragmentLinkRouterBuilder( private val fragmentNameMappersRegistry: MutableSet> = mutableSetOf(), - private val fragmentLinkInterceptorsRegistry: MutableList = mutableListOf() + private val fragmentLinkInterceptorsRegistry: MutableMap> = mutableMapOf() ) : FragmentLinkRouter.Builder { - override fun add(fragmentLinkInterceptor: FragmentLinkInterceptor): FragmentLinkRouter.Builder { - fragmentLinkInterceptorsRegistry.add(fragmentLinkInterceptor) + override fun add(priority: Int, fragmentLinkInterceptor: FragmentLinkInterceptor): FragmentLinkRouter.Builder { + val interceptors = fragmentLinkInterceptorsRegistry.getOrDefault(priority, emptyList()) + .toMutableList() + .apply { + add(fragmentLinkInterceptor) + } + fragmentLinkInterceptorsRegistry[priority] = interceptors return this } @@ -54,14 +59,14 @@ class FragmentLinkRouterBuilder( override fun newBuilder(): FragmentLinkRouter.Builder { return FragmentLinkRouterBuilder( fragmentNameMappersRegistry.toMutableSet(), - fragmentLinkInterceptorsRegistry.toMutableList() + fragmentLinkInterceptorsRegistry.toMutableMap() ) } override fun build(): FragmentLinkRouter { return FragmentLinkRouterImpl( fragmentNameMappersRegistry.toSet(), - ChainFactoryImpl(fragmentLinkInterceptorsRegistry.toList()) + ChainFactoryImpl(fragmentLinkInterceptorsRegistry.toSortedMap().values.flatten()) ) } } @@ -89,7 +94,7 @@ internal class FragmentLinkRouterImpl( if (newFragmentLink != fragmentLink) { return fragmentFor(newFragmentLink) } - val fragment = mapper.map(fragmentLink).newInstance() + val fragment = mapper.map(fragmentLink).getDeclaredConstructor().newInstance() return fragment.apply { arguments = Bundle().setLinkParameter(fragmentLink.parameter) } diff --git a/library/src/test/java/com/veepee/vpcore/route/activity/ActivityLinkRouterTest.kt b/library/src/test/java/com/veepee/vpcore/route/activity/ActivityLinkRouterTest.kt index 0813b26..741dfeb 100644 --- a/library/src/test/java/com/veepee/vpcore/route/activity/ActivityLinkRouterTest.kt +++ b/library/src/test/java/com/veepee/vpcore/route/activity/ActivityLinkRouterTest.kt @@ -23,6 +23,7 @@ import com.veepee.vpcore.route.activity.route.TestActivityALink import com.veepee.vpcore.route.activity.route.TestActivityBLink import com.veepee.vpcore.route.activity.route.TestActivityBParameter import com.veepee.vpcore.route.link.activity.ActivityLink +import com.veepee.vpcore.route.link.activity.ActivityLinkRouterBuilder import com.veepee.vpcore.route.link.activity.ActivityLinkRouterImpl import com.veepee.vpcore.route.link.activity.ActivityName import com.veepee.vpcore.route.link.activity.ActivityNameMapper @@ -31,11 +32,12 @@ import com.veepee.vpcore.route.link.activity.chain.ActivityLinkInterceptor import com.veepee.vpcore.route.link.interceptor.Chain import com.veepee.vpcore.route.link.interceptor.ChainFactoryImpl import com.veepee.vpcore.route.requireLinkParameter +import io.mockk.every +import io.mockk.mockk import org.junit.Assert.assertEquals import org.junit.Assert.assertThrows import org.junit.Test import org.junit.runner.RunWith -import org.mockito.kotlin.mock import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) @@ -45,15 +47,57 @@ class ActivityLinkRouterTest { private val activityBParameter = TestActivityBParameter("id") @Test - fun `should return intent for registered ActivityNameMappers`() { + fun `interceptors priority matters, not the order of addition`() { + val highPriority = 0 + val lowPriority = 10 + val router = ActivityLinkRouterBuilder() + .add(TestActivityNameMapper) + .add(lowPriority, object : ActivityLinkInterceptor { + override fun intercept( + chain: Chain, ActivityLink>, + mapper: ActivityNameMapper, + link: ActivityLink + ): ActivityLink { + return TestActivityALink + } + }) + .add(highPriority, object : ActivityLinkInterceptor { + override fun intercept( + chain: Chain, ActivityLink>, + mapper: ActivityNameMapper, + link: ActivityLink + ): ActivityLink { + return TestActivityBLink(TestActivityBParameter("id")) + } + }) + .build() + val activity = mockk(relaxed = true) + val intent = router.intentFor(activity, TestActivityALink) + assertEquals(intent.component!!.className, TestActivityB::class.java.name) + } + @Test + fun `should intercept activity link`() { + val activity: Activity = mockk(relaxed = true) + val interceptor: ActivityLinkInterceptor = mockk { + every { intercept(any(), any(), any()) } returns TestActivityBLink( + TestActivityBParameter("id") + ) + } + val router = ActivityLinkRouterImpl(mappers, ChainFactoryImpl(listOf(interceptor))) + val intent = router.intentFor(activity, TestActivityALink) + assertEquals(intent.component!!.className, TestActivityB::class.java.name) + } + + @Test + fun `should return intent for registered ActivityNameMappers`() { assertIntentFor(TestActivityALink, TestActivityA::class.java) assertIntentFor(TestActivityBLink(activityBParameter), TestActivityB::class.java) } @Test fun `should retrieve parameter from intent`() { - val activity: Activity = mock() + val activity: Activity = mockk(relaxed = true) val router = ActivityLinkRouterImpl(mappers, ChainFactoryImpl(emptyList())) val intent = router.intentFor(activity, TestActivityBLink(activityBParameter)) val parameter = intent.requireLinkParameter() @@ -65,7 +109,7 @@ class ActivityLinkRouterTest { val router = ActivityLinkRouterImpl(emptySet(), ChainFactoryImpl(emptyList())) - val activity: Activity = mock() + val activity: Activity = mockk() assertThrows(NoActivityNameMapperException::class.java) { router.intentFor(activity, TestActivityALink) } @@ -86,7 +130,7 @@ class ActivityLinkRouterTest { } } val router = ActivityLinkRouterImpl(mappers, ChainFactoryImpl(listOf(interceptor))) - val activity: Activity = mock() + val activity: Activity = mockk(relaxed = true) val intent = router.intentFor(activity, TestActivityALink) assertEquals(intent.component!!.className, TestActivityB::class.java.name) } @@ -95,7 +139,7 @@ class ActivityLinkRouterTest { activityLink: ActivityLink, clazz: Class ) { - val activity: Activity = mock() + val activity: Activity = mockk(relaxed = true) val router = ActivityLinkRouterImpl(mappers, ChainFactoryImpl(emptyList())) val intent = router.intentFor(activity, activityLink) diff --git a/library/src/test/java/com/veepee/vpcore/route/composable/ComposableLinkRouterTest.kt b/library/src/test/java/com/veepee/vpcore/route/composable/ComposableLinkRouterTest.kt index ddcac1f..be86861 100644 --- a/library/src/test/java/com/veepee/vpcore/route/composable/ComposableLinkRouterTest.kt +++ b/library/src/test/java/com/veepee/vpcore/route/composable/ComposableLinkRouterTest.kt @@ -23,6 +23,7 @@ import com.veepee.vpcore.route.composable.feature.TestComposablesNameMapper import com.veepee.vpcore.route.composable.route.TestComposableALink import com.veepee.vpcore.route.composable.route.TestComposableBLink import com.veepee.vpcore.route.composable.route.TestComposableBParameter +import com.veepee.vpcore.route.link.compose.ComposableEvent import com.veepee.vpcore.route.link.compose.ComposableFor import com.veepee.vpcore.route.link.compose.ComposableLink import com.veepee.vpcore.route.link.compose.ComposableLinkRouterContainer @@ -113,10 +114,10 @@ class ComposableLinkRouterTest { mappers, ChainFactoryImpl(listOf(object : ComposableLinkInterceptor { override fun intercept( - chain: Chain, ComposableLink>, + chain: Chain, ComposableLink>, mapper: ComposableNameMapper, - link: ComposableLink - ): ComposableLink { + link: ComposableLink + ): ComposableLink { if (link is TestComposableBLink) { return TestComposableALink() } diff --git a/library/src/test/java/com/veepee/vpcore/route/composable/feature/TestComposablesNameMapper.kt b/library/src/test/java/com/veepee/vpcore/route/composable/feature/TestComposablesNameMapper.kt index b44ce34..0bd8b18 100644 --- a/library/src/test/java/com/veepee/vpcore/route/composable/feature/TestComposablesNameMapper.kt +++ b/library/src/test/java/com/veepee/vpcore/route/composable/feature/TestComposablesNameMapper.kt @@ -22,6 +22,7 @@ import com.veepee.vpcore.route.composable.route.TestComposableALink import com.veepee.vpcore.route.composable.route.TestComposableBLink import com.veepee.vpcore.route.composable.route.TestComposableBLinkEvent import com.veepee.vpcore.route.composable.route.TestComposableName +import com.veepee.vpcore.route.link.compose.ComposableEvent import com.veepee.vpcore.route.link.compose.ComposableLink import com.veepee.vpcore.route.link.compose.ComposableNameMapper import com.veepee.vpcore.route.link.compose.events.LocalLinkRouterEventHandler @@ -30,12 +31,12 @@ object TestComposablesNameMapper : ComposableNameMapper { override val supportedNames: Array = TestComposableName.values() @Composable - override fun Map(composableLink: ComposableLink, modifier: Modifier) { + override fun Map(link: ComposableLink, modifier: Modifier) { val handler = LocalLinkRouterEventHandler.current - when (composableLink) { + when (link) { is TestComposableALink -> TestComposableA(modifier = modifier) is TestComposableBLink -> TestComposableB( - composableLink.parameter.message, + link.parameter.message, modifier = modifier.clickable { handler.publish(TestComposableBLinkEvent("bar")) } diff --git a/library/src/test/java/com/veepee/vpcore/route/composable/route/TestComposableALink.kt b/library/src/test/java/com/veepee/vpcore/route/composable/route/TestComposableALink.kt index 15356cb..c8028ec 100644 --- a/library/src/test/java/com/veepee/vpcore/route/composable/route/TestComposableALink.kt +++ b/library/src/test/java/com/veepee/vpcore/route/composable/route/TestComposableALink.kt @@ -15,11 +15,11 @@ */ package com.veepee.vpcore.route.composable.route -import com.veepee.vpcore.route.link.compose.ComposableLinkWithEvent +import com.veepee.vpcore.route.link.compose.ComposableLink import com.veepee.vpcore.route.link.compose.ComposableParameter -import com.veepee.vpcore.route.link.compose.NoEvent +import com.veepee.vpcore.route.link.compose.NoComposableEvent -class TestComposableALink : ComposableLinkWithEvent { +class TestComposableALink : ComposableLink { override val composableName: TestComposableName = TestComposableName.TestComposableA override val parameter: ComposableParameter? = null } diff --git a/library/src/test/java/com/veepee/vpcore/route/composable/route/TestComposableBLink.kt b/library/src/test/java/com/veepee/vpcore/route/composable/route/TestComposableBLink.kt index 9bfdd89..c8ac4f7 100644 --- a/library/src/test/java/com/veepee/vpcore/route/composable/route/TestComposableBLink.kt +++ b/library/src/test/java/com/veepee/vpcore/route/composable/route/TestComposableBLink.kt @@ -16,12 +16,12 @@ package com.veepee.vpcore.route.composable.route import com.veepee.vpcore.route.link.compose.ComposableEvent -import com.veepee.vpcore.route.link.compose.ComposableLinkWithEvent +import com.veepee.vpcore.route.link.compose.ComposableLink import com.veepee.vpcore.route.link.compose.ComposableParameter class TestComposableBLink( override val parameter: TestComposableBParameter -) : ComposableLinkWithEvent { +) : ComposableLink { override val composableName: TestComposableName = TestComposableName.TestComposableB } diff --git a/library/src/test/java/com/veepee/vpcore/route/deeplink/DeepLinkRouterImplTest.kt b/library/src/test/java/com/veepee/vpcore/route/deeplink/DeepLinkRouterImplTest.kt index 59f94ea..fbe9934 100644 --- a/library/src/test/java/com/veepee/vpcore/route/deeplink/DeepLinkRouterImplTest.kt +++ b/library/src/test/java/com/veepee/vpcore/route/deeplink/DeepLinkRouterImplTest.kt @@ -33,51 +33,49 @@ import com.veepee.vpcore.route.link.deeplink.StackBuilder import com.veepee.vpcore.route.link.deeplink.StackBuilderFactory import com.veepee.vpcore.route.link.deeplink.StackBuilderImpl import com.veepee.vpcore.route.link.deeplink.UriDeepLink +import com.veepee.vpcore.route.link.deeplink.UriParameter import com.veepee.vpcore.route.link.deeplink.chain.DeepLinkInterceptor import com.veepee.vpcore.route.link.interceptor.Chain import com.veepee.vpcore.route.link.interceptor.ChainFactory import com.veepee.vpcore.route.link.interceptor.ChainFactoryImpl +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import io.mockk.verifyOrder import org.junit.Assert.assertThrows import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.kotlin.any -import org.mockito.kotlin.inOrder -import org.mockito.kotlin.mock -import org.mockito.kotlin.times -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) class DeepLinkRouterImplTest { - private val chainFactory: ChainFactory, DeepLink> = mock() - private val chain: Chain, DeepLink> = mock() - private val activityLinkRouter: ActivityLinkRouter = mock() - private val stackBuilderFactory: StackBuilderFactory = mock() - private val stackBuilder: StackBuilder = mock() - private val context: Context = mock() - private val intentA: Intent = mock() - private val intentB: Intent = mock() - private val deepLink: DeepLink = mock() + private val chainFactory: ChainFactory, DeepLink> = mockk(relaxed = true) + private val chain: Chain, DeepLink> = mockk(relaxed = true) + private val activityLinkRouter: ActivityLinkRouter = mockk(relaxed = true) + private val stackBuilderFactory: StackBuilderFactory = mockk(relaxed = true) + private val stackBuilder: StackBuilder = mockk(relaxed = true) + private val context: Context = mockk(relaxed = true) + private val intentA: Intent = mockk(relaxed = true) + private val intentB: Intent = mockk(relaxed = true) + private val deepLink: DeepLink = mockk(relaxed = true) private val mappers: Set> = setOf(GoogleUriDeepLinkMapper, BingUriDeepLinkMapper) @Before fun setup() { - whenever(stackBuilderFactory.create(any())).thenReturn(stackBuilder) - whenever(activityLinkRouter.intentFor(context, TestActivityALink)) - .thenReturn(intentA) - whenever( + every { stackBuilderFactory.create(any()) } returns stackBuilder + every { activityLinkRouter.intentFor(context, TestActivityALink) } returns intentA + every { activityLinkRouter.intentFor( context, TestActivityBLink(TestActivityBParameter("www.google.com")) ) - ).thenReturn(intentB) + } returns intentB - whenever(chainFactory.create()).thenReturn(chain) - whenever(chain.next(any(), any())).thenReturn(deepLink) + every { chainFactory.create() } returns chain + every { chain.next(any(), any()) } returns deepLink } @Test @@ -89,21 +87,21 @@ class DeepLinkRouterImplTest { chainFactory = chainFactory ) - whenever(deepLink.authority).thenReturn("www.google.com") - whenever(deepLink.scheme).thenReturn(TestScheme.MyScheme) + every { deepLink.authority } returns "www.google.com" + every { deepLink.scheme } returns TestScheme.MyScheme router.route(context, deepLink) - val order = inOrder(stackBuilder) - - order.verify(stackBuilder).addNextIntent(intentA) - order.verify(stackBuilder).addNextIntent(intentB) - order.verify(stackBuilder).startActivities() + verifyOrder { + stackBuilder.addNextIntent(intentA) + stackBuilder.addNextIntent(intentB) + stackBuilder.startActivities() + } } @Test fun `should fail to route due missing mapper`() { - GlobalRouterBuilder.newBuilder().setStackBuilderFactory{ + GlobalRouterBuilder.newBuilder().setStackBuilderFactory { StackBuilderImpl(it) }.build() val router = DeepLinkRouterImpl( @@ -127,8 +125,10 @@ class DeepLinkRouterImplTest { link: DeepLink ): DeepLink { if (link.authority == "www.bing.com") { - return UriDeepLink(Uri.parse("myscheme://www.google.com")) - { TestScheme.MyScheme } + return UriDeepLink( + UriParameter(Uri.parse("myscheme://www.google.com")), + TestScheme.MyScheme + ) } return chain.next(mapper, link) } @@ -142,12 +142,17 @@ class DeepLinkRouterImplTest { chainFactory ) - router.route(context, UriDeepLink(Uri.parse("myscheme://www.bing.com")) - { TestScheme.MyScheme }) + router.route( + context, + UriDeepLink( + UriParameter(Uri.parse("myscheme://www.bing.com")), + TestScheme.MyScheme + ) + ) - verify(stackBuilderFactory, times(1)).create(context) - verify(stackBuilder, times(1)).addNextIntent(intentA) - verify(stackBuilder, times(1)).addNextIntent(intentB) - verify(stackBuilder, times(1)).startActivities() + verify(exactly = 1) { stackBuilderFactory.create(context) } + verify(exactly = 1) { stackBuilder.addNextIntent(intentA) } + verify(exactly = 1) { stackBuilder.addNextIntent(intentB) } + verify(exactly = 1) { stackBuilder.startActivities() } } } diff --git a/library/src/test/java/com/veepee/vpcore/route/deeplink/TestScheme.kt b/library/src/test/java/com/veepee/vpcore/route/deeplink/TestScheme.kt index 11e1bc8..e4da608 100644 --- a/library/src/test/java/com/veepee/vpcore/route/deeplink/TestScheme.kt +++ b/library/src/test/java/com/veepee/vpcore/route/deeplink/TestScheme.kt @@ -16,7 +16,9 @@ package com.veepee.vpcore.route.deeplink import com.veepee.vpcore.route.link.deeplink.Scheme +import kotlinx.parcelize.Parcelize +@Parcelize enum class TestScheme(override val value: String) : Scheme { MyScheme("myscheme") } diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 7849d1d..0000000 --- a/settings.gradle +++ /dev/null @@ -1,25 +0,0 @@ -rootProject.name = "Link-Router" -include ':library' - - -dependencyResolutionManagement { - versionCatalogs { - libs { - def kotlinVersion = version('koltin', "1.8.20") - library('lang.kotlin', 'org.jetbrains.kotlin', 'kotlin-stdlib').versionRef(kotlinVersion) - library('androidx.core', 'androidx.core', 'core').versionRef(version('core', '1.10.0')) - library('androidx.fragment', 'androidx.fragment', 'fragment').versionRef(version('fragment', '1.5.7')) - library('material.components', 'com.google.android.material', 'material').versionRef(version('material', '1.8.0')) - library('test.junit', 'junit', 'junit').versionRef(version('junit', '4.13.1')) - library('test.androidx.test.core', 'androidx.test', 'core-ktx').versionRef(version('core-test', '1.5.0')) - library('test.robolectric', 'org.robolectric', 'robolectric').versionRef(version('robolectric', '4.10.1')) - library('test.mockito.inline', 'org.mockito', 'mockito-inline').versionRef(version('mockito-inline', '3.11.2')) - library('test.mockito.kotlin', 'org.mockito.kotlin', 'mockito-kotlin').versionRef(version('mockito-kotlin', '3.2.0')) - - def composeVersion = version('compose', '1.4.2') - library('androidx.compose.foundation', 'androidx.compose.foundation', 'foundation').versionRef(composeVersion) - library('androidx.compose.ui.test', 'androidx.compose.ui', 'ui-test-junit4').versionRef(composeVersion) - library('androidx.compose.ui.test.manifest', 'androidx.compose.ui', 'ui-test-manifest').versionRef(composeVersion) - } - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..accab13 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} +dependencyResolutionManagement { + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "Link-Router" +include(":library") \ No newline at end of file