Skip to content

Commit

Permalink
Support Kotlin Multiplatform (#228)
Browse files Browse the repository at this point in the history
* Remove unused kotlinx.serialization

* Migrate to kotlin 2.0

* Change all 'java' folders to 'kotlin'

* Support Kotlin Multiplatform

* Add convention plugin for metalava

* Support KMP for ios

* Support KMP for macos

* Adjust CI timeout

* Fix navigation for samples

* Increase CI timeout
  • Loading branch information
fornewid authored Jun 6, 2024
1 parent a3bc68a commit c938f23
Show file tree
Hide file tree
Showing 96 changed files with 1,079 additions and 258 deletions.
16 changes: 11 additions & 5 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ on:

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 30
runs-on: macos-latest
timeout-minutes: 60

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -46,8 +46,14 @@ jobs:
- name: Check lint
run: ./gradlew lintDebug --stacktrace

- name: Build all build type and flavor permutations
run: ./gradlew assemble --stacktrace
- name: Build android app
run: ./gradlew :sample:android:assemble

- name: Build desktop app
run: ./gradlew :sample:desktop:assemble

- name: Build iOS app
run: xcodebuild -project sample/iosApp/iosApp.xcodeproj -scheme iosApp -destination 'platform=iOS Simulator,name=iPhone 14,OS=latest'

- name: Clean secrets
if: always()
Expand All @@ -56,7 +62,7 @@ jobs:
test:
needs: build
runs-on: ubuntu-latest
timeout-minutes: 30
timeout-minutes: 70

strategy:
matrix:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ captures/
.idea/navEditor.xml

# User-specific configurations
.idea/artifacts/
.idea/caches/
.idea/libraries/
.idea/shelf/
Expand Down Expand Up @@ -104,3 +105,5 @@ lint/generated/
lint/outputs/
lint/tmp/
# lint/reports/

.kotlin/
5 changes: 0 additions & 5 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 17 additions & 3 deletions build-logic/convention/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ java {
dependencies {
implementation(libs.android.pluginGradle)
implementation(libs.kotlin.pluginGradle)
implementation(libs.compose.compiler.pluginGradle)
implementation(libs.metalava.pluginGradle)
}

gradlePlugin {
Expand All @@ -24,9 +26,21 @@ gradlePlugin {
id = "mmc.android.library"
implementationClass = "AndroidLibraryConventionPlugin"
}
register("androidCompose") {
id = "mmc.android.compose"
implementationClass = "AndroidComposeConventionPlugin"
register("kotlinAndroid") {
id = "mmc.kotlin.android"
implementationClass = "KotlinAndroidConventionPlugin"
}
register("kotlinMultiplatform") {
id = "mmc.kotlin.multiplatform"
implementationClass = "KotlinMultiplatformConventionPlugin"
}
register("compose") {
id = "mmc.compose"
implementationClass = "ComposeMultiplatformConventionPlugin"
}
register("metalava") {
id = "mmc.metalava"
implementationClass = "MetalavaConventionPlugin"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ class AndroidApplicationConventionPlugin : Plugin<Project> {
with(target) {
with(pluginManager) {
apply("com.android.application")
apply("org.jetbrains.kotlin.android")
}
configureAndroid()
configureKotlin()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ class AndroidLibraryConventionPlugin : Plugin<Project> {
with(target) {
with(pluginManager) {
apply("com.android.library")
apply("org.jetbrains.kotlin.android")
}
configureAndroid()
configureKotlin()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import soup.compose.material.motion.buildlogic.configureCompose
import org.gradle.api.Plugin
import org.gradle.api.Project

class AndroidComposeConventionPlugin : Plugin<Project> {
class ComposeMultiplatformConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
configureCompose()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import org.gradle.api.Plugin
import org.gradle.api.Project
import soup.compose.material.motion.buildlogic.configureKotlin

class KotlinAndroidConventionPlugin: Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("org.jetbrains.kotlin.android")
}

configureKotlin()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.getByType
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import soup.compose.material.motion.buildlogic.configureKotlin

class KotlinMultiplatformConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("org.jetbrains.kotlin.multiplatform")

kotlin {
applyDefaultHierarchyTemplate()

if (pluginManager.hasPlugin("com.android.library")) {
androidTarget {
publishLibraryVariants("release")
}
}

jvm()

iosX64()
iosArm64()
iosSimulatorArm64()

macosX64()
macosArm64()

configureKotlin()
}
}
}
}

internal fun Project.kotlin(action: KotlinMultiplatformExtension.() -> Unit) {
extensions.configure<KotlinMultiplatformExtension>(action)
}

internal val Project.kotlin: KotlinMultiplatformExtension
get() = extensions.getByType<KotlinMultiplatformExtension>()
24 changes: 24 additions & 0 deletions build-logic/convention/src/main/kotlin/MetalavaConventionPlugin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import me.tylerbwong.gradle.metalava.extension.MetalavaExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure

class MetalavaConventionPlugin : Plugin<Project> {
override fun apply(target: Project) = with(target) {
with(pluginManager) {
apply("me.tylerbwong.gradle.metalava")
}

metalava {
filename.set("api/current.api")
sourcePaths.setFrom(
target.kotlin.sourceSets
.filterNot { it.name.contains("test", ignoreCase = true) }
.flatMap { it.kotlin.sourceDirectories },
)
}
}
}

private fun Project.metalava(action: MetalavaExtension.() -> Unit) =
extensions.configure<MetalavaExtension>(action)
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ fun Project.configureAndroid() {
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
package soup.compose.material.motion.buildlogic

import com.android.build.gradle.BaseExtension
import org.gradle.api.Project
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.getByType
import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension

fun Project.configureCompose() {
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
android {
buildFeatures.compose = true
pluginManager.apply("org.jetbrains.compose")
pluginManager.apply("org.jetbrains.kotlin.plugin.compose")

composeOptions {
kotlinCompilerExtensionVersion =
libs.findVersion("compose-compiler").get().toString()
}
extensions.configure<ComposeCompilerGradlePluginExtension> {
enableStrongSkippingMode = false
}
}

private fun Project.android(action: BaseExtension.() -> Unit) {
extensions.configure(action)
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package soup.compose.material.motion.buildlogic

import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask

fun Project.configureKotlin() {
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
tasks.withType<KotlinCompilationTask<*>>().configureEach {
compilerOptions {
if (this is KotlinJvmCompilerOptions) {
jvmTarget.set(JvmTarget.JVM_11)
}

freeCompilerArgs = freeCompilerArgs + listOf(
freeCompilerArgs.addAll(
"-opt-in=kotlin.RequiresOptIn",
)
}
Expand Down
1 change: 1 addition & 0 deletions build-logic/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
versionCatalogs {
create("libs") {
Expand Down
6 changes: 4 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
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.kotlin.serialization) apply false
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.kotlin.multiplatform) apply false
alias(libs.plugins.jetbrains.compose) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.metalava) apply false
alias(libs.plugins.maven.publish) apply false
alias(libs.plugins.jetbrains.dokka)
Expand Down
10 changes: 5 additions & 5 deletions core/api/current.api
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ package soup.compose.material.motion {
}

public final class MaterialFadeThroughKt {
method @androidx.compose.runtime.Composable public static <T> void MaterialFadeThrough(T? targetState, optional androidx.compose.ui.Modifier modifier, optional String label, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedVisibilityScope,? super T,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static <T> void MaterialFadeThrough(T targetState, optional androidx.compose.ui.Modifier modifier, optional String label, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedVisibilityScope,? super T,kotlin.Unit> content);
}

public final class MaterialMotionKt {
method @androidx.compose.runtime.Composable public static <S> void MaterialMotion(S? targetState, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<S>,androidx.compose.animation.ContentTransform> transitionSpec, optional androidx.compose.ui.Modifier modifier, optional boolean pop, optional androidx.compose.ui.Alignment contentAlignment, optional String label, optional kotlin.jvm.functions.Function1<? super S,?> contentKey, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedVisibilityScope,? super S,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static <S> void MaterialMotion(androidx.compose.animation.core.Transition<S>, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<S>,androidx.compose.animation.ContentTransform> transitionSpec, optional androidx.compose.ui.Modifier modifier, optional boolean pop, optional androidx.compose.ui.Alignment contentAlignment, optional kotlin.jvm.functions.Function1<? super S,?> contentKey, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedVisibilityScope,? super S,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static <S> void MaterialMotion(S targetState, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedContentTransitionScope<S>,androidx.compose.animation.ContentTransform> transitionSpec, optional androidx.compose.ui.Modifier modifier, optional boolean pop, optional androidx.compose.ui.Alignment contentAlignment, optional String label, optional kotlin.jvm.functions.Function1<? super S,?> contentKey, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedVisibilityScope,? super S,kotlin.Unit> content);
}

public final class MaterialSharedAxisKt {
method @androidx.compose.runtime.Composable public static <T> void MaterialSharedAxisX(T? targetState, boolean forward, optional androidx.compose.ui.Modifier modifier, optional float slideDistance, optional String label, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedVisibilityScope,? super T,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static <T> void MaterialSharedAxisY(T? targetState, boolean forward, optional androidx.compose.ui.Modifier modifier, optional float slideDistance, optional String label, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedVisibilityScope,? super T,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static <T> void MaterialSharedAxisZ(T? targetState, boolean forward, optional androidx.compose.ui.Modifier modifier, optional String label, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedVisibilityScope,? super T,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static <T> void MaterialSharedAxisX(T targetState, boolean forward, optional androidx.compose.ui.Modifier modifier, optional float slideDistance, optional String label, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedVisibilityScope,? super T,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static <T> void MaterialSharedAxisY(T targetState, boolean forward, optional androidx.compose.ui.Modifier modifier, optional float slideDistance, optional String label, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedVisibilityScope,? super T,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static <T> void MaterialSharedAxisZ(T targetState, boolean forward, optional androidx.compose.ui.Modifier modifier, optional String label, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedVisibilityScope,? super T,kotlin.Unit> content);
}

public final class MotionConstants {
Expand Down
62 changes: 20 additions & 42 deletions core/build.gradle
Original file line number Diff line number Diff line change
@@ -1,54 +1,32 @@
plugins {
id("mmc.android.library")
id("mmc.android.compose")
id("mmc.kotlin.multiplatform")
id("mmc.compose")
id("mmc.metalava")
alias(libs.plugins.maven.publish)
alias(libs.plugins.jetbrains.dokka)
alias(libs.plugins.metalava)
}

android {
namespace 'soup.compose.material.motion'
kotlinOptions {
freeCompilerArgs += '-Xexplicit-api=warning'
}
lint {
textReport true
textOutput file('stdout')
checkReleaseBuilds false
}
testOptions {
unitTests {
includeAndroidResources = true
kotlin {
explicitApi()
sourceSets {
commonMain.dependencies {
implementation(compose.animation)
implementation(compose.ui)
implementation(libs.androidx.annotation)
}
}
packagingOptions {
resources {
excludes += ['/META-INF/AL2.0', '/META-INF/LGPL2.1']
androidInstrumentedTest.dependencies {
implementation(libs.androidx.test.core)
implementation(libs.androidx.test.rules)
implementation(libs.androidx.test.runner)
implementation(libs.compose.foundation)
implementation(libs.compose.ui.testJunit4)
implementation(libs.compose.ui.testManifest)
implementation(libs.androidx.tracing)
}
}
}

metalava {
sourcePaths.setFrom("src/main")
filename.set("api/current.api")
reportLintsAsErrors.set(true)
}

dependencies {
implementation libs.kotlin.stdlib
implementation libs.compose.animation
implementation libs.compose.runtime
implementation libs.compose.ui.ui

// ======================
// Test dependencies
// ======================

androidTestImplementation libs.androidx.test.core
androidTestImplementation libs.androidx.test.rules
androidTestImplementation libs.androidx.test.runner
androidTestImplementation libs.compose.foundation
androidTestImplementation libs.compose.ui.testJunit4
debugImplementation libs.compose.ui.testManifest
debugImplementation libs.androidx.tracing
android {
namespace 'soup.compose.material.motion'
}
Loading

0 comments on commit c938f23

Please sign in to comment.