From 0c175a867830f52e6f4a7c32d98340263e2afb8c Mon Sep 17 00:00:00 2001 From: Mugurell Date: Fri, 21 Jul 2023 19:25:01 +0300 Subject: [PATCH 1/6] Fix #302 - Update ktor and minimum deployment target of the iOS app This will ensure the iOS app can be built. --- gradle/libs.versions.toml | 2 +- ios/KaMPKitiOS.xcodeproj/project.pbxproj | 8 ++++---- ios/Podfile.lock | 4 ++-- ios/Pods/Local Podspecs/shared.podspec.json | 2 +- ios/Pods/Manifest.lock | 4 ++-- ios/Pods/Pods.xcodeproj/project.pbxproj | 8 ++++---- .../Pods-KaMPKitiOS/Pods-KaMPKitiOS-Info.plist | 2 +- .../Pods-KaMPKitiOS/Pods-KaMPKitiOS-frameworks.sh | 2 +- .../SwiftLint/SwiftLint.debug.xcconfig | 1 + .../SwiftLint/SwiftLint.release.xcconfig | 1 + .../Target Support Files/shared/shared.debug.xcconfig | 1 + .../Target Support Files/shared/shared.release.xcconfig | 1 + shared/build.gradle.kts | 2 +- shared/shared.podspec | 2 +- 14 files changed, 22 insertions(+), 18 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index affd5f00..3334e51a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,7 +24,7 @@ junit = "4.13.2" coroutines = "1.7.0" kotlinx-datetime = "0.4.0" -ktor = "2.3.1" +ktor = "2.3.2" robolectric = "4.10.3" diff --git a/ios/KaMPKitiOS.xcodeproj/project.pbxproj b/ios/KaMPKitiOS.xcodeproj/project.pbxproj index 765a0360..957a685d 100644 --- a/ios/KaMPKitiOS.xcodeproj/project.pbxproj +++ b/ios/KaMPKitiOS.xcodeproj/project.pbxproj @@ -464,7 +464,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -522,7 +522,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -596,7 +596,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = KaMPKitiOSTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -617,7 +617,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = KaMPKitiOSTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0d481a6a..9863cf83 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -15,9 +15,9 @@ EXTERNAL SOURCES: :path: "../shared/" SPEC CHECKSUMS: - shared: 153082a09d0db819a966647739a6809fed9eff56 + shared: 2f802391954274f6b79e59e6941e2cc7b18b56b1 SwiftLint: c585ebd615d9520d7fbdbe151f527977b0534f1e PODFILE CHECKSUM: d5a73f50a47bad1893e4fbf8978f1bef946ebdf6 -COCOAPODS: 1.11.3 +COCOAPODS: 1.12.1 diff --git a/ios/Pods/Local Podspecs/shared.podspec.json b/ios/Pods/Local Podspecs/shared.podspec.json index 9f2f93a2..3cb2c35d 100644 --- a/ios/Pods/Local Podspecs/shared.podspec.json +++ b/ios/Pods/Local Podspecs/shared.podspec.json @@ -11,7 +11,7 @@ "vendored_frameworks": "build/cocoapods/framework/shared.framework", "libraries": "c++", "platforms": { - "ios": "12.4" + "ios": "14.0" }, "pod_target_xcconfig": { "KOTLIN_PROJECT_PATH": ":shared", diff --git a/ios/Pods/Manifest.lock b/ios/Pods/Manifest.lock index 0d481a6a..9863cf83 100644 --- a/ios/Pods/Manifest.lock +++ b/ios/Pods/Manifest.lock @@ -15,9 +15,9 @@ EXTERNAL SOURCES: :path: "../shared/" SPEC CHECKSUMS: - shared: 153082a09d0db819a966647739a6809fed9eff56 + shared: 2f802391954274f6b79e59e6941e2cc7b18b56b1 SwiftLint: c585ebd615d9520d7fbdbe151f527977b0534f1e PODFILE CHECKSUM: d5a73f50a47bad1893e4fbf8978f1bef946ebdf6 -COCOAPODS: 1.11.3 +COCOAPODS: 1.12.1 diff --git a/ios/Pods/Pods.xcodeproj/project.pbxproj b/ios/Pods/Pods.xcodeproj/project.pbxproj index 96c12b0b..bb9e0a26 100644 --- a/ios/Pods/Pods.xcodeproj/project.pbxproj +++ b/ios/Pods/Pods.xcodeproj/project.pbxproj @@ -257,8 +257,8 @@ 46EB2E00000000 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1240; - LastUpgradeCheck = 1240; + LastSwiftUpdateCheck = 1300; + LastUpgradeCheck = 1300; }; buildConfigurationList = 46EB2E00000030 /* Build configuration list for PBXProject "Pods" */; compatibilityVersion = "Xcode 10.0"; @@ -498,7 +498,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ENABLE_OBJC_WEAK = NO; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -516,7 +516,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ENABLE_OBJC_WEAK = NO; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/ios/Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS-Info.plist b/ios/Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS-Info.plist index 2243fe6e..19cf209d 100644 --- a/ios/Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS-Info.plist +++ b/ios/Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS-Info.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - en + ${PODS_DEVELOPMENT_LANGUAGE} CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier diff --git a/ios/Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS-frameworks.sh b/ios/Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS-frameworks.sh index 333d767c..1e57ae2b 100755 --- a/ios/Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS-frameworks.sh +++ b/ios/Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS-frameworks.sh @@ -41,7 +41,7 @@ install_framework() if [ -L "${source}" ]; then echo "Symlinked..." - source="$(readlink "${source}")" + source="$(readlink -f "${source}")" fi if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then diff --git a/ios/Pods/Target Support Files/SwiftLint/SwiftLint.debug.xcconfig b/ios/Pods/Target Support Files/SwiftLint/SwiftLint.debug.xcconfig index 003a1f43..5238df58 100644 --- a/ios/Pods/Target Support Files/SwiftLint/SwiftLint.debug.xcconfig +++ b/ios/Pods/Target Support Files/SwiftLint/SwiftLint.debug.xcconfig @@ -3,6 +3,7 @@ CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SwiftLint GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} PODS_ROOT = ${SRCROOT} PODS_TARGET_SRCROOT = ${PODS_ROOT}/SwiftLint PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates diff --git a/ios/Pods/Target Support Files/SwiftLint/SwiftLint.release.xcconfig b/ios/Pods/Target Support Files/SwiftLint/SwiftLint.release.xcconfig index 003a1f43..5238df58 100644 --- a/ios/Pods/Target Support Files/SwiftLint/SwiftLint.release.xcconfig +++ b/ios/Pods/Target Support Files/SwiftLint/SwiftLint.release.xcconfig @@ -3,6 +3,7 @@ CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SwiftLint GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} PODS_ROOT = ${SRCROOT} PODS_TARGET_SRCROOT = ${PODS_ROOT}/SwiftLint PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates diff --git a/ios/Pods/Target Support Files/shared/shared.debug.xcconfig b/ios/Pods/Target Support Files/shared/shared.debug.xcconfig index 49484481..ee6cdedd 100644 --- a/ios/Pods/Target Support Files/shared/shared.debug.xcconfig +++ b/ios/Pods/Target Support Files/shared/shared.debug.xcconfig @@ -6,6 +6,7 @@ KOTLIN_PROJECT_PATH = :shared OTHER_LDFLAGS = $(inherited) -l"c++" PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} PODS_ROOT = ${SRCROOT} PODS_TARGET_SRCROOT = ${PODS_ROOT}/../../shared PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates diff --git a/ios/Pods/Target Support Files/shared/shared.release.xcconfig b/ios/Pods/Target Support Files/shared/shared.release.xcconfig index 49484481..ee6cdedd 100644 --- a/ios/Pods/Target Support Files/shared/shared.release.xcconfig +++ b/ios/Pods/Target Support Files/shared/shared.release.xcconfig @@ -6,6 +6,7 @@ KOTLIN_PROJECT_PATH = :shared OTHER_LDFLAGS = $(inherited) -l"c++" PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} PODS_ROOT = ${SRCROOT} PODS_TARGET_SRCROOT = ${PODS_ROOT}/../../shared PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 75b64d60..099f4132 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -101,7 +101,7 @@ kotlin { linkerOpts("-lsqlite3") export(libs.touchlab.kermit.simple) } - ios.deploymentTarget = "12.4" + ios.deploymentTarget = "14.0" podfile = project.file("../ios/Podfile") } } diff --git a/shared/shared.podspec b/shared/shared.podspec index 7c41fceb..853464bb 100644 --- a/shared/shared.podspec +++ b/shared/shared.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |spec| spec.summary = 'Common library for the KaMP starter kit' spec.vendored_frameworks = 'build/cocoapods/framework/shared.framework' spec.libraries = 'c++' - spec.ios.deployment_target = '12.4' + spec.ios.deployment_target = '14.0' spec.pod_target_xcconfig = { From 0ee5d1749051616902a21835775998044abbfd65 Mon Sep 17 00:00:00 2001 From: Mugurell Date: Tue, 18 Jul 2023 22:12:54 +0300 Subject: [PATCH 2/6] For #305 - Add support for Compose Multiplatform support https://blog.jetbrains.com/kotlin/2023/05/compose-multiplatform-for-ios-is-in-alpha/ --- app/build.gradle.kts | 8 ++++++++ build.gradle.kts | 1 + gradle.properties | 4 ++++ gradle/libs.versions.toml | 5 +++-- shared/build.gradle.kts | 10 ++++++++++ 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ef663cea..27cf45c3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("com.android.application") + id("org.jetbrains.compose") kotlin("android") } @@ -39,6 +40,13 @@ android { } } +// Using Compose gradle plugin v 1.4.1 which supports at most Kotlin 1.8.1 +// And SQLDelight 2.0+ which supports at least Kotlin 1.8.2 +// Quick workaround until we get some easier to match versions. +compose { + kotlinCompilerPlugin.set("org.jetbrains.compose.compiler:compiler:1.4.8") +} + dependencies { implementation(project(":shared")) implementation(libs.bundles.app.ui) diff --git a/build.gradle.kts b/build.gradle.kts index 47e20f28..673ba272 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,6 +9,7 @@ plugins { kotlin("plugin.serialization") version libs.versions.kotlin.get() apply false id("app.cash.sqldelight") version libs.versions.sqlDelight.get() apply false id("com.android.library") version libs.versions.android.gradle.plugin.get() apply false + id("org.jetbrains.compose") version libs.versions.compose.gradle.plugin.get() apply(false) } allprojects { diff --git a/gradle.properties b/gradle.properties index cb13eb29..ac3a2858 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,3 +17,7 @@ kotlin.code.style=official xcodeproj=./ios # New Android source-set layout kotlin.mpp.androidSourceSetLayoutVersion=2 + +# Compose Multiplatform +org.jetbrains.compose.experimental.uikit.enabled=true +kotlin.native.cacheKind=none diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3334e51a..d50d86d6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -kotlin = "1.8.21" +kotlin = "1.8.22" ## SDK Versions minSdk = "21" @@ -8,11 +8,12 @@ compileSdk = "33" # Dependencies android-gradle-plugin = "7.4.2" +compose-gradle-plugin = "1.4.1" ktlint-gradle = "11.4.2" gradle-versions = "0.47.0" compose = "1.4.3" -composeCompiler = "1.4.7" +composeCompiler = "1.4.8" android-desugaring = "2.0.3" androidx-core = "1.10.1" diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 099f4132..9aff8490 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -5,6 +5,7 @@ plugins { kotlin("native.cocoapods") kotlin("plugin.serialization") id("com.android.library") + id("org.jetbrains.compose") id("app.cash.sqldelight") } @@ -46,6 +47,7 @@ kotlin { val commonMain by getting { dependencies { + implementation(compose.runtime) implementation(libs.koin.core) implementation(libs.coroutines.core) implementation(libs.sqlDelight.coroutinesExt) @@ -62,6 +64,7 @@ kotlin { } val androidMain by getting { dependencies { + implementation(libs.compose.activity) implementation(libs.androidx.lifecycle.viewmodel) implementation(libs.sqlDelight.android) implementation(libs.ktor.client.okHttp) @@ -106,6 +109,13 @@ kotlin { } } +// Using Compose gradle plugin v 1.4.1 which supports at most Kotlin 1.8.1 +// And SQLDelight 2.0+ which supports at least Kotlin 1.8.2 +// Quick workaround until we get some easier to match versions. +compose { + kotlinCompilerPlugin.set("org.jetbrains.compose.compiler:compiler:1.4.8") +} + sqldelight { databases.create("KaMPKitDb") { packageName.set("co.touchlab.kampkit.db") From 87166b0852e5fe437012c875838253d845a3328b Mon Sep 17 00:00:00 2001 From: Mugurell Date: Tue, 18 Jul 2023 22:42:08 +0300 Subject: [PATCH 3/6] For #305 - Upstream the Compose theme to the shared module. This will allow to share it with iOS also. Migrated to Material3 and Dynamic Color support for Android in the meantime. Migrated to support automatic day/night theme support for both platforms. --- .../touchlab/kampkit/android/MainActivity.kt | 5 +- .../kampkit/android/ui/theme/Theme.kt | 47 ----------------- shared/build.gradle.kts | 2 + .../touchlab/kampkit/ui/theme/KaMPKitTheme.kt | 52 +++++++++++++++++++ .../co/touchlab/kampkit}/ui/theme/Color.kt | 2 +- .../touchlab/kampkit/ui/theme/KaMPKitTheme.kt | 10 ++++ .../co/touchlab/kampkit}/ui/theme/Shapes.kt | 4 +- .../co/touchlab/kampkit/ui/theme/Theme.kt | 25 +++++++++ .../touchlab/kampkit}/ui/theme/Typography.kt | 6 +-- .../touchlab/kampkit/ui.theme/KaMPKitTheme.kt | 18 +++++++ 10 files changed, 116 insertions(+), 55 deletions(-) delete mode 100644 app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Theme.kt create mode 100644 shared/src/androidMain/kotlin/co/touchlab/kampkit/ui/theme/KaMPKitTheme.kt rename {app/src/main/kotlin/co/touchlab/kampkit/android => shared/src/commonMain/kotlin/co/touchlab/kampkit}/ui/theme/Color.kt (79%) create mode 100644 shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/KaMPKitTheme.kt rename {app/src/main/kotlin/co/touchlab/kampkit/android => shared/src/commonMain/kotlin/co/touchlab/kampkit}/ui/theme/Shapes.kt (73%) create mode 100644 shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/Theme.kt rename {app/src/main/kotlin/co/touchlab/kampkit/android => shared/src/commonMain/kotlin/co/touchlab/kampkit}/ui/theme/Typography.kt (86%) create mode 100644 shared/src/iosMain/kotlin/co/touchlab/kampkit/ui.theme/KaMPKitTheme.kt diff --git a/app/src/main/kotlin/co/touchlab/kampkit/android/MainActivity.kt b/app/src/main/kotlin/co/touchlab/kampkit/android/MainActivity.kt index 08ae0954..b9f8402d 100644 --- a/app/src/main/kotlin/co/touchlab/kampkit/android/MainActivity.kt +++ b/app/src/main/kotlin/co/touchlab/kampkit/android/MainActivity.kt @@ -3,8 +3,9 @@ package co.touchlab.kampkit.android import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.compose.foundation.isSystemInDarkTheme import co.touchlab.kampkit.android.ui.MainScreen -import co.touchlab.kampkit.android.ui.theme.KaMPKitTheme +import co.touchlab.kampkit.ui.theme.KaMPKitTheme import co.touchlab.kampkit.injectLogger import co.touchlab.kampkit.models.BreedViewModel import co.touchlab.kermit.Logger @@ -19,7 +20,7 @@ class MainActivity : ComponentActivity(), KoinComponent { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { - KaMPKitTheme { + KaMPKitTheme(isSystemInDarkTheme(), true) { MainScreen(viewModel, log) } } diff --git a/app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Theme.kt b/app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Theme.kt deleted file mode 100644 index d17201c4..00000000 --- a/app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Theme.kt +++ /dev/null @@ -1,47 +0,0 @@ -package co.touchlab.kampkit.android.ui.theme - -import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.material.MaterialTheme -import androidx.compose.material.darkColors -import androidx.compose.material.lightColors -import androidx.compose.runtime.Composable - -private val DarkColorPalette = darkColors( - primary = Purple200, - primaryVariant = Purple700, - secondary = Teal200 -) - -private val LightColorPalette = lightColors( - primary = Purple500, - primaryVariant = Purple700, - secondary = Teal200 - - // Other default colors to override - // - // background = Color.White, - // surface = Color.White, - // onPrimary = Color.White, - // onSecondary = Color.Black, - // onBackground = Color.Black, - // onSurface = Color.Black, -) - -@Composable -fun KaMPKitTheme( - darkTheme: Boolean = isSystemInDarkTheme(), - content: @Composable () -> Unit -) { - val colors = if (darkTheme) { - DarkColorPalette - } else { - LightColorPalette - } - - MaterialTheme( - colors = colors, - typography = Typography, - shapes = Shapes, - content = content - ) -} diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 9aff8490..d6ee7bf7 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -48,6 +48,8 @@ kotlin { val commonMain by getting { dependencies { implementation(compose.runtime) + implementation(compose.foundation) + implementation(compose.material3) implementation(libs.koin.core) implementation(libs.coroutines.core) implementation(libs.sqlDelight.coroutinesExt) diff --git a/shared/src/androidMain/kotlin/co/touchlab/kampkit/ui/theme/KaMPKitTheme.kt b/shared/src/androidMain/kotlin/co/touchlab/kampkit/ui/theme/KaMPKitTheme.kt new file mode 100644 index 00000000..9fab32ae --- /dev/null +++ b/shared/src/androidMain/kotlin/co/touchlab/kampkit/ui/theme/KaMPKitTheme.kt @@ -0,0 +1,52 @@ +package co.touchlab.kampkit.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +@Composable +actual fun KaMPKitTheme( + darkTheme: Boolean, + dynamicColor: Boolean, + content: @Composable () -> Unit +) { + val colorScheme = when { + // Dynamic color is only supported on Android 12+ + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + darkTheme -> DarkColorPalette + else -> LightColorPalette + } + + // If not in Android Studio's preview then update also the system bars + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + (view.context as Activity).window.apply { + statusBarColor = colorScheme.primary.toArgb() + WindowCompat + .getInsetsController(this, view).apply { + isAppearanceLightStatusBars = darkTheme + isAppearanceLightNavigationBars = darkTheme + } + } + } + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + shapes = Shapes, + content = content + ) +} diff --git a/app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Color.kt b/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/Color.kt similarity index 79% rename from app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Color.kt rename to shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/Color.kt index 287f01c9..11f754dd 100644 --- a/app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Color.kt +++ b/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/Color.kt @@ -1,4 +1,4 @@ -package co.touchlab.kampkit.android.ui.theme +package co.touchlab.kampkit.ui.theme import androidx.compose.ui.graphics.Color diff --git a/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/KaMPKitTheme.kt b/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/KaMPKitTheme.kt new file mode 100644 index 00000000..d5b06f60 --- /dev/null +++ b/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/KaMPKitTheme.kt @@ -0,0 +1,10 @@ +package co.touchlab.kampkit.ui.theme + +import androidx.compose.runtime.Composable + +@Composable +expect fun KaMPKitTheme( + darkTheme: Boolean, + dynamicColor: Boolean, + content: @Composable () -> Unit +) diff --git a/app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Shapes.kt b/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/Shapes.kt similarity index 73% rename from app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Shapes.kt rename to shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/Shapes.kt index 0260e337..f464b2b5 100644 --- a/app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Shapes.kt +++ b/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/Shapes.kt @@ -1,7 +1,7 @@ -package co.touchlab.kampkit.android.ui.theme +package co.touchlab.kampkit.ui.theme import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Shapes +import androidx.compose.material3.Shapes import androidx.compose.ui.unit.dp val Shapes = Shapes( diff --git a/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/Theme.kt b/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/Theme.kt new file mode 100644 index 00000000..9f76f7a4 --- /dev/null +++ b/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/Theme.kt @@ -0,0 +1,25 @@ +package co.touchlab.kampkit.ui.theme + +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme + +val DarkColorPalette = darkColorScheme( + primary = Purple200, + inversePrimary = Purple700, + secondary = Teal200 +) + +val LightColorPalette = lightColorScheme( + primary = Purple500, + inversePrimary = Purple700, + secondary = Teal200 + + // Other default colors to override + // + // background = Color.White, + // surface = Color.White, + // onPrimary = Color.White, + // onSecondary = Color.Black, + // onBackground = Color.Black, + // onSurface = Color.Black, +) diff --git a/app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Typography.kt b/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/Typography.kt similarity index 86% rename from app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Typography.kt rename to shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/Typography.kt index 2c6faca5..92c7665f 100644 --- a/app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Typography.kt +++ b/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/theme/Typography.kt @@ -1,6 +1,6 @@ -package co.touchlab.kampkit.android.ui.theme +package co.touchlab.kampkit.ui.theme -import androidx.compose.material.Typography +import androidx.compose.material3.Typography import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight @@ -8,7 +8,7 @@ import androidx.compose.ui.unit.sp // Set of Material typography styles to start with val Typography = Typography( - body1 = TextStyle( + bodyLarge = TextStyle( fontFamily = FontFamily.Default, fontWeight = FontWeight.Normal, fontSize = 16.sp diff --git a/shared/src/iosMain/kotlin/co/touchlab/kampkit/ui.theme/KaMPKitTheme.kt b/shared/src/iosMain/kotlin/co/touchlab/kampkit/ui.theme/KaMPKitTheme.kt new file mode 100644 index 00000000..253d2ea2 --- /dev/null +++ b/shared/src/iosMain/kotlin/co/touchlab/kampkit/ui.theme/KaMPKitTheme.kt @@ -0,0 +1,18 @@ +package co.touchlab.kampkit.ui.theme + +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable + +@Composable +actual fun KaMPKitTheme( + darkTheme: Boolean, + dynamicColor: Boolean, + content: @Composable () -> Unit +) { + MaterialTheme( + colorScheme = if (darkTheme) DarkColorPalette else LightColorPalette, + typography = Typography, + shapes = Shapes, + content = content + ) +} From c0f692865a3e44007ab39ab602b1b5bd3ac9b4f1 Mon Sep 17 00:00:00 2001 From: Mugurell Date: Fri, 21 Jul 2023 11:19:01 +0300 Subject: [PATCH 4/6] For #305 - Use Compose Multiplatform to show the UI from :shared on Android Added moko-resources as the community preferred approach to using strings in similar scenarios. Added the materialIconsExtended dependency for :shared instead of reusing the vector images shown previously from :app since those vectors are not in a format moko-resources supports at this moment (though it support SVGs). While this is a big package R8 will ensure unused resources are stripped from the generated builds at compile time. --- .../touchlab/kampkit/android/MainActivity.kt | 2 +- .../main/res/drawable/ic_favorite_24px.xml | 9 ----- .../res/drawable/ic_favorite_border_24px.xml | 9 ----- build.gradle.kts | 3 ++ gradle/libs.versions.toml | 8 ++++ shared/build.gradle.kts | 16 ++++++++ .../co/touchlab/kampkit/utils/Strings.kt | 24 ++++++++++++ .../co/touchlab/kampkit}/ui/Composables.kt | 38 +++++++------------ .../co/touchlab/kampkit/utils/Strings.kt | 7 ++++ .../commonMain/resources/MR/base/strings.xml | 7 ++++ .../co/touchlab/kampkit/utils/Strings.kt | 13 +++++++ 11 files changed, 92 insertions(+), 44 deletions(-) delete mode 100644 app/src/main/res/drawable/ic_favorite_24px.xml delete mode 100644 app/src/main/res/drawable/ic_favorite_border_24px.xml create mode 100644 shared/src/androidMain/kotlin/co/touchlab/kampkit/utils/Strings.kt rename {app/src/main/kotlin/co/touchlab/kampkit/android => shared/src/commonMain/kotlin/co/touchlab/kampkit}/ui/Composables.kt (83%) create mode 100644 shared/src/commonMain/kotlin/co/touchlab/kampkit/utils/Strings.kt create mode 100644 shared/src/commonMain/resources/MR/base/strings.xml create mode 100644 shared/src/iosMain/kotlin/co/touchlab/kampkit/utils/Strings.kt diff --git a/app/src/main/kotlin/co/touchlab/kampkit/android/MainActivity.kt b/app/src/main/kotlin/co/touchlab/kampkit/android/MainActivity.kt index b9f8402d..91a9d0fd 100644 --- a/app/src/main/kotlin/co/touchlab/kampkit/android/MainActivity.kt +++ b/app/src/main/kotlin/co/touchlab/kampkit/android/MainActivity.kt @@ -4,7 +4,7 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.isSystemInDarkTheme -import co.touchlab.kampkit.android.ui.MainScreen +import co.touchlab.kampkit.ui.MainScreen import co.touchlab.kampkit.ui.theme.KaMPKitTheme import co.touchlab.kampkit.injectLogger import co.touchlab.kampkit.models.BreedViewModel diff --git a/app/src/main/res/drawable/ic_favorite_24px.xml b/app/src/main/res/drawable/ic_favorite_24px.xml deleted file mode 100644 index ce351f43..00000000 --- a/app/src/main/res/drawable/ic_favorite_24px.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_favorite_border_24px.xml b/app/src/main/res/drawable/ic_favorite_border_24px.xml deleted file mode 100644 index e6646709..00000000 --- a/app/src/main/res/drawable/ic_favorite_border_24px.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/build.gradle.kts b/build.gradle.kts index 673ba272..b71bca0a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,6 +4,7 @@ plugins { alias(libs.plugins.gradleVersions) alias(libs.plugins.ktlint) apply false + alias(libs.plugins.moko.resources) apply false kotlin("multiplatform") version libs.versions.kotlin.get() apply false kotlin("plugin.serialization") version libs.versions.kotlin.get() apply false @@ -18,6 +19,7 @@ allprojects { mavenCentral() maven("https://androidx.dev/storage/compose-compiler/repository/") maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev/") + gradlePluginPortal() // for moko } } @@ -25,6 +27,7 @@ subprojects { // TODO libs doesn't resolve if we do this // apply(plugin = libs.plugins.ktlint.get().pluginId) apply(plugin = "org.jlleitschuh.gradle.ktlint") + apply(plugin = "dev.icerock.mobile.multiplatform-resources") configure { enableExperimentalRules.set(true) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d50d86d6..695c9c94 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -36,6 +36,9 @@ multiplatformSettings = "1.0.0" turbine = "1.0.0" sqlDelight = "2.0.0-rc01" +moko-resources = "0.23.0" +moko-graphics = "0.9.0" + [libraries] android-desugaring = { module = "com.android.tools:desugar_jdk_libs", version.ref = "android-desugaring" } androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" } @@ -87,9 +90,14 @@ touchlab-kermit-simple = { module = "co.touchlab:kermit-simple", version.ref = " turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } +moko-resources = { module = "dev.icerock.moko:resources", version.ref = "moko-resources" } +moko-resources-compose = { module = "dev.icerock.moko:resources-compose", version.ref = "moko-resources" } +moko-graphics = { module = "dev.icerock.moko:graphics", version.ref = "moko-graphics" } + [plugins] ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-gradle" } gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradle-versions" } +moko-resources = { id = "dev.icerock.mobile.multiplatform-resources", version.ref = "moko-resources" } [bundles] app-ui = [ diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index d6ee7bf7..6447a7c1 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -49,7 +49,9 @@ kotlin { dependencies { implementation(compose.runtime) implementation(compose.foundation) + implementation(compose.material) // for PullRefreshIndicator implementation(compose.material3) + implementation(compose.materialIconsExtended) implementation(libs.koin.core) implementation(libs.coroutines.core) implementation(libs.sqlDelight.coroutinesExt) @@ -57,6 +59,8 @@ kotlin { implementation(libs.multiplatformSettings.common) implementation(libs.kotlinx.dateTime) api(libs.touchlab.kermit) + api(libs.moko.resources) + api(libs.moko.resources.compose) } } val commonTest by getting { @@ -65,6 +69,8 @@ kotlin { } } val androidMain by getting { + // Below line adds a temporary workaround for https://github.com/icerockdev/moko-resources/issues/531 + kotlin.srcDirs("build/generated/moko/androidMain/src") dependencies { implementation(libs.compose.activity) implementation(libs.androidx.lifecycle.viewmodel) @@ -78,6 +84,7 @@ kotlin { } } val iosMain by getting { + resources.srcDirs("build/generated/moko/iosMain/src") dependencies { implementation(libs.sqlDelight.native) implementation(libs.ktor.client.ios) @@ -86,6 +93,7 @@ kotlin { } val iosTest by getting val iosSimulatorArm64Main by getting { + resources.srcDirs("build/generated/moko/iosSimulatorArm64Main/src") dependsOn(iosMain) } val iosSimulatorArm64Test by getting { @@ -105,6 +113,8 @@ kotlin { isStatic = false // SwiftUI preview requires dynamic framework linkerOpts("-lsqlite3") export(libs.touchlab.kermit.simple) + export(libs.moko.resources) + export(libs.moko.graphics) } ios.deploymentTarget = "14.0" podfile = project.file("../ios/Podfile") @@ -123,3 +133,9 @@ sqldelight { packageName.set("co.touchlab.kampkit.db") } } + +multiplatformResources { + multiplatformResourcesPackage = "co.touchlab.kampkit" // required + // multiplatformResourcesSourceSet = "iosSimulatorArm64Main" + multiplatformResourcesClassName = "MR" // optional, default MR +} diff --git a/shared/src/androidMain/kotlin/co/touchlab/kampkit/utils/Strings.kt b/shared/src/androidMain/kotlin/co/touchlab/kampkit/utils/Strings.kt new file mode 100644 index 00000000..8d69d97d --- /dev/null +++ b/shared/src/androidMain/kotlin/co/touchlab/kampkit/utils/Strings.kt @@ -0,0 +1,24 @@ +package co.touchlab.kampkit.utils + +import android.content.Context +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import dev.icerock.moko.resources.StringResource +import dev.icerock.moko.resources.desc.Resource +import dev.icerock.moko.resources.desc.StringDesc +import dev.icerock.moko.resources.format + +actual class Strings(private val context: Context) { + actual fun get(id: StringResource, args: List): String { + return when (args.isEmpty()) { + true -> StringDesc.Resource(id).toString(context) + false -> id.format(*args.toTypedArray()).toString(context) + } + } +} + +/** + * Get a string existing in the shared module. + */ +@Composable +fun getString(id: StringResource, vararg args: Any) = Strings(LocalContext.current).get(id, args.toList()) diff --git a/app/src/main/kotlin/co/touchlab/kampkit/android/ui/Composables.kt b/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/Composables.kt similarity index 83% rename from app/src/main/kotlin/co/touchlab/kampkit/android/ui/Composables.kt rename to shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/Composables.kt index 002c2624..7f03c87b 100644 --- a/app/src/main/kotlin/co/touchlab/kampkit/android/ui/Composables.kt +++ b/shared/src/commonMain/kotlin/co/touchlab/kampkit/ui/Composables.kt @@ -1,4 +1,4 @@ -package co.touchlab.kampkit.android.ui +package co.touchlab.kampkit.ui import androidx.compose.animation.Crossfade import androidx.compose.animation.core.FastOutSlowInEasing @@ -20,25 +20,26 @@ import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Favorite +import androidx.compose.material.icons.filled.FavoriteBorder import androidx.compose.material.pullrefresh.PullRefreshIndicator import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import co.touchlab.kampkit.android.R +import co.touchlab.kampkit.MR import co.touchlab.kampkit.db.Breed import co.touchlab.kampkit.models.BreedViewModel import co.touchlab.kampkit.models.BreedViewState import co.touchlab.kermit.Logger +import dev.icerock.moko.resources.compose.stringResource import kotlinx.coroutines.launch @Composable @@ -46,7 +47,7 @@ fun MainScreen( viewModel: BreedViewModel, log: Logger ) { - val dogsState by viewModel.breedState.collectAsStateWithLifecycle() + val dogsState by viewModel.breedState.collectAsState() val scope = rememberCoroutineScope() MainScreenContent( @@ -106,7 +107,7 @@ fun Empty() { verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { - Text(stringResource(R.string.empty_breeds)) + Text(text = stringResource(MR.strings.empty_breeds)) } } @@ -166,27 +167,14 @@ fun FavoriteIcon(breed: Breed) { ) { fav -> if (fav) { Image( - painter = painterResource(id = R.drawable.ic_favorite_border_24px), - contentDescription = stringResource(R.string.favorite_breed, breed.name) + imageVector = Icons.Default.FavoriteBorder, + contentDescription = stringResource(MR.strings.favorite_breed, breed.name) ) } else { Image( - painter = painterResource(id = R.drawable.ic_favorite_24px), - contentDescription = stringResource(R.string.unfavorite_breed, breed.name) + imageVector = Icons.Default.Favorite, + contentDescription = stringResource(MR.strings.unfavorite_breed, breed.name) ) } } } - -@Preview -@Composable -fun MainScreenContentPreview_Success() { - MainScreenContent( - dogsState = BreedViewState( - breeds = listOf( - Breed(0, "appenzeller", false), - Breed(1, "australian", true) - ) - ) - ) -} diff --git a/shared/src/commonMain/kotlin/co/touchlab/kampkit/utils/Strings.kt b/shared/src/commonMain/kotlin/co/touchlab/kampkit/utils/Strings.kt new file mode 100644 index 00000000..ed868d2f --- /dev/null +++ b/shared/src/commonMain/kotlin/co/touchlab/kampkit/utils/Strings.kt @@ -0,0 +1,7 @@ +package co.touchlab.kampkit.utils + +import dev.icerock.moko.resources.StringResource + +expect class Strings { + fun get(id: StringResource, args: List): String +} diff --git a/shared/src/commonMain/resources/MR/base/strings.xml b/shared/src/commonMain/resources/MR/base/strings.xml new file mode 100644 index 00000000..5ac1e5a9 --- /dev/null +++ b/shared/src/commonMain/resources/MR/base/strings.xml @@ -0,0 +1,7 @@ + + + KaMP Kit + Favorite %1$s + Unfavorite %1$s + Sorry, no doggos found + diff --git a/shared/src/iosMain/kotlin/co/touchlab/kampkit/utils/Strings.kt b/shared/src/iosMain/kotlin/co/touchlab/kampkit/utils/Strings.kt new file mode 100644 index 00000000..1502f5cd --- /dev/null +++ b/shared/src/iosMain/kotlin/co/touchlab/kampkit/utils/Strings.kt @@ -0,0 +1,13 @@ +package co.touchlab.kampkit.utils + +import dev.icerock.moko.resources.StringResource +import dev.icerock.moko.resources.desc.Resource +import dev.icerock.moko.resources.desc.StringDesc +import dev.icerock.moko.resources.format + +actual class Strings { + actual fun get(id: StringResource, args: List) = when (args.isEmpty()) { + true -> StringDesc.Resource(id).localized() + false -> id.format(*args.toTypedArray()).localized() + } +} From dec16b1f21e86db2d0277103c2bd77c16746c2e8 Mon Sep 17 00:00:00 2001 From: Mugurell Date: Fri, 21 Jul 2023 17:09:40 +0300 Subject: [PATCH 5/6] For #305 - Use Compose Multiplatform to show the UI from :shared on iOS --- gradle/libs.versions.toml | 2 +- ios/KaMPKitiOS.xcodeproj/project.pbxproj | 36 +++++++------------ ios/KaMPKitiOS/AppDelegate.swift | 34 ------------------ ios/KaMPKitiOS/ComposeContentView.swift | 24 +++++++++++++ ios/KaMPKitiOS/ContentView.swift | 16 +++++++++ ios/KaMPKitiOS/IOSApp.swift | 23 ++++++++++++ ios/KaMPKitiOS/Info.plist | 6 ++-- ios/Pods/Pods.xcodeproj/project.pbxproj | 12 +++---- shared/build.gradle.kts | 3 +- .../kotlin/co/touchlab/kampkit/Koin.kt | 14 ++++++++ .../touchlab/kampkit/ui/MainViewController.kt | 20 +++++++++++ 11 files changed, 121 insertions(+), 69 deletions(-) delete mode 100644 ios/KaMPKitiOS/AppDelegate.swift create mode 100644 ios/KaMPKitiOS/ComposeContentView.swift create mode 100644 ios/KaMPKitiOS/ContentView.swift create mode 100644 ios/KaMPKitiOS/IOSApp.swift create mode 100644 shared/src/iosMain/kotlin/co/touchlab/kampkit/ui/MainViewController.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 695c9c94..ba5dac19 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ androidx-lifecycle = "2.6.1" junit = "4.13.2" -coroutines = "1.7.0" +coroutines = "1.7.2" kotlinx-datetime = "0.4.0" ktor = "2.3.2" diff --git a/ios/KaMPKitiOS.xcodeproj/project.pbxproj b/ios/KaMPKitiOS.xcodeproj/project.pbxproj index 957a685d..84b08187 100644 --- a/ios/KaMPKitiOS.xcodeproj/project.pbxproj +++ b/ios/KaMPKitiOS.xcodeproj/project.pbxproj @@ -7,12 +7,11 @@ objects = { /* Begin PBXBuildFile section */ + 0AE285002A6AD6B7000B6B60 /* ComposeContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE284FF2A6AD6B7000B6B60 /* ComposeContentView.swift */; }; + 0AE285022A6AD7BD000B6B60 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE285012A6AD7BD000B6B60 /* ContentView.swift */; }; + 0AE285042A6AD7D0000B6B60 /* IOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE285032A6AD7D0000B6B60 /* IOSApp.swift */; }; 3DFF917C64A18A83DA010EE1 /* Pods_KaMPKitiOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B859F3FB23133D22AB9DD835 /* Pods_KaMPKitiOS.framework */; }; - 461C74AA2788F5F3004B1FFC /* CombineAdapters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 461C74A92788F5F3004B1FFC /* CombineAdapters.swift */; }; - 46A5B5EF26AF54F7002EFEAA /* BreedListScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A5B5EE26AF54F7002EFEAA /* BreedListScreen.swift */; }; - 46A5B60826B04921002EFEAA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 46A5B60626B04920002EFEAA /* Main.storyboard */; }; 46B5284D249C5CF400A7725D /* Koin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46B5284C249C5CF400A7725D /* Koin.swift */; }; - F1465F0123AA94BF0055F7C3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1465F0023AA94BF0055F7C3 /* AppDelegate.swift */; }; F1465F0A23AA94BF0055F7C3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F1465F0923AA94BF0055F7C3 /* Assets.xcassets */; }; F1465F0D23AA94BF0055F7C3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F1465F0B23AA94BF0055F7C3 /* LaunchScreen.storyboard */; }; F1465F1823AA94C00055F7C3 /* KaMPKitiOSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1465F1723AA94C00055F7C3 /* KaMPKitiOSTests.swift */; }; @@ -37,16 +36,15 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 0AE284FF2A6AD6B7000B6B60 /* ComposeContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeContentView.swift; sourceTree = ""; }; + 0AE285012A6AD7BD000B6B60 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 0AE285032A6AD7D0000B6B60 /* IOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOSApp.swift; sourceTree = ""; }; 1DFCC00C8DAA719770A18D1A /* Pods-KaMPKitiOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KaMPKitiOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS.release.xcconfig"; sourceTree = ""; }; 2A1ED6A4A2A53F5F75C58E5F /* Pods-KaMPKitiOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KaMPKitiOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS.release.xcconfig"; sourceTree = ""; }; - 461C74A92788F5F3004B1FFC /* CombineAdapters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombineAdapters.swift; sourceTree = ""; }; - 46A5B5EE26AF54F7002EFEAA /* BreedListScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreedListScreen.swift; sourceTree = ""; }; - 46A5B60726B04920002EFEAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 46B5284C249C5CF400A7725D /* Koin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Koin.swift; sourceTree = ""; }; B859F3FB23133D22AB9DD835 /* Pods_KaMPKitiOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_KaMPKitiOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; ED1F782AF3705197012D0C33 /* Pods-KaMPKitiOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KaMPKitiOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS.debug.xcconfig"; sourceTree = ""; }; F1465EFD23AA94BF0055F7C3 /* KaMPKitiOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KaMPKitiOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; - F1465F0023AA94BF0055F7C3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; F1465F0923AA94BF0055F7C3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; F1465F0C23AA94BF0055F7C3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; F1465F0E23AA94BF0055F7C3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -129,14 +127,13 @@ F1465EFF23AA94BF0055F7C3 /* KaMPKitiOS */ = { isa = PBXGroup; children = ( - F1465F0023AA94BF0055F7C3 /* AppDelegate.swift */, - 46A5B60626B04920002EFEAA /* Main.storyboard */, 46B5284C249C5CF400A7725D /* Koin.swift */, F1465F0923AA94BF0055F7C3 /* Assets.xcassets */, F1465F0B23AA94BF0055F7C3 /* LaunchScreen.storyboard */, F1465F0E23AA94BF0055F7C3 /* Info.plist */, - 46A5B5EE26AF54F7002EFEAA /* BreedListScreen.swift */, - 461C74A92788F5F3004B1FFC /* CombineAdapters.swift */, + 0AE284FF2A6AD6B7000B6B60 /* ComposeContentView.swift */, + 0AE285012A6AD7BD000B6B60 /* ContentView.swift */, + 0AE285032A6AD7D0000B6B60 /* IOSApp.swift */, ); path = KaMPKitiOS; sourceTree = ""; @@ -266,7 +263,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 46A5B60826B04921002EFEAA /* Main.storyboard in Resources */, F1465F0D23AA94BF0055F7C3 /* LaunchScreen.storyboard in Resources */, F1465F0A23AA94BF0055F7C3 /* Assets.xcassets in Resources */, ); @@ -354,9 +350,9 @@ buildActionMask = 2147483647; files = ( 46B5284D249C5CF400A7725D /* Koin.swift in Sources */, - 461C74AA2788F5F3004B1FFC /* CombineAdapters.swift in Sources */, - 46A5B5EF26AF54F7002EFEAA /* BreedListScreen.swift in Sources */, - F1465F0123AA94BF0055F7C3 /* AppDelegate.swift in Sources */, + 0AE285002A6AD6B7000B6B60 /* ComposeContentView.swift in Sources */, + 0AE285022A6AD7BD000B6B60 /* ContentView.swift in Sources */, + 0AE285042A6AD7D0000B6B60 /* IOSApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -392,14 +388,6 @@ /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ - 46A5B60626B04920002EFEAA /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 46A5B60726B04920002EFEAA /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; F1465F0B23AA94BF0055F7C3 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( diff --git a/ios/KaMPKitiOS/AppDelegate.swift b/ios/KaMPKitiOS/AppDelegate.swift deleted file mode 100644 index 25924195..00000000 --- a/ios/KaMPKitiOS/AppDelegate.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// AppDelegate.swift -// KaMPKitiOS -// -// Created by Kevin Schildhorn on 12/18/19. -// Copyright © 2019 Touchlab. All rights reserved. -// - -import SwiftUI -import shared - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - - // Lazy so it doesn't try to initialize before startKoin() is called - lazy var log = koin.loggerWithTag(tag: "AppDelegate") - - func application(_ application: UIApplication, didFinishLaunchingWithOptions - launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - - startKoin() - - let viewController = UIHostingController(rootView: BreedListScreen()) - - self.window = UIWindow(frame: UIScreen.main.bounds) - self.window?.rootViewController = viewController - self.window?.makeKeyAndVisible() - - log.v(message: {"App Started"}) - return true - } -} diff --git a/ios/KaMPKitiOS/ComposeContentView.swift b/ios/KaMPKitiOS/ComposeContentView.swift new file mode 100644 index 00000000..733655b7 --- /dev/null +++ b/ios/KaMPKitiOS/ComposeContentView.swift @@ -0,0 +1,24 @@ +// +// ComposeContentView.swift +// KaMPKitiOS +// +// Created by Petru on 7/21/23. +// Copyright © 2023 Touchlab. All rights reserved. +// + +import Foundation +import shared +import SwiftUI + +struct ComposeContentView: UIViewControllerRepresentable { + func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { + // no-op + } + + func makeUIViewController(context: Context) -> some UIViewController { + MainViewControllerKt.MainViewController( + logger: koin.loggerWithTag(tag: "ViewController"), + viewModel: KotlinDependencies.shared.getBreedViewModel().viewModel + ) + } +} diff --git a/ios/KaMPKitiOS/ContentView.swift b/ios/KaMPKitiOS/ContentView.swift new file mode 100644 index 00000000..05074fbe --- /dev/null +++ b/ios/KaMPKitiOS/ContentView.swift @@ -0,0 +1,16 @@ +// +// ContentView.swift +// KaMPKitiOS +// +// Created by Petru on 7/21/23. +// Copyright © 2023 Touchlab. All rights reserved. +// + +import SwiftUI +import shared + +struct ContentView: View { + var body: some View { + ComposeContentView() + } +} diff --git a/ios/KaMPKitiOS/IOSApp.swift b/ios/KaMPKitiOS/IOSApp.swift new file mode 100644 index 00000000..8fd64b39 --- /dev/null +++ b/ios/KaMPKitiOS/IOSApp.swift @@ -0,0 +1,23 @@ +// +// iOSApp.swift +// KaMPKitiOS +// +// Created by Petru on 7/21/23. +// Copyright © 2023 Touchlab. All rights reserved. +// + +import SwiftUI + +@main +struct IOSApp: App { + + init() { + startKoin() + } + + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/ios/KaMPKitiOS/Info.plist b/ios/KaMPKitiOS/Info.plist index af8868b2..b79441c7 100644 --- a/ios/KaMPKitiOS/Info.plist +++ b/ios/KaMPKitiOS/Info.plist @@ -21,13 +21,13 @@ LSRequiresIPhoneOS UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main + LaunchScreen.storyboard UIRequiredDeviceCapabilities armv7 + UIStatusBarStyle + UISupportedInterfaceOrientations UIInterfaceOrientationPortrait diff --git a/ios/Pods/Pods.xcodeproj/project.pbxproj b/ios/Pods/Pods.xcodeproj/project.pbxproj index bb9e0a26..04900b6c 100644 --- a/ios/Pods/Pods.xcodeproj/project.pbxproj +++ b/ios/Pods/Pods.xcodeproj/project.pbxproj @@ -383,7 +383,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -446,7 +446,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -464,7 +464,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -481,7 +481,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -542,7 +542,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -580,7 +580,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 6447a7c1..cad6e133 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -110,7 +110,8 @@ kotlin { summary = "Common library for the KaMP starter kit" homepage = "https://github.com/touchlab/KaMPKit" framework { - isStatic = false // SwiftUI preview requires dynamic framework + // Below line is needed for Compose Multiplatform, see https://github.com/JetBrains/compose-multiplatform/issues/3178 + isStatic = true linkerOpts("-lsqlite3") export(libs.touchlab.kermit.simple) export(libs.moko.resources) diff --git a/shared/src/commonMain/kotlin/co/touchlab/kampkit/Koin.kt b/shared/src/commonMain/kotlin/co/touchlab/kampkit/Koin.kt index db7c2df1..0c002b27 100644 --- a/shared/src/commonMain/kotlin/co/touchlab/kampkit/Koin.kt +++ b/shared/src/commonMain/kotlin/co/touchlab/kampkit/Koin.kt @@ -83,4 +83,18 @@ internal inline fun Scope.getWith(vararg params: Any?): T { // Simple function to clean up the syntax a bit fun KoinComponent.injectLogger(tag: String): Lazy = inject { parametersOf(tag) } +/** + * Get any instance of `T` if available in the dependencies graph. + * + * @param tag Optional name of allowing to get a specific + */ +inline fun injectInstance(tag: String? = null): T { + return object : KoinComponent { + val value: T by when (tag) { + null -> inject() + else -> inject { parametersOf(tag) } + } + }.value +} + expect val platformModule: Module diff --git a/shared/src/iosMain/kotlin/co/touchlab/kampkit/ui/MainViewController.kt b/shared/src/iosMain/kotlin/co/touchlab/kampkit/ui/MainViewController.kt new file mode 100644 index 00000000..186145e9 --- /dev/null +++ b/shared/src/iosMain/kotlin/co/touchlab/kampkit/ui/MainViewController.kt @@ -0,0 +1,20 @@ +package co.touchlab.kampkit.ui + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.ui.window.ComposeUIViewController +import co.touchlab.kampkit.injectInstance +import co.touchlab.kampkit.models.BreedViewModel +import co.touchlab.kampkit.ui.theme.KaMPKitTheme +import co.touchlab.kermit.Logger +import platform.UIKit.UIApplication +import platform.UIKit.UIScreen +import platform.UIKit.UIUserInterfaceStyle + +fun MainViewController(logger: Logger, viewModel: BreedViewModel) = ComposeUIViewController { + val isDarkThemeEnabled = + UIScreen.mainScreen.traitCollection.userInterfaceStyle == UIUserInterfaceStyle.UIUserInterfaceStyleDark + + KaMPKitTheme(isDarkThemeEnabled, false) { + MainScreen(viewModel, logger) + } +} From 2eb30a8cc635c48d47d5bc61b90a8f6445430101 Mon Sep 17 00:00:00 2001 From: Mugurell Date: Fri, 21 Jul 2023 20:06:12 +0300 Subject: [PATCH 6/6] For #305 - Update README to include Compose Multiplatform --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8ac73825..13361f4c 100644 --- a/README.md +++ b/README.md @@ -121,15 +121,18 @@ As part of your evaluation, you'll need to decide if you're going to integrate K ### Android -The Android side is somewhat more straightforward. Kotlin is the preferred language for Android, and the library can be integrated as just another module library. We'll be updating soon with a general Android integration doc. In the meantime, the simplest method would be to copy the shared module into your standard Android build, and use the `app` module as a reference for dependency resolution. +The Android side is somewhat more straightforward. Kotlin is the preferred language for Android, and the library can be integrated as just another module library. +The main benefit of the :shared module is that it holds all the functionality needed to download, persist and display application's UI. +This is accomplished by it using +- Ktor - https://ktor.io/ as a Kotlin only library for handling downloads +- SQLDelight - https://cashapp.github.io/sqldelight/ as a Kotlin only library for persisting data +- Compose Multiplatform https://blog.jetbrains.com/kotlin/2023/05/compose-multiplatform-for-ios-is-in-alpha/ which is powered by Skia to allow displaying the same UI written in Jetpack Compose on multiple platforms. ### iOS -The iOS integration process is relatively new and has been iterating fast. Be prepared to spend more time with config related issues when integrating with a production build. +The iOS side is very similar to the Android one by leveraging the same technologies through :shared showcasing the major advantage of a Compose Multiplatform project - run once and run everywhere. -You can integrate with Cocoapods, or by directly including the Xcode framework. If you are an Android developer without extensive iOS build experience, be aware that this is a risky option. Production build systems, for any ecosystem, tend to be complex. You'll almost certainly need to recruit somebody with experience maintaining your iOS build. - -See [IOS_PROJ_INTEGRATION.md](docs/IOS_PROJ_INTEGRATION.md) for iOS integration information. +See [IOS_PROJ_INTEGRATION.md](docs/IOS_PROJ_INTEGRATION.md) for how iOS is consuming :shared through a Podfile. If you are attempting to integrate your KMP project with a production iOS application, please let us know what issues you run into and reach out with questions if stuck. This is an ongoing area of improvement for the KMP platform and we'd like to help make this as smooth as possible.