Skip to content

add Compose Multiplatform sample, using io.github.hoc081098:solivagant-navigation:0.3.0 #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Apr 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,4 @@ jobs:
run: chmod +x ./gradlew

- name: Build
run: ./gradlew :sample:app:assembleDebug --stacktrace
run: ./gradlew :sample:standalone-androidApp:assembleDebug :sample:standalone-composeMultiplatform:desktopApp:packageDistributionForCurrentOS --stacktrace
2 changes: 1 addition & 1 deletion .idea/deploymentTargetDropDown.xml

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

Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,9 @@ private class ChannelEventBusImpl(
*/
private fun markAsNotCollecting(key: ChannelEventKey<*>): Unit =
_busMap.synchronized {
_busMap[key] = _busMap[key]!!
// _busMap[key] can be null if it is removed and closed before calling this method.
// Just ignore in that case.
_busMap[key] = (_busMap[key] ?: return)
.copy(isCollecting = false)
.also { logger?.onStopCollection(key, this) }
}
Expand Down
3 changes: 3 additions & 0 deletions detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,9 @@ style:
UnusedPrivateMember:
active: true
allowedNames: '(_|ignored|expected|serialVersionUID)'
ignoreAnnotated:
- Preview
- androidx.compose.desktop.ui.tooling.preview.Preview
UseAnyOrNoneInsteadOfFind:
active: true
UseArrayLiteralsInAnnotations:
Expand Down
31 changes: 19 additions & 12 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[versions]
kotlin = "1.9.22"
coroutines = "1.8.0"
kotlin = "1.9.23"
coroutines = "1.8.1-Beta"
kotlinx-serialization-json = "1.6.3"
kotlinx-collections-immutable = "0.3.7"

Expand All @@ -12,9 +12,9 @@ java-toolchain = "17"
# the Android minSdkVersion to use
android-min = "21"
# the Android target to use
android-target = "33"
android-target = "34"
# the Android compileSdkVersion to use
android-compile = "33"
android-compile = "34"

android-gradle = "8.3.1"

Expand All @@ -23,22 +23,23 @@ sample-android-target = "34"
# the Android compileSdkVersion to use in sample
sample-android-compile = "34"

jetbrains-compose = "1.6.1"
jetbrains-compose = "1.6.2"

touchlab-stately = "2.0.6"
napier = "2.7.1"
flowExt = "0.8.0"
koin = "3.5.3"
koin-androidx-compose = "3.5.3"
flowExt = "0.8.1-Beta"
koin-core = "3.5.3"
koin-compose = "1.1.2"
coil = "2.6.0"
compose-rules-detekt = "0.3.12"

androidx-lifecycle = "2.7.0"
androidx-annotation = "1.7.1"
androidx-activity = "1.8.2"
androidx-compose-compiler = "1.5.9"
androidx-compose-compiler = "1.5.11"
androidx-navigation = "2.7.7"
kmp-viewmodel = "0.7.1"
solivagant = "0.3.0"
timber = "5.0.1"

spotless = "6.25.0"
Expand All @@ -54,6 +55,7 @@ ktlint = "0.50.0"
[libraries]
coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "coroutines" }
coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
coroutines-jdk8 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8", version.ref = "coroutines" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" }
Expand All @@ -64,9 +66,10 @@ jetbrains-compose-runtime = { module = "org.jetbrains.compose.runtime:runtime",
touchlab-stately-concurrency = { module = "co.touchlab:stately-concurrency", version.ref = "touchlab-stately" }
napier = { module = "io.github.aakira:napier", version.ref = "napier" }
flowExt = { module = "io.github.hoc081098:FlowExt", version.ref = "flowExt" }
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" }
koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin-androidx-compose" }
koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin-core" }
koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin-core" }
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin-core" }
koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin-compose" }
coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" }
compose-rules-detekt = { module = "io.nlopez.compose.rules:detekt", version.ref = "compose-rules-detekt" }

Expand All @@ -86,7 +89,11 @@ androidx-compose-material3 = { module = "androidx.compose.material3:material3" }
androidx-compose-runtime = { module = "androidx.compose.runtime:runtime" }
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidx-navigation" }

kmp-viewmodel = { module = "io.github.hoc081098:kmp-viewmodel", version.ref = "kmp-viewmodel" }
kmp-viewmodel-savedstate = { module = "io.github.hoc081098:kmp-viewmodel-savedstate", version.ref = "kmp-viewmodel" }
kmp-viewmodel-compose = { module = "io.github.hoc081098:kmp-viewmodel-compose", version.ref = "kmp-viewmodel" }
kmp-viewmodel-koin-compose = { module = "io.github.hoc081098:kmp-viewmodel-koin-compose", version.ref = "kmp-viewmodel" }
solivagant-navigation = { module = "io.github.hoc081098:solivagant-navigation", version.ref = "solivagant" }
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }

[plugins]
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
109 changes: 109 additions & 0 deletions sample/standalone-composeMultiplatform/composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.jetbrains.compose)
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.parcelize)
}

kotlin {
jvmToolchain {
languageVersion = JavaLanguageVersion.of(17)
vendor = JvmVendorSpec.AZUL
}

androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = "11"
}
}
}

jvm("desktop") {
compilations.all {
kotlinOptions {
jvmTarget = "11"
}
}
}

sourceSets {
val desktopMain by getting

androidMain.dependencies {
api(libs.androidx.compose.ui.tooling.preview)
api(libs.androidx.activity.compose)

// Koin
api(libs.koin.android)
api(libs.koin.androidx.compose)
}
commonMain.dependencies {
// Channel event bus
implementation(project(":channel-event-bus"))

implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
implementation(compose.ui)
implementation(compose.components.resources)

// KMP View Model & Solivagant navigation
api(libs.kmp.viewmodel)
api(libs.kmp.viewmodel.savedstate)
api(libs.kmp.viewmodel.compose)
api(libs.kmp.viewmodel.koin.compose)
api(libs.solivagant.navigation)

// Koin
api(libs.koin.core)
api(libs.koin.compose)

// Coroutines & FlowExt
api(libs.coroutines.core)
api(libs.flowExt)

// Immutable collections
api(libs.kotlinx.collections.immutable)

// Napier logger
api(libs.napier)
}
desktopMain.dependencies {
implementation(compose.desktop.currentOs)
}
}
}

android {
namespace = "com.hoc081098.channeleventbus.sample.kmp.compose"
compileSdk = libs.versions.sample.android.compile.get().toInt()

sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
sourceSets["main"].res.srcDirs("src/androidMain/res")
sourceSets["main"].resources.srcDirs("src/commonMain/resources")

defaultConfig {
minSdk = libs.versions.android.min.get().toInt()
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
buildFeatures {
buildConfig = true
}
dependencies {
debugImplementation(libs.androidx.compose.ui.tooling)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package com.hoc081098.channeleventbus.sample.kmp.compose

import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import com.hoc081098.channeleventbus.sample.kmp.compose.common.MyApplicationTheme
import com.hoc081098.channeleventbus.sample.kmp.compose.ui.home.detail.DetailScreenDestination
import com.hoc081098.channeleventbus.sample.kmp.compose.ui.home.home.HomeScreenRouteDestination
import com.hoc081098.channeleventbus.sample.kmp.compose.ui.register.stepone.RegisterStepOneScreenDestination
import com.hoc081098.channeleventbus.sample.kmp.compose.ui.register.stepone.RegisterStepOneScreenRoute
import com.hoc081098.channeleventbus.sample.kmp.compose.ui.register.stepthree.RegisterStepThreeScreenDestination
import com.hoc081098.channeleventbus.sample.kmp.compose.ui.register.steptwo.RegisterStepTwoScreenDestination
import com.hoc081098.solivagant.navigation.BaseRoute
import com.hoc081098.solivagant.navigation.NavDestination
import com.hoc081098.solivagant.navigation.NavEventNavigator
import com.hoc081098.solivagant.navigation.NavHost
import com.hoc081098.solivagant.navigation.NavHostDefaults
import com.hoc081098.solivagant.navigation.NavRoot
import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.adapters.ImmutableSetAdapter
import org.koin.compose.KoinContext
import org.koin.compose.koinInject

@Stable
private val AllDestinations: ImmutableSet<NavDestination> by lazy {
ImmutableSetAdapter(
hashSetOf(
RegisterStepOneScreenDestination,
RegisterStepTwoScreenDestination,
RegisterStepThreeScreenDestination,
HomeScreenRouteDestination,
DetailScreenDestination,
),
)
}

@OptIn(ExperimentalMaterial3Api::class)
@Suppress("LongMethod")
@Composable
fun ChannelEventBusSampleApp(
modifier: Modifier = Modifier,
navigator: NavEventNavigator = koinInject(),
) {
var currentRoute by rememberSaveable { mutableStateOf<BaseRoute?>(null) }

KoinContext {
MyApplicationTheme(darkTheme = false) {
Surface(
modifier = modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background,
) {
Scaffold(
modifier = Modifier.fillMaxSize(),
topBar = {
CenterAlignedTopAppBar(
title = { Text(text = currentRoute.toString()) },
navigationIcon = {
if (currentRoute !is NavRoot) {
IconButton(onClick = remember { navigator::navigateBack }) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
)
}
}
},
)
},
) { innerPadding ->
NavHost(
modifier = Modifier.fillMaxSize()
.padding(innerPadding)
.consumeWindowInsets(innerPadding),
startRoute = RegisterStepOneScreenRoute,
destinations = AllDestinations,
navEventNavigator = navigator,
destinationChangedCallback = { currentRoute = it },
transitionAnimations = NavHostDefaults.transitionAnimations(
enterTransition = {
slideIntoContainer(
towards = AnimatedContentTransitionScope.SlideDirection.Left,
)
},
exitTransition = {
slideOutOfContainer(
towards = AnimatedContentTransitionScope.SlideDirection.Left,
)
},
popEnterTransition = {
slideIntoContainer(
towards = AnimatedContentTransitionScope.SlideDirection.Right,
)
},
popExitTransition = {
slideOutOfContainer(
towards = AnimatedContentTransitionScope.SlideDirection.Right,
)
},
replaceEnterTransition = { fadeIn() },
replaceExitTransition = { fadeOut() },
),
)
}
}
}
}
}
Loading
Loading