diff --git a/.editorconfig b/.editorconfig index 1f808de..ed67ead 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,2 +1,21 @@ -[*] +[*.{kt,kts}] +# https://pinterest.github.io/ktlint/latest/rules/configuration-ktlint/#code-style +ktlint_code_style = intellij_idea + +############################################# + +# https://pinterest.github.io/ktlint/latest/rules/configuration-ktlint/#final-newline insert_final_newline = true + +# https://pinterest.github.io/ktlint/latest/rules/standard/#trailing-comma-on-declaration-site +ij_kotlin_allow_trailing_comma = false + +# https://pinterest.github.io/ktlint/latest/rules/standard/#trailing-comma-on-call-site +ij_kotlin_allow_trailing_comma_on_call_site = false + +# https://pinterest.github.io/ktlint/latest/rules/standard/#no-wildcard-imports +ij_kotlin_packages_to_use_import_on_demand = unset # Disallows all wildcard imports + +# https://pinterest.github.io/ktlint/latest/rules/standard/#import-ordering +# https://pinterest.github.io/ktlint/latest/rules/standard/#no-wildcard-imports +ij_kotlin_imports_layout = * # Alphabetical with capital letters before lower case letters (e.g. Z before a), no blank lines diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ef39f50..e15e826 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,16 +8,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Clone Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - name: Set up JDK 11 - uses: actions/setup-java@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v4 with: - java-version: '11' + java-version: '17' distribution: 'temurin' cache: gradle - name: Build with Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v3 with: arguments: build diff --git a/.github/workflows/publish-documentation.yml b/.github/workflows/publish-documentation.yml index a9541cf..d74d965 100644 --- a/.github/workflows/publish-documentation.yml +++ b/.github/workflows/publish-documentation.yml @@ -9,17 +9,17 @@ jobs: runs-on: ubuntu-latest steps: - name: Clone Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - name: Set up JDK 11 - uses: actions/setup-java@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v4 with: - java-version: '11' + java-version: '17' distribution: 'temurin' cache: gradle - name: Build the Dokka Documentation - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v3 with: arguments: dokkaHtmlMultiModule diff --git a/.github/workflows/publish-library.yml b/.github/workflows/publish-library.yml index fdb8d96..306e8bd 100644 --- a/.github/workflows/publish-library.yml +++ b/.github/workflows/publish-library.yml @@ -9,12 +9,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Clone Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - name: Set up JDK 11 - uses: actions/setup-java@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v4 with: - java-version: '11' + java-version: '17' distribution: 'temurin' cache: gradle @@ -31,6 +31,6 @@ jobs: GPG_SIGNING_KEY_PASSWORD: ${{ secrets.GPG_SIGNING_KEY_PASSWORD }} - name: Publish the Library - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v3 with: arguments: publishMultimodalSpannerPublicationToCentralRepository diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 70fc169..118cd4d 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -44,17 +44,12 @@ - - diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..35eb1dd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4d01dee..da48194 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,91 +1,12 @@ plugins { - id("com.android.application") - id("com.google.dagger.hilt.android") - kotlin("android") - kotlin("kapt") -} - -android { - compileSdk = Versions.COMPILE_SDK - namespace = "${Config.APPLICATION_ID}.sample" - - defaultConfig { - applicationId = "${Config.APPLICATION_ID}.sample" - - minSdk = Versions.MIN_SDK - targetSdk = Versions.TARGET_SDK - - versionCode = Versions.VERSION_CODE - versionName = Versions.VERSION_NAME - - vectorDrawables { - useSupportLibrary = true - } - } - - buildTypes { - getByName("debug") { - isMinifyEnabled = false - isTestCoverageEnabled = true - } - - getByName("release") { - isMinifyEnabled = false - isShrinkResources = false - } - } - - compileOptions { - sourceCompatibility = Versions.JVM - targetCompatibility = Versions.JVM - } - - kotlinOptions { - jvmTarget = Versions.JVM_STRING - } + alias(libs.plugins.multimodal.app) - buildFeatures { - compose = true - } - - composeOptions { - kotlinCompilerExtensionVersion = Versions.COMPOSE_COMPILER - } - - packagingOptions { - resources { - excludes += "/META-INF/{AL2.0,LGPL2.1}" - } - } + alias(libs.plugins.multimodal.compose.app) + alias(libs.plugins.multimodal.hilt) } dependencies { - api(platform(project(":constraints"))) - api(project(":multimodal")) - kapt(platform(project(":constraints"))) - - ///////////////////////////////////////////////////////////////////// - - // region Application - - debugImplementation(Libraries.COMPOSE_MANIFEST_TEST) - debugImplementation(Libraries.COMPOSE_UI_TOOLING) - - implementation(Libraries.ACTIVITY_COMPOSE) - implementation(Libraries.COMPOSE_UI) - implementation(Libraries.COMPOSE_UI_TOOLING_PREVIEW) - implementation(Libraries.CORE_KTX) - implementation(Libraries.DAGGER_ANDROID) - implementation(Libraries.MATERIAL) - implementation(Libraries.MATERIAL_3) - implementation(Libraries.NAVIGATION_COMPOSE) - implementation(Libraries.WINDOW_MANAGER) - - kapt(Libraries.DAGGER_COMPILER) - - // endregion -} + implementation(project(":multimodal")) -kapt { - correctErrorTypes = true + implementation(libs.material) } diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/App.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/App.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/App.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/App.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/MainActivity.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/MainActivity.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/MainActivity.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/MainActivity.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/di/ScreenCaptureModule.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/di/ScreenCaptureModule.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/di/ScreenCaptureModule.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/di/ScreenCaptureModule.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/MultimodalSpanner.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/MultimodalSpanner.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/MultimodalSpanner.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/MultimodalSpanner.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsDetailScreen.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsDetailScreen.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsDetailScreen.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsDetailScreen.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsListHalfAndDetailHalf.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsListHalfAndDetailHalf.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsListHalfAndDetailHalf.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsListHalfAndDetailHalf.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsListOneThirdAndDetailTwoThirds.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsListOneThirdAndDetailTwoThirds.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsListOneThirdAndDetailTwoThirds.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsListOneThirdAndDetailTwoThirds.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsListScreen.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsListScreen.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsListScreen.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsListScreen.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsRoute.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsRoute.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsRoute.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsRoute.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsStacked.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsStacked.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsStacked.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsStacked.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsViewModel.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsViewModel.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsViewModel.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/adaptivelayouts/AdaptiveLayoutsViewModel.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/home/HomeRoute.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/home/HomeRoute.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/home/HomeRoute.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/home/HomeRoute.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/home/HomeScreen.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/home/HomeScreen.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/home/HomeScreen.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/home/HomeScreen.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/navigation/Destinations.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/navigation/Destinations.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/navigation/Destinations.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/navigation/Destinations.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/navigation/MultimodalSpannerNavGraph.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/navigation/MultimodalSpannerNavGraph.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/navigation/MultimodalSpannerNavGraph.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/navigation/MultimodalSpannerNavGraph.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/screeninfo/ScreenInfoRoute.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/screeninfo/ScreenInfoRoute.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/screeninfo/ScreenInfoRoute.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/screeninfo/ScreenInfoRoute.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/screeninfo/ScreenInfoScreen.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/screeninfo/ScreenInfoScreen.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/screeninfo/ScreenInfoScreen.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/screeninfo/ScreenInfoScreen.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/theme/Color.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/theme/Color.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/theme/Color.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/theme/Color.kt diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/theme/Theme.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/theme/Theme.kt similarity index 94% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/theme/Theme.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/theme/Theme.kt index a4be68c..ee6df45 100644 --- a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/theme/Theme.kt +++ b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/theme/Theme.kt @@ -47,7 +47,7 @@ fun MultimodalSpannerTheme( if (!view.isInEditMode) { SideEffect { (view.context as Activity).window.statusBarColor = colorScheme.primary.toArgb() - ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = darkTheme + //ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = darkTheme } } diff --git a/app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/theme/Type.kt b/app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/theme/Type.kt similarity index 100% rename from app/src/main/java/com/oliverspryn/android/multimodal/sample/ui/theme/Type.kt rename to app/src/main/kotlin/com/oliverspryn/android/multimodal/sample/ui/theme/Type.kt diff --git a/build-logic/.gitignore b/build-logic/.gitignore new file mode 100644 index 0000000..eab0873 --- /dev/null +++ b/build-logic/.gitignore @@ -0,0 +1,2 @@ +/build +/*/build diff --git a/build-logic/README.md b/build-logic/README.md new file mode 100644 index 0000000..71074db --- /dev/null +++ b/build-logic/README.md @@ -0,0 +1,34 @@ +# Convention Plugins + +The `build-logic` folder defines project-specific convention plugins, used to keep a single source +of truth for common module configurations. + +This approach is heavily based on these articles and/or repositories: + +- [Now in Android](https://github.com/android/nowinandroid/tree/main/build-logic) +- [Unlocking Reusability in Gradle: How to Use Kotlin-written Convention + Plugins](https://medium.com/@amsavarthan/11b95cb008ef) +- [Mastering Dependency Management: Version Catalog & Convention Plugin at + Scale](https://proandroiddev.com/b94205595f6b) +- [Using Version Catalogs from Gradle Precompiled Scripts with Kotlin + DSL](https://medium.com/@saulmm2/df3c27ea017c) + +By setting up convention plugins in `build-logic`, we can avoid duplicated build script setup, +messy `subproject` configurations, without the pitfalls of the `buildSrc` directory. + +`build-logic` is an included build, as configured in the root +[`settings.gradle.kts`](../settings.gradle.kts). + +Inside `build-logic` is a `convention` module, which defines a set of plugins that all other +modules can use to configure themselves. + +`build-logic` also includes a set of `Kotlin` files used to share logic between plugins themselves, +which is most useful for configuring Android components (libraries vs applications) with shared +code. + +These plugins are *additive* and *composable*, and try to only accomplish a single responsibility. +Modules can then pick and choose the configurations they need. + +If there is one-off logic for a module without shared code, it's preferable to define that directly +in the module's `build.gradle.kts`, as opposed to creating a convention plugin with module-specific +setup. diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts new file mode 100644 index 0000000..2363579 --- /dev/null +++ b/build-logic/convention/build.gradle.kts @@ -0,0 +1,65 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + `kotlin-dsl` +} + +group = "com.oliverspryn.gradle" + +// Configure the build-logic plugins to target JDK 17 +// This matches the JDK used to build the project, and is not related to what is running on device. +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +tasks.withType().configureEach { + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17.toString() + } +} + +dependencies { + compileOnly(libs.agp) + compileOnly(libs.dokka) + compileOnly(libs.kotlin) +} + +gradlePlugin { + plugins { + register("app") { + id = "multimodal.app" + implementationClass = "com.oliverspryn.gradle.plugin.AndroidApplicationConventionPlugin" + } + + register("compose-app") { + id = "multimodal.compose-app" + implementationClass = "com.oliverspryn.gradle.plugin.ComposeApplicationConventionPlugin" + } + + register("compose-library-base") { + id = "multimodal.compose-library-base" + implementationClass = "com.oliverspryn.gradle.plugin.BaseComposeLibraryConventionPlugin" + } + + register("dokka") { + id = "multimodal.dokka" + implementationClass = "com.oliverspryn.gradle.plugin.DokkaConventionPlugin" + } + + register("hilt") { + id = "multimodal.hilt" + implementationClass = "com.oliverspryn.gradle.plugin.HiltConventionPlugin" + } + + register("library") { + id = "multimodal.library" + implementationClass = "com.oliverspryn.gradle.plugin.AndroidLibraryConventionPlugin" + } + + register("publish") { + id = "multimodal.publish" + implementationClass = "com.oliverspryn.gradle.plugin.PublishConventionPlugin" + } + } +} diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/BuildConfig.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/BuildConfig.kt new file mode 100644 index 0000000..581aa28 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/BuildConfig.kt @@ -0,0 +1,104 @@ +package com.oliverspryn.gradle + +import org.gradle.api.JavaVersion + +object BuildConfig { + private object DeveloperCoreConfig { + // region App Version + + // ================================================================== + // Hey developers! This is where you can configure the app's version. + // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv + + const val VERSION_CODE = 1 + const val VERSION_NAME = CentralRepository.Artifact.VERSION + + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // Make sure to update both of these values before publishing. + // ================================================================== + + // endregion + + // region SDKs and Supported Android API Versions + + const val COMPILE_SDK = 34 + const val MIN_SDK = 21 + const val TARGET_SDK = COMPILE_SDK + + // endregion + + // region Build Types and Common Build Config Fields + + val BUILD_TYPES = listOf( + BuildType.Debug, + BuildType.Release + ) + + // endregion + } + + // ============================================================================================= + // Everything from above is meant for you to easily configure the app. + // Your settings from above will percolate down to the rest of the config below. + // + // There really shouldn't be any need to change anything below this line. + // If you do, you're probably changing some of the more fundamental aspects of the app. + // + // So, I guess the correct phrases would be: + // - "Fool of a Took!" ~ Gandalf + // - "Here be dragons." ~ Unknown + // - "Live long and prosper." ~ Spock + // - "May the force be with you." ~ Obi-Wan Kenobi + // - "I have a bad feeling about this." ~ Han Solo + // ============================================================================================= + + object App { + const val APPLICATION_ID = "com.oliverspryn.android.multimodal" + + val BUILD_TYPES = DeveloperCoreConfig.BUILD_TYPES + + /** + * This is effectively the base package name for the application. This + * should not be confused with the [APPLICATION_ID], which is used to + * uniquely identify the application on the device and in the Google Play + * Store. This identifier was set years ago and cannot now be changed. + */ + const val NAMESPACE = APPLICATION_ID + + const val VERSION_CODE = DeveloperCoreConfig.VERSION_CODE + const val VERSION_NAME = DeveloperCoreConfig.VERSION_NAME + } + + object Android { + const val COMPILE_SDK = DeveloperCoreConfig.COMPILE_SDK + const val MIN_SDK = DeveloperCoreConfig.MIN_SDK + const val TARGET_SDK = DeveloperCoreConfig.TARGET_SDK + } + + object Jvm { + const val KOTLIN_WARNINGS_AS_ERRORS = true + val VERSION = JavaVersion.VERSION_1_8 + const val VERSION_STRING = "1.8" + } + + abstract class BuildType( + val enableUnitTestCoverage: Boolean = true, + val initWithOtherPreExistingBuildType: String? = "debug", + val isBuiltInBuildType: Boolean = false, + val isDebuggable: Boolean = true, + val isMinifyEnabled: Boolean = false, + val isShrinkResources: Boolean = false, + val name: String + ) { + object Debug : BuildType( + isBuiltInBuildType = true, + name = "debug" + ) + + object Release : BuildType( + enableUnitTestCoverage = false, + isBuiltInBuildType = true, + name = "release" + ) + } +} diff --git a/buildSrc/src/main/kotlin/CentralRepository.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/CentralRepository.kt similarity index 74% rename from buildSrc/src/main/kotlin/CentralRepository.kt rename to build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/CentralRepository.kt index 36b9bb8..5d56c9c 100644 --- a/buildSrc/src/main/kotlin/CentralRepository.kt +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/CentralRepository.kt @@ -1,37 +1,32 @@ -object CentralRepository { +package com.oliverspryn.gradle +object CentralRepository { const val LIBRARY_NAME = "MultimodalSpanner" object Artifact { - const val GROUP_ID = "com.oliverspryn.android" const val ID = "multimodal-spanner" const val VERSION = "1.0.0" } object Developer { - const val ID = "oliverspryn" const val NAME = "Oliver Spryn" const val URL = "https://oliverspryn.com/" } object Project { - - const val DESCRIPTION = - "Smooths over the rough edges to help you extract information about your Android device's screen and foldable state." + const val DESCRIPTION = "Smooths over the rough edges to help you extract information about your Android device's screen and foldable state." const val NAME = "Multimodal Spanner" - const val URL = "https://oliverspryn.com/portfolio/multimodal-spanner" + const val URL = "https://oliverspryn.com/" } object License { - const val NAME = "MIT License" const val URL = "https://mit-license.org/" } object SCM { - const val URL = "github.com/oliverspryn/multimodal-spanner" // Omit the protocol and trailing slash } } diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/AndroidBaseVersionExtension.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/AndroidBaseVersionExtension.kt new file mode 100644 index 0000000..7ec3d02 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/AndroidBaseVersionExtension.kt @@ -0,0 +1,15 @@ +package com.oliverspryn.gradle.extension + +import com.android.build.api.dsl.CommonExtension +import com.oliverspryn.gradle.BuildConfig + +internal fun configureAndroidBaseVersion(commonExtension: CommonExtension<*, *, *, *, *>) { + commonExtension.apply { + compileSdk = BuildConfig.Android.COMPILE_SDK + + defaultConfig { + minSdk = BuildConfig.Android.MIN_SDK + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + } +} diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/ComposeExtension.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/ComposeExtension.kt new file mode 100644 index 0000000..b3eb835 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/ComposeExtension.kt @@ -0,0 +1,25 @@ +package com.oliverspryn.gradle.extension + +import com.android.build.api.dsl.CommonExtension +import org.gradle.api.artifacts.VersionCatalog + +internal fun configureCompose( + commonExtension: CommonExtension<*, *, *, *, *>, + libs: VersionCatalog +) { + commonExtension.apply { + buildFeatures { + compose = true + } + + composeOptions { + kotlinCompilerExtensionVersion = libs.findVersionId("compose-compiler") + } + + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } + } +} diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/KotlinAndroidExtension.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/KotlinAndroidExtension.kt new file mode 100644 index 0000000..3c46dab --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/KotlinAndroidExtension.kt @@ -0,0 +1,26 @@ +package com.oliverspryn.gradle.extension + +import com.android.build.api.dsl.CommonExtension +import com.oliverspryn.gradle.BuildConfig +import org.gradle.api.Project +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +internal fun Project.configureKotlinAndroid( + commonExtension: CommonExtension<*, *, *, *, *> +) { + commonExtension.apply { + compileOptions { + sourceCompatibility = BuildConfig.Jvm.VERSION + targetCompatibility = BuildConfig.Jvm.VERSION + } + } + + // Use withType to workaround https://youtrack.jetbrains.com/issue/KT-55947 + tasks.withType().configureEach { + kotlinOptions { + allWarningsAsErrors = BuildConfig.Jvm.KOTLIN_WARNINGS_AS_ERRORS + jvmTarget = BuildConfig.Jvm.VERSION_STRING + } + } +} diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/ProjectExtension.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/ProjectExtension.kt new file mode 100644 index 0000000..ad2c5e7 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/ProjectExtension.kt @@ -0,0 +1,9 @@ +package com.oliverspryn.gradle.extension + +import org.gradle.api.Project +import org.gradle.api.artifacts.VersionCatalog +import org.gradle.api.artifacts.VersionCatalogsExtension +import org.gradle.kotlin.dsl.getByType + +val Project.libs + get(): VersionCatalog = extensions.getByType().named("libs") diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/VersionCatalogExtension.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/VersionCatalogExtension.kt new file mode 100644 index 0000000..d6506b2 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/extension/VersionCatalogExtension.kt @@ -0,0 +1,7 @@ +package com.oliverspryn.gradle.extension + +import org.gradle.api.artifacts.VersionCatalog + +fun VersionCatalog.findPluginId(alias: String): String = findPlugin(alias).get().get().pluginId +fun VersionCatalog.findLibraryId(alias: String) = findLibrary(alias).get() +fun VersionCatalog.findVersionId(alias: String) = findVersion(alias).get().toString() diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/AndroidApplicationConventionPlugin.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/AndroidApplicationConventionPlugin.kt new file mode 100644 index 0000000..54f5820 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/AndroidApplicationConventionPlugin.kt @@ -0,0 +1,84 @@ +package com.oliverspryn.gradle.plugin + +import com.android.build.api.dsl.ApplicationBuildType +import com.android.build.api.dsl.ApplicationExtension +import com.oliverspryn.gradle.BuildConfig +import com.oliverspryn.gradle.extension.configureAndroidBaseVersion +import com.oliverspryn.gradle.extension.configureKotlinAndroid +import com.oliverspryn.gradle.extension.findPluginId +import com.oliverspryn.gradle.extension.libs +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure + +class AndroidApplicationConventionPlugin : BaseAndroidConventionPlugin() { + override fun apply(target: Project) { + super.apply(target) + + with(target) { + with(pluginManager) { + apply(libs.findPluginId("android-application")) + } + + extensions.configure { + configureAndroidBaseVersion(this) + configureKotlinAndroid(this) + + namespace = "${BuildConfig.App.NAMESPACE}.sample" + + defaultConfig { + applicationId = "${BuildConfig.App.APPLICATION_ID}.sample" + targetSdk = BuildConfig.Android.TARGET_SDK + + versionCode = BuildConfig.App.VERSION_CODE + versionName = BuildConfig.App.VERSION_NAME + + vectorDrawables { + useSupportLibrary = true + } + } + + buildTypes { + BuildConfig.App.BUILD_TYPES.forEach { buildTypeProperties -> + if (buildTypeProperties.isBuiltInBuildType) { + getByName(buildTypeProperties.name) { + setupBuildType( + buildTypes = this@buildTypes, + applicationBuildType = this, + buildTypeProperties = buildTypeProperties + ) + } + } else { + create(buildTypeProperties.name) { + setupBuildType( + buildTypes = this@buildTypes, + applicationBuildType = this, + buildTypeProperties = buildTypeProperties + ) + } + } + } + } + + buildFeatures { + buildConfig = true + } + } + } + } + + private fun setupBuildType( + buildTypes: NamedDomainObjectContainer, + applicationBuildType: ApplicationBuildType, + buildTypeProperties: BuildConfig.BuildType + ) = with(applicationBuildType) { + buildTypeProperties.initWithOtherPreExistingBuildType?.let { + initWith(buildTypes.getByName(it)) + } + + enableUnitTestCoverage = buildTypeProperties.enableUnitTestCoverage + isDebuggable = buildTypeProperties.isDebuggable + isMinifyEnabled = buildTypeProperties.isMinifyEnabled + isShrinkResources = buildTypeProperties.isShrinkResources + } +} diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/AndroidLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/AndroidLibraryConventionPlugin.kt new file mode 100644 index 0000000..d256081 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/AndroidLibraryConventionPlugin.kt @@ -0,0 +1,76 @@ +package com.oliverspryn.gradle.plugin + +import com.android.build.api.dsl.LibraryBuildType +import com.android.build.api.dsl.LibraryExtension +import com.oliverspryn.gradle.BuildConfig +import com.oliverspryn.gradle.extension.configureAndroidBaseVersion +import com.oliverspryn.gradle.extension.configureKotlinAndroid +import com.oliverspryn.gradle.extension.findPluginId +import com.oliverspryn.gradle.extension.libs +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure + +class AndroidLibraryConventionPlugin : BaseAndroidConventionPlugin() { + override fun apply(target: Project) { + super.apply(target) + + with(target) { + with(pluginManager) { + apply(libs.findPluginId("android-library")) + } + + extensions.configure { + configureAndroidBaseVersion(this) + configureKotlinAndroid(this) + + namespace = BuildConfig.App.NAMESPACE + + defaultConfig { + vectorDrawables { + useSupportLibrary = true + } + } + + buildTypes { + BuildConfig.App.BUILD_TYPES.forEach { buildTypeProperties -> + if (buildTypeProperties.isBuiltInBuildType) { + getByName(buildTypeProperties.name) { + setupBuildType( + buildTypes = this@buildTypes, + applicationBuildType = this, + buildTypeProperties = buildTypeProperties + ) + } + } else { + create(buildTypeProperties.name) { + setupBuildType( + buildTypes = this@buildTypes, + applicationBuildType = this, + buildTypeProperties = buildTypeProperties + ) + } + } + } + } + + buildFeatures { + buildConfig = true + } + } + } + } + + private fun setupBuildType( + buildTypes: NamedDomainObjectContainer, + applicationBuildType: LibraryBuildType, + buildTypeProperties: BuildConfig.BuildType + ) = with(applicationBuildType) { + buildTypeProperties.initWithOtherPreExistingBuildType?.let { + initWith(buildTypes.getByName(it)) + } + + enableUnitTestCoverage = buildTypeProperties.enableUnitTestCoverage + isMinifyEnabled = buildTypeProperties.isMinifyEnabled + } +} diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/BaseAndroidConventionPlugin.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/BaseAndroidConventionPlugin.kt new file mode 100644 index 0000000..7d03baa --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/BaseAndroidConventionPlugin.kt @@ -0,0 +1,16 @@ +package com.oliverspryn.gradle.plugin + +import com.oliverspryn.gradle.extension.findPluginId +import com.oliverspryn.gradle.extension.libs +import org.gradle.api.Plugin +import org.gradle.api.Project + +abstract class BaseAndroidConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + with(pluginManager) { + apply(libs.findPluginId("kotlin-android")) + } + } + } +} diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/BaseComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/BaseComposeConventionPlugin.kt new file mode 100644 index 0000000..ae5d084 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/BaseComposeConventionPlugin.kt @@ -0,0 +1,18 @@ +package com.oliverspryn.gradle.plugin + +import com.oliverspryn.gradle.extension.findLibraryId +import com.oliverspryn.gradle.extension.libs +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.dependencies + +abstract class BaseComposeConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + dependencies { + val compose = libs.findLibraryId("compose-bom") + add("implementation", platform(compose)) + } + } + } +} diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/BaseComposeLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/BaseComposeLibraryConventionPlugin.kt new file mode 100644 index 0000000..f673a55 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/BaseComposeLibraryConventionPlugin.kt @@ -0,0 +1,19 @@ +package com.oliverspryn.gradle.plugin + +import com.android.build.api.dsl.LibraryExtension +import com.oliverspryn.gradle.extension.configureCompose +import com.oliverspryn.gradle.extension.libs +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure + +open class BaseComposeLibraryConventionPlugin : BaseComposeConventionPlugin() { + override fun apply(target: Project) { + super.apply(target) + + with(target) { + extensions.configure { + configureCompose(this, libs) + } + } + } +} diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/ComposeApplicationConventionPlugin.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/ComposeApplicationConventionPlugin.kt new file mode 100644 index 0000000..e65e5b9 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/ComposeApplicationConventionPlugin.kt @@ -0,0 +1,37 @@ +package com.oliverspryn.gradle.plugin + +import com.android.build.api.dsl.ApplicationExtension +import com.oliverspryn.gradle.BuildConfig +import com.oliverspryn.gradle.extension.configureCompose +import com.oliverspryn.gradle.extension.findLibraryId +import com.oliverspryn.gradle.extension.libs +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.dependencies + +class ComposeApplicationConventionPlugin : BaseComposeConventionPlugin() { + override fun apply(target: Project) { + super.apply(target) + + with(target) { + extensions.configure { + configureCompose(this, libs) + } + + dependencies { + add("implementation", libs.findLibraryId("activity-compose")) + add("implementation", libs.findLibraryId("material3")) + add("implementation", libs.findLibraryId("navigation")) + add("implementation", libs.findLibraryId("ui")) + add("implementation", libs.findLibraryId("ui-graphics")) + add("implementation", libs.findLibraryId("ui-tooling-preview")) + + // Required to include these dependencies for each build type + BuildConfig.App.BUILD_TYPES.forEach { variant -> + add("${variant.name}Implementation", libs.findLibraryId("ui-test-manifest")) + add("${variant.name}Implementation", libs.findLibraryId("ui-tooling")) + } + } + } + } +} diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/DokkaConventionPlugin.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/DokkaConventionPlugin.kt new file mode 100644 index 0000000..9e0a48a --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/DokkaConventionPlugin.kt @@ -0,0 +1,24 @@ +package com.oliverspryn.gradle.plugin + +import com.oliverspryn.gradle.CentralRepository +import com.oliverspryn.gradle.extension.findPluginId +import com.oliverspryn.gradle.extension.libs +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.withType +import org.jetbrains.dokka.gradle.DokkaTaskPartial + +class DokkaConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + with(pluginManager) { + apply(libs.findPluginId("dokka")) + } + + tasks.withType().configureEach { + moduleName.set(CentralRepository.LIBRARY_NAME) + moduleVersion.set(CentralRepository.Artifact.VERSION) + } + } + } +} diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/HiltConventionPlugin.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/HiltConventionPlugin.kt new file mode 100644 index 0000000..65b6c7d --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/HiltConventionPlugin.kt @@ -0,0 +1,25 @@ +package com.oliverspryn.gradle.plugin + +import com.oliverspryn.gradle.extension.findLibraryId +import com.oliverspryn.gradle.extension.findPluginId +import com.oliverspryn.gradle.extension.libs +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.dependencies + +class HiltConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + with(pluginManager) { + apply(libs.findPluginId("hilt")) + apply(libs.findPluginId("ksp")) + } + + dependencies { + add("implementation", libs.findLibraryId("hilt-android")) + add("implementation", libs.findLibraryId("hilt-navigation-compose")) + add("ksp", libs.findLibraryId("hilt-compiler")) + } + } + } +} diff --git a/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/PublishConventionPlugin.kt b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/PublishConventionPlugin.kt new file mode 100644 index 0000000..fa43839 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/oliverspryn/gradle/plugin/PublishConventionPlugin.kt @@ -0,0 +1,112 @@ +package com.oliverspryn.gradle.plugin + +import com.android.build.api.dsl.LibraryExtension +import com.oliverspryn.gradle.BuildConfig +import com.oliverspryn.gradle.CentralRepository +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.artifacts.repositories.PasswordCredentials +import org.gradle.api.publish.PublishingExtension +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.authentication.http.BasicAuthentication +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.credentials +import org.gradle.kotlin.dsl.get +import org.gradle.kotlin.dsl.getByType +import org.gradle.kotlin.dsl.provideDelegate +import org.gradle.kotlin.dsl.repositories +import org.gradle.plugins.signing.SigningExtension + +class PublishConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + with(pluginManager) { + apply("maven-publish") + apply("signing") + } + + extensions.configure { + publishing { + singleVariant(BuildConfig.BuildType.Release.name) { + withJavadocJar() + withSourcesJar() + } + } + } + + group = CentralRepository.Artifact.GROUP_ID + version = CentralRepository.Artifact.VERSION + + extensions.configure { + publications { + create(CentralRepository.LIBRARY_NAME) { + groupId = CentralRepository.Artifact.GROUP_ID + artifactId = CentralRepository.Artifact.ID + version = CentralRepository.Artifact.VERSION + + afterEvaluate { + from(components["release"]) + } + + pom { + name.set(CentralRepository.Project.NAME) + description.set(CentralRepository.Project.DESCRIPTION) + url.set(CentralRepository.Project.URL) + + developers { + developer { + id.set(CentralRepository.Developer.ID) + name.set(CentralRepository.Developer.NAME) + url.set(CentralRepository.Developer.URL) + } + } + + issueManagement { + url.set("https://${CentralRepository.SCM.URL}/issues") + } + + licenses { + license { + name.set(CentralRepository.License.NAME) + name.set(CentralRepository.License.URL) + } + } + + scm { + connection.set("scm:git:git://${CentralRepository.SCM.URL}.git") + developerConnection.set("scm:git:ssh://${CentralRepository.SCM.URL}.git") + url.set("https://${CentralRepository.SCM.URL}") + } + } + } + } + + repositories { + maven { + val releaseUri = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") + val snapshotUri = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/") + + name = "central" + url = if (CentralRepository.Artifact.VERSION.endsWith("SNAPSHOT")) snapshotUri else releaseUri + + credentials(PasswordCredentials::class) + + authentication { + create("basic") + } + } + } + } + + extensions.configure { + @Suppress("ktlint:standard:property-naming") + val GPG_SIGNING_KEY: String? by project + val GPG_SIGNING_KEY_PASSWORD: String? by project + + useInMemoryPgpKeys(GPG_SIGNING_KEY, GPG_SIGNING_KEY_PASSWORD) + sign(extensions.getByType().publications[CentralRepository.LIBRARY_NAME]) + } + } + } +} diff --git a/build-logic/gradle.properties b/build-logic/gradle.properties new file mode 100644 index 0000000..1c9073e --- /dev/null +++ b/build-logic/gradle.properties @@ -0,0 +1,4 @@ +# Gradle properties are not passed to included builds https://github.com/gradle/gradle/issues/2534 +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.configureondemand=true diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts new file mode 100644 index 0000000..0a1095d --- /dev/null +++ b/build-logic/settings.gradle.kts @@ -0,0 +1,15 @@ +dependencyResolutionManagement { + repositories { + google() + mavenCentral() + } + + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} + +rootProject.name = "RootBuildLogic" +include(":convention") diff --git a/build.gradle.kts b/build.gradle.kts index ec5464a..7bfbeec 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,32 +1,8 @@ -import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask - plugins { - id("com.android.application") version Versions.ANDROID_APPLICATION_PLUGIN apply false - id("com.android.library") version Versions.ANDROID_LIBRARY_PLUGIN apply false - id("com.github.ben-manes.versions") version Versions.GRADLE_PLUGIN_VERSIONS - id("com.google.dagger.hilt.android") version Versions.DAGGER apply false - id("org.jetbrains.dokka") version Versions.DOKKA - id("org.jetbrains.kotlin.android") version Versions.KOTLIN apply false -} - -tasks.create("clean") { - delete(rootProject.buildDir) -} - -fun isNonStable(version: String): Boolean { - val stableKeyword = listOf("RELEASE", "FINAL", "GA").any { version.toUpperCase().contains(it) } - val regex = "^[0-9,.v-]+(-r)?$".toRegex() - val isStable = stableKeyword || regex.matches(version) - return isStable.not() -} - -tasks.named("dependencyUpdates").configure { - rejectVersionIf { - isNonStable(candidate.version) - } - - checkForGradleUpdate = true - outputFormatter = "html" - outputDir = "build/dependencyUpdates" - reportfileName = "report" + alias(libs.plugins.android.application) apply false + alias(libs.plugins.android.library) apply false + alias(libs.plugins.dokka) + alias(libs.plugins.hilt) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.ksp) apply false } diff --git a/buildSrc/.gitignore b/buildSrc/.gitignore deleted file mode 100644 index 796b96d..0000000 --- a/buildSrc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts deleted file mode 100644 index cc02e63..0000000 --- a/buildSrc/build.gradle.kts +++ /dev/null @@ -1,7 +0,0 @@ -plugins { - `kotlin-dsl` -} - -repositories { - gradlePluginPortal() -} diff --git a/buildSrc/src/main/kotlin/Config.kt b/buildSrc/src/main/kotlin/Config.kt deleted file mode 100644 index b8162e9..0000000 --- a/buildSrc/src/main/kotlin/Config.kt +++ /dev/null @@ -1,4 +0,0 @@ -object Config { - const val APPLICATION_ID = "com.oliverspryn.android.multimodal" - const val PROJECT_NAME = "Multimodal Spanner" -} diff --git a/buildSrc/src/main/kotlin/Libraries.kt b/buildSrc/src/main/kotlin/Libraries.kt deleted file mode 100644 index 11c0423..0000000 --- a/buildSrc/src/main/kotlin/Libraries.kt +++ /dev/null @@ -1,19 +0,0 @@ -object Libraries { - // region Application - - const val ACTIVITY_COMPOSE = "androidx.activity:activity-compose" - const val COMPOSE_MANIFEST_TEST = "androidx.compose.ui:ui-test-manifest" - const val COMPOSE_UI = "androidx.compose.ui:ui" - const val COMPOSE_UI_UNIT = "androidx.compose.ui:ui-unit" - const val COMPOSE_UI_TOOLING = "androidx.compose.ui:ui-tooling" - const val COMPOSE_UI_TOOLING_PREVIEW = "androidx.compose.ui:ui-tooling-preview" - const val CORE_KTX = "androidx.core:core-ktx" - const val DAGGER_ANDROID = "com.google.dagger:hilt-android" - const val DAGGER_COMPILER = "com.google.dagger:hilt-compiler" - const val MATERIAL = "com.google.android.material:material" - const val MATERIAL_3 = "androidx.compose.material3:material3" - const val NAVIGATION_COMPOSE = "androidx.navigation:navigation-compose" - const val WINDOW_MANAGER = "androidx.window:window" - - // endregion -} diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt deleted file mode 100644 index 7dda050..0000000 --- a/buildSrc/src/main/kotlin/Versions.kt +++ /dev/null @@ -1,49 +0,0 @@ -import org.gradle.api.JavaVersion - -object Versions { - // region App & Build Tool definitions - - const val COMPILE_SDK = 33 - const val MIN_SDK = 21 - const val TARGET_SDK = 33 - - const val VERSION_CODE = 1 - const val VERSION_NAME = CentralRepository.Artifact.VERSION - - // endregion - - // region Core Libraries - - const val ANDROID_APPLICATION_PLUGIN = "7.4.1" - const val ANDROID_LIBRARY_PLUGIN = "7.4.1" - const val COMPOSE = "1.3.3" // Reference this list for a the latest version: - const val COMPOSE_COMPILER = "1.4.3" // https://developer.android.com/jetpack/androidx/releases/compose - const val DAGGER = "2.45" - const val DOKKA = "1.7.20" - val JVM = JavaVersion.VERSION_11 - const val JVM_STRING = "11" - const val KOTLIN = "1.8.10" - - // endregion - - ///////////////////////////////////////////////////////////////////// - - // region Application - - const val ACTIVITY_COMPOSE = "1.6.1" - const val CORE_KTX = "1.9.0" - const val MATERIAL = "1.8.0" - const val MATERIAL_3 = "1.0.1" - const val NAVIGATION_COMPOSE = "2.5.3" - const val WINDOW_MANAGER = "1.0.0" - - // endregion - - ///////////////////////////////////////////////////////////////////// - - // region Gradle tooling - - const val GRADLE_PLUGIN_VERSIONS = "0.46.0" - - // endregion -} diff --git a/constraints/build.gradle.kts b/constraints/build.gradle.kts deleted file mode 100644 index f508917..0000000 --- a/constraints/build.gradle.kts +++ /dev/null @@ -1,25 +0,0 @@ -plugins { - id("java-platform") -} - -dependencies { - constraints { - // region Application - - api("${Libraries.ACTIVITY_COMPOSE}:${Versions.ACTIVITY_COMPOSE}") - api("${Libraries.COMPOSE_MANIFEST_TEST}:${Versions.COMPOSE}") - api("${Libraries.COMPOSE_UI}:${Versions.COMPOSE}") - api("${Libraries.COMPOSE_UI_UNIT}:${Versions.COMPOSE}") - api("${Libraries.COMPOSE_UI_TOOLING}:${Versions.COMPOSE}") - api("${Libraries.COMPOSE_UI_TOOLING_PREVIEW}:${Versions.COMPOSE}") - api("${Libraries.CORE_KTX}:${Versions.CORE_KTX}") - api("${Libraries.DAGGER_ANDROID}:${Versions.DAGGER}") - api("${Libraries.DAGGER_COMPILER}:${Versions.DAGGER}") - api("${Libraries.MATERIAL}:${Versions.MATERIAL}") - api("${Libraries.MATERIAL_3}:${Versions.MATERIAL_3}") - api("${Libraries.NAVIGATION_COMPOSE}:${Versions.NAVIGATION_COMPOSE}") - api("${Libraries.WINDOW_MANAGER}:${Versions.WINDOW_MANAGER}") - - // endregion - } -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..2801e97 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,66 @@ +[versions] +# Core +agp = "8.2.2" +dokka = "1.9.10" +hilt = "2.50" +hilt-navigation-compose = "1.1.0" +kotlin = "1.9.22" # KSP and Kotlin must... +ksp = "1.9.22-1.0.17" # ... share the same major.minor.patch version + +# AndroidX +activity-ktx = "1.8.2" +material = "1.11.0" +window = "1.2.0" + +# Jetpack Compose +compose = "2024.01.00" +compose-compiler = "1.5.8" +compose-ui-unit = "1.6.0" +navigation = "2.7.6" + +# Other + +[libraries] +# AndroidX +material = { group = "com.google.android.material", name = "material", version.ref = "material" } +window = { group = "androidx.window", name = "window", version.ref = "window" } + +# Build Logic +agp = { group = "com.android.tools.build", name = "gradle", version.ref = "agp" } +dokka = { group = "org.jetbrains.dokka", name = "dokka-gradle-plugin", version.ref = "dokka" } +kotlin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } + +# Dagger Hilt +hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" } +hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" } +hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hilt-navigation-compose" } + +# Jetpack Compose +activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-ktx" } +compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose" } +material3 = { group = "androidx.compose.material3", name = "material3" } +navigation = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" } +ui = { group = "androidx.compose.ui", name = "ui" } +ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +ui-unit = { group = "androidx.compose.ui", name = "ui-unit", version.ref = "compose-ui-unit" } # Versioned outside of the BOM for minimal version conflicts with apps using this library + +[plugins] +# Core +android-application = { id = "com.android.application", version.ref = "agp" } +android-library = { id = "com.android.library", version.ref = "agp" } +dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } +hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } + +# Multimodal Spanner Convention Plugins +multimodal-app = { id = "multimodal.app", version = "unspecified" } +multimodal-compose-app = { id = "multimodal.compose-app", version = "unspecified" } +multimodal-compose-library-base = { id = "multimodal.compose-library-base", version = "unspecified" } +multimodal-dokka = { id = "multimodal.dokka", version = "unspecified" } +multimodal-hilt = { id = "multimodal.hilt", version = "unspecified" } +multimodal-library = { id = "multimodal.library", version = "unspecified" } +multimodal-publish = { id = "multimodal.publish", version = "unspecified" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d752ba5..4bdc122 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue Jan 11 16:54:21 EST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/multimodal/build.gradle.kts b/multimodal/build.gradle.kts index ed168df..9b0a21b 100644 --- a/multimodal/build.gradle.kts +++ b/multimodal/build.gradle.kts @@ -1,155 +1,14 @@ -import org.jetbrains.dokka.gradle.DokkaTaskPartial - plugins { - `maven-publish` - signing - - id("com.android.library") - id("org.jetbrains.dokka") version Versions.DOKKA - kotlin("android") - kotlin("kapt") -} - -apply(plugin = "org.jetbrains.dokka") - -android { - compileSdk = Versions.COMPILE_SDK - namespace = Config.APPLICATION_ID - - defaultConfig { - minSdk = Versions.MIN_SDK - targetSdk = Versions.TARGET_SDK - - vectorDrawables { - useSupportLibrary = true - } - } - - buildTypes { - getByName("debug") { - isMinifyEnabled = false - isTestCoverageEnabled = true - } - - getByName("release") { - isMinifyEnabled = false - } - } + alias(libs.plugins.multimodal.library) - compileOptions { - sourceCompatibility = Versions.JVM - targetCompatibility = Versions.JVM - } - - kotlinOptions { - jvmTarget = Versions.JVM_STRING - } - - buildFeatures { - compose = true - } - - composeOptions { - kotlinCompilerExtensionVersion = Versions.COMPOSE_COMPILER - } - - publishing { - singleVariant("release") { - withJavadocJar() - withSourcesJar() - } - } + alias(libs.plugins.multimodal.compose.library.base) + alias(libs.plugins.multimodal.dokka) + alias(libs.plugins.multimodal.publish) } dependencies { - api(platform(project(":constraints"))) - kapt(platform(project(":constraints"))) - - ///////////////////////////////////////////////////////////////////// - - // region Application - - implementation(Libraries.ACTIVITY_COMPOSE) - implementation(Libraries.COMPOSE_UI_UNIT) - implementation(Libraries.WINDOW_MANAGER) - - // endregion -} - -///////////////////////////////////////////////////////////////////// - -group = CentralRepository.Artifact.GROUP_ID -version = CentralRepository.Artifact.VERSION - -publishing { - publications { - create(CentralRepository.LIBRARY_NAME) { - groupId = CentralRepository.Artifact.GROUP_ID - artifactId = CentralRepository.Artifact.ID - version = CentralRepository.Artifact.VERSION - - afterEvaluate { - from(components["release"]) - } - - pom { - name.set(CentralRepository.Project.NAME) - description.set(CentralRepository.Project.DESCRIPTION) - url.set(CentralRepository.Project.URL) - - developers { - developer { - id.set(CentralRepository.Developer.ID) - name.set(CentralRepository.Developer.NAME) - url.set(CentralRepository.Developer.URL) - } - } - - issueManagement { - url.set("https://${CentralRepository.SCM.URL}/issues") - } - - licenses { - license { - name.set(CentralRepository.License.NAME) - name.set(CentralRepository.License.URL) - } - } - - scm { - connection.set("scm:git:git://${CentralRepository.SCM.URL}.git") - developerConnection.set("scm:git:ssh://${CentralRepository.SCM.URL}.git") - url.set("https://${CentralRepository.SCM.URL}") - } - } - } - } - - repositories { - maven { - val releaseUri = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") - val snapshotUri = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/") - - name = "central" - url = if (CentralRepository.Artifact.VERSION.endsWith("SNAPSHOT")) snapshotUri else releaseUri - - credentials(PasswordCredentials::class) - - authentication { - create("basic") - } - } - } -} - -signing { - val GPG_SIGNING_KEY: String? by project - val GPG_SIGNING_KEY_PASSWORD: String? by project - useInMemoryPgpKeys(GPG_SIGNING_KEY, GPG_SIGNING_KEY_PASSWORD) - sign(publishing.publications[CentralRepository.LIBRARY_NAME]) -} - -tasks.withType().configureEach { - moduleName.set(Config.PROJECT_NAME) - moduleVersion.set(CentralRepository.Artifact.VERSION) + // Uses api() instead of implementation() to expose the libraries to the consumers + api(libs.activity.compose) + api(libs.ui.unit) + api(libs.window) } diff --git a/multimodal/src/main/java/com/oliverspryn/android/multimodal/exceptions/MissingActivityException.kt b/multimodal/src/main/java/com/oliverspryn/android/multimodal/exceptions/MissingActivityException.kt deleted file mode 100644 index cf16d59..0000000 --- a/multimodal/src/main/java/com/oliverspryn/android/multimodal/exceptions/MissingActivityException.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.oliverspryn.android.multimodal.exceptions - -/** - * Indicates that the framework was not initialized properly by providing - * a [androidx.activity.ComponentActivity] (or one of it's child classes) - * to the initialization function prior to usage. - * - * @see com.oliverspryn.android.multimodal.ScreenCapture - * @see com.oliverspryn.android.multimodal.ScreenCapture.init - */ -object MissingActivityException : - Throwable("No activity is available to the framework. Did you call ScreenCapture.init(activity) before making any other calls?") diff --git a/multimodal/src/main/java/com/oliverspryn/android/multimodal/Classifier.kt b/multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/Classifier.kt similarity index 91% rename from multimodal/src/main/java/com/oliverspryn/android/multimodal/Classifier.kt rename to multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/Classifier.kt index e312da1..d4b716e 100644 --- a/multimodal/src/main/java/com/oliverspryn/android/multimodal/Classifier.kt +++ b/multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/Classifier.kt @@ -8,12 +8,13 @@ import com.oliverspryn.android.multimodal.model.ScreenClassifier import com.oliverspryn.android.multimodal.model.WindowSizeClass /** - * Uses information about the device's foldable posture and the size - * of the screen to determine what posture the screen is in and all - * of the information that can be extracted about the size of the screen - * and where its hinge is located. + * Uses information about the device's foldable posture and the size of the + * screen to determine what posture the screen is in and all information + * that can be extracted about the size of the screen and where its hinge + * is located. * - * @constructor A default instance of this class without any initialization or other actions. + * @constructor A default instance of this class without any initialization + * or other actions. */ class Classifier { @@ -28,19 +29,21 @@ class Classifier { private val MEDIUM_WIDTH_BREAKPOINT = 840.dp } - /** * Classifies the device as either fully opened or a foldable in one of - * several possible postures, based on the information given to it - * about the app's window. + * several possible postures, based on the information given to it about + * the app's window. * * The window's size class uses breakpoints following Google's recommended * practices, as defined here: * [Window Size Classes](https://developer.android.com/guide/topics/large-screens/support-different-screen-sizes#window_size_classes). * - * @param foldingFeature A physical description of the screen's folded state, if a hinge is present. - * @param windowDpSize A rectangle indicating the X and Y dimensions of the screen in DPs (density-independent pixels). - * @return Data modeling the complete posture and size of the device's screen. + * @param foldingFeature A physical description of the screen's folded + * state, if a hinge is present. + * @param windowDpSize A rectangle indicating the X and Y dimensions of the + * screen in DPs (density-independent pixels). + * @return Data modeling the complete posture and size of the device's + * screen. */ fun createClassifier(foldingFeature: FoldingFeature?, windowDpSize: DpSize) = when { foldingFeature == null -> createFullyOpenedDevice(windowDpSize) diff --git a/multimodal/src/main/java/com/oliverspryn/android/multimodal/ScreenCapture.kt b/multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/ScreenCapture.kt similarity index 71% rename from multimodal/src/main/java/com/oliverspryn/android/multimodal/ScreenCapture.kt rename to multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/ScreenCapture.kt index b01433c..6a50b7a 100644 --- a/multimodal/src/main/java/com/oliverspryn/android/multimodal/ScreenCapture.kt +++ b/multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/ScreenCapture.kt @@ -18,25 +18,26 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn /** - * Captures raw, unclassified data about the the screen's dimensions and + * Captures raw, unclassified data about the screen's dimensions and * information about the device's hinge, assuming it is present. * - * @constructor A default instance of this class without any initialization or other actions. + * @constructor A default instance of this class without any initialization + * or other actions. */ class ScreenCapture { private var activity: ComponentActivity? = null /** - * For use outside of composable functions. + * For use outside composable functions. * - * Initializes the capture class with a copy of the activity it will be using - * to measure the screen against. + * Initializes the capture class with a copy of the activity it will be + * using to measure the screen against. * - * This function is broken out separately from the constructor so that you can - * use the [ScreenCapture] class itself inside of DI framework, like Hilt, and - * later setup the capturing capabilities in the onCreate() function - * of a [ComponentActivity]. + * This function is broken out separately from the constructor so that + * you can use the [ScreenCapture] class itself inside of DI framework, + * like Hilt, and later set up the capturing capabilities in the + * `onCreate()` function of a [ComponentActivity]. * * @param activity An activity which will be used to measure the screen. */ @@ -45,15 +46,16 @@ class ScreenCapture { } /** - * For use outside of composable functions. - * [init] must be called first! + * For use outside composable functions. [init] must be called first! * - * Captures the raw, unclassified data from the video about the state of a foldable - * hinge, if it is present. All updates are pushed with real time updates via a - * Kotlin [StateFlow] object. + * Captures the raw, unclassified data from the video about the state of a + * foldable hinge, if it is present. All updates are pushed with real time + * updates via a Kotlin [StateFlow] object. * - * @throws MissingActivityException If the [init] function isn't called before this one. - * @return Raw data about the device's foldable hinge, pushed in real time via a Kotlin [StateFlow] object. + * @return Raw data about the device's foldable hinge, pushed in real time + * via a Kotlin [StateFlow] object. + * @throws MissingActivityException If the [init] function isn't called + * before this one. */ fun foldingFeature(): StateFlow { val requiredActivity = activity ?: throw MissingActivityException @@ -74,16 +76,18 @@ class ScreenCapture { } /** - * For use in composable functions only. - * [init] must be called first! + * For use in composable functions only. [init] must be called first! * - * Returns the raw, unprocessed data showing the X and Y dimensions of the window, - * measured in DPs (density-independent pixels). These updates are properly adjusted - * when the app is in split mode or windowed mode. It will then measure the size of - * the app's window, instead of the entire screen. + * Returns the raw, unprocessed data showing the X and Y dimensions of the + * window, measured in DPs (density-independent pixels). These updates are + * properly adjusted when the app is in split mode or windowed mode. It + * will then measure the size of the app's window, instead of the entire + * screen. * - * @throws MissingActivityException If the [init] function isn't called before this one. - * @return Current size of the app window, taking into account full screen, split screen, and windowed apps. + * @return Current size of the app window, taking into account full screen, + * split screen, and windowed apps. + * @throws MissingActivityException If the [init] function isn't called + * before this one. */ @Composable fun windowDpSize(): DpSize { diff --git a/multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/exceptions/MissingActivityException.kt b/multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/exceptions/MissingActivityException.kt new file mode 100644 index 0000000..8a6400e --- /dev/null +++ b/multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/exceptions/MissingActivityException.kt @@ -0,0 +1,15 @@ +package com.oliverspryn.android.multimodal.exceptions + +import androidx.activity.ComponentActivity +import com.oliverspryn.android.multimodal.ScreenCapture + +/** + * Indicates that the framework was not initialized properly by providing a + * [ComponentActivity] (or one of its child classes) to the initialization + * function prior to usage. + * + * @see ScreenCapture + * @see ScreenCapture.init + */ +object MissingActivityException : + Throwable("No Activity is available to the framework. Did you call ScreenCapture.init(activity) before making any other calls?") diff --git a/multimodal/src/main/java/com/oliverspryn/android/multimodal/model/Dimension.kt b/multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/model/Dimension.kt similarity index 81% rename from multimodal/src/main/java/com/oliverspryn/android/multimodal/model/Dimension.kt rename to multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/model/Dimension.kt index d8c6279..1b36f44 100644 --- a/multimodal/src/main/java/com/oliverspryn/android/multimodal/model/Dimension.kt +++ b/multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/model/Dimension.kt @@ -7,12 +7,14 @@ import androidx.compose.ui.unit.Dp * such as either the X axis or Y axis. Two [Dimension] classes together * are used to define the complete dimensions of a screen along both axes. * - * @constructor A measurement and classification of the screen size. * @param dp Size of the screen in DPs (density-independent pixels). - * @param sizeClass Classification of the screen size based on pre-defined breakpoints defined by Google, as followed in [ScreenClassifier]. + * @param sizeClass Classification of the screen size based on pre-defined + * breakpoints defined by Google, as followed in [ScreenClassifier]. + * @constructor A measurement and classification of the screen size. * @property dp Size of the screen in DPs (density-independent pixels). - * @property sizeClass Classification of the screen size based on pre-defined breakpoints defined by Google, as followed in [ScreenClassifier]. - * + * @property sizeClass Classification of the screen size based on + * pre-defined breakpoints defined by Google, as followed in + * [ScreenClassifier]. * @see ScreenClassifier * @see WindowSizeClass */ diff --git a/multimodal/src/main/java/com/oliverspryn/android/multimodal/model/ScreenClassifier.kt b/multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/model/ScreenClassifier.kt similarity index 67% rename from multimodal/src/main/java/com/oliverspryn/android/multimodal/model/ScreenClassifier.kt rename to multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/model/ScreenClassifier.kt index 751c561..f1b1fa8 100644 --- a/multimodal/src/main/java/com/oliverspryn/android/multimodal/model/ScreenClassifier.kt +++ b/multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/model/ScreenClassifier.kt @@ -54,14 +54,27 @@ sealed interface ScreenClassifier { val occlusionType: FoldingFeature.OcclusionType /** - * Indicates the device is in book mode, where the hinge runs from top to bottom - * and the device is in a folded position, like the natural use of a book. + * Indicates the device is in book mode, where the hinge runs from top to + * bottom and the device is in a folded position, like the natural use of a + * book. * - * @constructor All of the available information about a foldable screen in book mode. - * @param hingePosition Indicates the DP position through which the hinge cuts through the physical screen, whether it is horizontal a vertical. - * @param hingeSeparationRatio Number between 0 and 1 indicating where the hinge lives. Often is 0.5 for most foldable devices with apps in full-screen mode, since most hinges run down the center of the screen. Apps in floating window mode will see this value change as the app is dragged around, moving its position relative to the device's hinge. Does not indicate the up/down or left/right direction of the hinge. See [hingePosition] for information on that. - * @param isSeparating Indicates whether the hinge is visually diving the screen (like Microsoft Surface Duo) or seamless (like Samsung Galaxy Z Fold + Z Flip). - * @param occlusionType Indicates if the screen is or is not obscured in any way by the hinge. + * @param hingePosition Indicates the DP position through which the hinge + * cuts through the physical screen, whether it is horizontal a + * vertical. + * @param hingeSeparationRatio Number between 0 and 1 indicating where the + * hinge lives. Often is 0.5 for most foldable devices with apps in + * full-screen mode, since most hinges run down the center of the + * screen. Apps in floating window mode will see this value change as + * the app is dragged around, moving its position relative to the + * device's hinge. Does not indicate the up/down or left/right + * direction of the hinge. See [hingePosition] for information on that. + * @param isSeparating Indicates whether the hinge is visually diving the + * screen (like Microsoft Surface Duo) or seamless (like Samsung Galaxy + * Z Fold + Z Flip). + * @param occlusionType Indicates if the screen is or is not obscured in + * any way by the hinge. + * @constructor All available information about a foldable screen in book + * mode. */ data class BookMode( override val hingePosition: Rect, @@ -71,14 +84,27 @@ sealed interface ScreenClassifier { ) : HalfOpened /** - * Indicates the device is in tabletop mode, where the hinge runs from left to right - * and device is in a folded position, much like how a laptop would sit on a table. + * Indicates the device is in tabletop mode, where the hinge runs from left + * to right and device is in a folded position, much like how a laptop + * would sit on a table. * - * @constructor All of the available information about a foldable screen in tabletop mode. - * @param hingePosition Indicates the DP position through which the hinge cuts through the physical screen, whether it is horizontal a vertical. - * @param hingeSeparationRatio Number between 0 and 1 indicating where the hinge lives. Often is 0.5 for most foldable devices with apps in full-screen mode, since most hinges run down the center of the screen. Apps in floating window mode will see this value change as the app is dragged around, moving its position relative to the device's hinge. Does not indicate the up/down or left/right direction of the hinge. See [hingePosition] for information on that. - * @param isSeparating Indicates whether the hinge is visually diving the screen (like Microsoft Surface Duo) or seamless (like Samsung Galaxy Z Fold + Z Flip). - * @param occlusionType Indicates if the screen is or is not obscured in any way by the hinge. + * @param hingePosition Indicates the DP position through which the hinge + * cuts through the physical screen, whether it is horizontal a + * vertical. + * @param hingeSeparationRatio Number between 0 and 1 indicating where the + * hinge lives. Often is 0.5 for most foldable devices with apps in + * full-screen mode, since most hinges run down the center of the + * screen. Apps in floating window mode will see this value change as + * the app is dragged around, moving its position relative to the + * device's hinge. Does not indicate the up/down or left/right + * direction of the hinge. See [hingePosition] for information on that. + * @param isSeparating Indicates whether the hinge is visually diving the + * screen (like Microsoft Surface Duo) or seamless (like Samsung Galaxy + * Z Fold + Z Flip). + * @param occlusionType Indicates if the screen is or is not obscured in + * any way by the hinge. + * @constructor All available information about a foldable screen in + * tabletop mode. */ data class TableTopMode( override val hingePosition: Rect, diff --git a/multimodal/src/main/java/com/oliverspryn/android/multimodal/model/WindowSizeClass.kt b/multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/model/WindowSizeClass.kt similarity index 66% rename from multimodal/src/main/java/com/oliverspryn/android/multimodal/model/WindowSizeClass.kt rename to multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/model/WindowSizeClass.kt index 168ddea..7fef993 100644 --- a/multimodal/src/main/java/com/oliverspryn/android/multimodal/model/WindowSizeClass.kt +++ b/multimodal/src/main/kotlin/com/oliverspryn/android/multimodal/model/WindowSizeClass.kt @@ -1,16 +1,18 @@ package com.oliverspryn.android.multimodal.model +import com.oliverspryn.android.multimodal.Classifier + /** * Classifies a [ScreenClassifier.FullyOpened] screen into one of three - * size classes: Compact, Medium, or Expanded. Does not indicate a directional - * axis, and is used twice by the [com.oliverspryn.android.multimodal.Classifier] - * to individually represent the size of the screen along both the X and Y - * axes. + * size classes: Compact, Medium, or Expanded. Does not indicate a + * directional axis, and is used twice by the [Classifier] to individually + * represent the size of the screen along both the X and Y axes. * - * These breakpoints follow Google's recommended practices, as defined here: + * These breakpoints follow Google's recommended practices, as defined + * here: * [Window Size Classes](https://developer.android.com/guide/topics/large-screens/support-different-screen-sizes#window_size_classes). * - * @see com.oliverspryn.android.multimodal.Classifier + * @see Classifier * @see ScreenClassifier */ enum class WindowSizeClass { diff --git a/settings.gradle.kts b/settings.gradle.kts index dfe4311..fab0385 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,19 +1,23 @@ -pluginManagement { +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { google() - gradlePluginPortal() mavenCentral() } } -dependencyResolutionManagement { - repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) +pluginManagement { + includeBuild("build-logic") repositories { google() + gradlePluginPortal() mavenCentral() } } rootProject.name = "MultimodalSpanner" -include(":app", ":constraints", ":multimodal") + +include(":app") +include(":multimodal")