create-cmp-cli 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +232 -0
- package/bin/create-cmp.mjs +91 -0
- package/options.schema.json +110 -0
- package/package.json +52 -0
- package/src/bootstrap/checks.mjs +283 -0
- package/src/bootstrap/exec.mjs +90 -0
- package/src/commands/clean.mjs +195 -0
- package/src/commands/create.mjs +223 -0
- package/src/commands/doctor.mjs +256 -0
- package/src/commands/upgrade.mjs +196 -0
- package/src/commands/verify.mjs +94 -0
- package/src/doctor.mjs +109 -0
- package/src/lib/args.mjs +38 -0
- package/src/lib/clean.mjs +72 -0
- package/src/lib/fsutil.mjs +90 -0
- package/src/lib/log.mjs +40 -0
- package/src/lib/project-doctor.mjs +329 -0
- package/src/lib/registry.mjs +102 -0
- package/src/lib/rename.mjs +116 -0
- package/src/lib/schema.mjs +123 -0
- package/src/lib/toggle.mjs +130 -0
- package/src/lib/tokens.mjs +96 -0
- package/src/lib/toml.mjs +137 -0
- package/src/lib/upgrade.mjs +159 -0
- package/src/lib/verify.mjs +97 -0
- package/src/scaffold.mjs +347 -0
- package/src/verify.mjs +4 -0
- package/src/versions/registry.json +42 -0
- package/template/.github/workflows/verify.yml +70 -0
- package/template/build.gradle.kts +17 -0
- package/template/composeApp/build.gradle.kts +257 -0
- package/template/composeApp/google-services.json +29 -0
- package/template/composeApp/proguard-rules.pro +34 -0
- package/template/composeApp/src/androidDebug/AndroidManifest.xml +13 -0
- package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/ComposeRootRegistry.kt +40 -0
- package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/InspectorCatalog.kt +80 -0
- package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/InspectorHttpServer.kt +322 -0
- package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/InspectorInit.kt +16 -0
- package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/LiveSemanticsJson.kt +102 -0
- package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/RemoteControlPage.kt +106 -0
- package/template/composeApp/src/androidDebug/res/xml/debug_network_security_config.xml +9 -0
- package/template/composeApp/src/androidMain/AndroidManifest.xml +28 -0
- package/template/composeApp/src/androidMain/kotlin/com/example/app/AppApplication.kt +72 -0
- package/template/composeApp/src/androidMain/kotlin/com/example/app/MainActivity.kt +24 -0
- package/template/composeApp/src/androidMain/kotlin/com/example/app/core/connectivity/NetworkMonitor.kt +42 -0
- package/template/composeApp/src/androidMain/kotlin/com/example/app/data/local/DatabaseBuilder.android.kt +13 -0
- package/template/composeApp/src/androidMain/kotlin/com/example/app/di/AndroidModule.kt +9 -0
- package/template/composeApp/src/androidMain/kotlin/com/example/app/presentation/components/TestTagAutomation.android.kt +11 -0
- package/template/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml +9 -0
- package/template/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml +6 -0
- package/template/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml +6 -0
- package/template/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_foreground.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_foreground.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_foreground.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_foreground.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_foreground.png +0 -0
- package/template/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/template/composeApp/src/androidMain/res/values/colors.xml +6 -0
- package/template/composeApp/src/androidMain/res/values/themes.xml +9 -0
- package/template/composeApp/src/androidMain/res/values-v31/themes.xml +8 -0
- package/template/composeApp/src/androidRelease/kotlin/com/example/app/inspector/InspectorInit.kt +13 -0
- package/template/composeApp/src/commonMain/composeResources/font/DMSans_Bold.ttf +0 -0
- package/template/composeApp/src/commonMain/composeResources/font/DMSans_Medium.ttf +0 -0
- package/template/composeApp/src/commonMain/composeResources/font/DMSans_Regular.ttf +0 -0
- package/template/composeApp/src/commonMain/composeResources/font/DMSans_SemiBold.ttf +0 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/App.kt +7 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/core/connectivity/NetworkMonitor.kt +7 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/data/local/AppDatabase.kt +28 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/data/local/DatabaseBuilder.kt +14 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/data/local/ItemDao.kt +18 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/data/remote/FirebaseConfig.kt +5 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/data/remote/ItemRepositoryImpl.kt +22 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/di/AppModule.kt +23 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/domain/model/Item.kt +8 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/domain/repository/ItemRepository.kt +8 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/domain/usecase/GetItemsUseCase.kt +12 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/App.kt +13 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/components/BaseScreen.kt +69 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/components/TestTagAutomation.kt +18 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/home/DetailScreen.kt +39 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/home/HomeScreen.kt +87 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/home/HomeViewModel.kt +35 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/navigation/AppNavHost.kt +43 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/navigation/AppShell.kt +144 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/navigation/AppTab.kt +25 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/navigation/Screen.kt +15 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/profile/ProfileScreen.kt +43 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/theme/DesignToken.kt +25 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/theme/Shape.kt +12 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/theme/Theme.kt +64 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/theme/Tokens.kt +19 -0
- package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/theme/Typography.kt +36 -0
- package/template/composeApp/src/desktopMain/kotlin/com/example/app/core/connectivity/NetworkMonitor.desktop.kt +9 -0
- package/template/composeApp/src/desktopMain/kotlin/com/example/app/data/local/DatabaseBuilder.desktop.kt +13 -0
- package/template/composeApp/src/desktopMain/kotlin/com/example/app/di/DesktopModule.kt +32 -0
- package/template/composeApp/src/desktopMain/kotlin/com/example/app/main.kt +29 -0
- package/template/composeApp/src/desktopMain/kotlin/com/example/app/presentation/components/TestTagAutomation.desktop.kt +6 -0
- package/template/composeApp/src/iosMain/kotlin/com/example/app/KoinHelper.kt +50 -0
- package/template/composeApp/src/iosMain/kotlin/com/example/app/MainViewController.kt +10 -0
- package/template/composeApp/src/iosMain/kotlin/com/example/app/core/connectivity/NetworkMonitor.kt +32 -0
- package/template/composeApp/src/iosMain/kotlin/com/example/app/data/local/DatabaseBuilder.ios.kt +10 -0
- package/template/composeApp/src/iosMain/kotlin/com/example/app/presentation/components/TestTagAutomation.ios.kt +11 -0
- package/template/docs/dev-client.md +52 -0
- package/template/gitignore +21 -0
- package/template/gradle/libs.versions.toml +100 -0
- package/template/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/template/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/template/gradle.properties +9 -0
- package/template/gradlew +152 -0
- package/template/gradlew.bat +94 -0
- package/template/iosApp/Podfile +27 -0
- package/template/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png +0 -0
- package/template/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
- package/template/iosApp/iosApp/Assets.xcassets/Contents.json +6 -0
- package/template/iosApp/iosApp/ContentView.swift +17 -0
- package/template/iosApp/iosApp/GoogleService-Info.plist +34 -0
- package/template/iosApp/iosApp/Info.plist +43 -0
- package/template/iosApp/iosApp/PrivacyInfo.xcprivacy +42 -0
- package/template/iosApp/iosApp/iOSApp.swift +33 -0
- package/template/iosApp/project.yml +56 -0
- package/template/local.properties.example +2 -0
- package/template/manifest.json +125 -0
- package/template/qa/appium/README.md +23 -0
- package/template/qa/appium/lib/appium-client.mjs +225 -0
- package/template/qa/appium/package.json +8 -0
- package/template/qa/appium/run-android-smoke.mjs +39 -0
- package/template/settings.gradle.kts +34 -0
- package/template/tests/appium/cmp/conftest.py +96 -0
- package/template/tests/appium/cmp/test_smoke.py +17 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import org.jetbrains.compose.resources.ResourcesExtension
|
|
2
|
+
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
|
3
|
+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
4
|
+
|
|
5
|
+
plugins {
|
|
6
|
+
alias(libs.plugins.kotlin.multiplatform)
|
|
7
|
+
alias(libs.plugins.kotlin.serialization)
|
|
8
|
+
alias(libs.plugins.compose.multiplatform)
|
|
9
|
+
alias(libs.plugins.compose.compiler)
|
|
10
|
+
alias(libs.plugins.android.application)
|
|
11
|
+
// >>> cmp:feature firebase
|
|
12
|
+
alias(libs.plugins.google.services)
|
|
13
|
+
// <<< cmp:feature firebase
|
|
14
|
+
// >>> cmp:feature room
|
|
15
|
+
alias(libs.plugins.ksp)
|
|
16
|
+
alias(libs.plugins.room)
|
|
17
|
+
// <<< cmp:feature room
|
|
18
|
+
// >>> cmp:feature dev-client
|
|
19
|
+
alias(libs.plugins.compose.hot.reload)
|
|
20
|
+
// <<< cmp:feature dev-client
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
kotlin {
|
|
24
|
+
compilerOptions {
|
|
25
|
+
// kotlinx-datetime 0.7.x Clock/Instant delegate to the experimental kotlin.time
|
|
26
|
+
// types on Kotlin 2.2.20; opt in project-wide.
|
|
27
|
+
optIn.add("kotlin.time.ExperimentalTime")
|
|
28
|
+
// >>> cmp:feature ios
|
|
29
|
+
// iosMain cinterop Foreign APIs (NWPathMonitor, NSHomeDirectory, etc.)
|
|
30
|
+
optIn.add("kotlinx.cinterop.ExperimentalForeignApi")
|
|
31
|
+
// <<< cmp:feature ios
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
androidTarget {
|
|
35
|
+
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
|
36
|
+
compilerOptions {
|
|
37
|
+
jvmTarget.set(JvmTarget.JVM_17)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// >>> cmp:feature ios
|
|
42
|
+
listOf(
|
|
43
|
+
iosX64(),
|
|
44
|
+
iosArm64(),
|
|
45
|
+
iosSimulatorArm64()
|
|
46
|
+
).forEach { iosTarget ->
|
|
47
|
+
iosTarget.binaries.framework {
|
|
48
|
+
baseName = "ComposeApp"
|
|
49
|
+
isStatic = true
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// <<< cmp:feature ios
|
|
53
|
+
|
|
54
|
+
// >>> cmp:feature dev-client
|
|
55
|
+
// Desktop dev-client: runs the shared commonMain UI in a live JVM window — the daily dev
|
|
56
|
+
// loop. Compose Hot Reload attaches to this target (task: hotRunDesktop). See docs/dev-client.md.
|
|
57
|
+
jvm("desktop") {
|
|
58
|
+
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
|
59
|
+
compilerOptions {
|
|
60
|
+
jvmTarget.set(JvmTarget.JVM_17)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// <<< cmp:feature dev-client
|
|
64
|
+
|
|
65
|
+
sourceSets {
|
|
66
|
+
commonMain.dependencies {
|
|
67
|
+
implementation(compose.runtime)
|
|
68
|
+
implementation(compose.foundation)
|
|
69
|
+
implementation(compose.material3)
|
|
70
|
+
implementation(compose.materialIconsExtended)
|
|
71
|
+
implementation(compose.ui)
|
|
72
|
+
implementation(compose.components.resources)
|
|
73
|
+
|
|
74
|
+
// Lifecycle / ViewModel
|
|
75
|
+
implementation(libs.lifecycle.viewmodel)
|
|
76
|
+
implementation(libs.lifecycle.viewmodel.compose)
|
|
77
|
+
implementation(libs.lifecycle.runtime.compose)
|
|
78
|
+
|
|
79
|
+
// Navigation
|
|
80
|
+
implementation(libs.navigation.compose)
|
|
81
|
+
|
|
82
|
+
// Koin DI
|
|
83
|
+
implementation(libs.koin.core)
|
|
84
|
+
implementation(libs.koin.compose)
|
|
85
|
+
implementation(libs.koin.compose.viewmodel)
|
|
86
|
+
|
|
87
|
+
// Ktor
|
|
88
|
+
implementation(libs.ktor.client.core)
|
|
89
|
+
implementation(libs.ktor.client.content.negotiation)
|
|
90
|
+
implementation(libs.ktor.serialization.kotlinx.json)
|
|
91
|
+
|
|
92
|
+
// >>> cmp:feature firebase
|
|
93
|
+
implementation(libs.firebase.auth)
|
|
94
|
+
implementation(libs.firebase.firestore)
|
|
95
|
+
implementation(libs.firebase.functions)
|
|
96
|
+
implementation(libs.firebase.storage)
|
|
97
|
+
implementation(libs.firebase.messaging)
|
|
98
|
+
implementation(libs.firebase.config)
|
|
99
|
+
// <<< cmp:feature firebase
|
|
100
|
+
|
|
101
|
+
// >>> cmp:feature room
|
|
102
|
+
implementation(libs.room.runtime)
|
|
103
|
+
implementation(libs.sqlite.bundled)
|
|
104
|
+
// <<< cmp:feature room
|
|
105
|
+
|
|
106
|
+
// Kotlinx
|
|
107
|
+
implementation(libs.kotlinx.serialization.json)
|
|
108
|
+
implementation(libs.kotlinx.datetime)
|
|
109
|
+
implementation(libs.kotlinx.coroutines.core)
|
|
110
|
+
|
|
111
|
+
// Coil image loading
|
|
112
|
+
implementation(libs.coil.compose)
|
|
113
|
+
implementation(libs.coil.network.ktor)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
androidMain.dependencies {
|
|
117
|
+
implementation(libs.androidx.core.ktx)
|
|
118
|
+
implementation(libs.androidx.activity.compose)
|
|
119
|
+
implementation(libs.ktor.client.cio)
|
|
120
|
+
implementation(libs.koin.android)
|
|
121
|
+
implementation(libs.kotlinx.coroutines.android)
|
|
122
|
+
// >>> cmp:feature room
|
|
123
|
+
implementation(libs.room.runtime.android)
|
|
124
|
+
// <<< cmp:feature room
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// >>> cmp:feature ios
|
|
128
|
+
iosMain.dependencies {
|
|
129
|
+
implementation(libs.ktor.client.darwin)
|
|
130
|
+
}
|
|
131
|
+
// <<< cmp:feature ios
|
|
132
|
+
|
|
133
|
+
// >>> cmp:feature dev-client
|
|
134
|
+
val desktopMain by getting {
|
|
135
|
+
dependencies {
|
|
136
|
+
implementation(compose.desktop.currentOs)
|
|
137
|
+
implementation(libs.kotlinx.coroutines.swing)
|
|
138
|
+
implementation(libs.ktor.client.cio)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// <<< cmp:feature dev-client
|
|
142
|
+
|
|
143
|
+
commonTest.dependencies {
|
|
144
|
+
implementation(libs.kotlin.test)
|
|
145
|
+
implementation(libs.koin.test)
|
|
146
|
+
implementation(libs.kotlinx.coroutines.test)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
android {
|
|
152
|
+
namespace = "__PACKAGE__"
|
|
153
|
+
compileSdk = 35
|
|
154
|
+
|
|
155
|
+
defaultConfig {
|
|
156
|
+
applicationId = "__PACKAGE__"
|
|
157
|
+
minSdk = 24
|
|
158
|
+
targetSdk = 35
|
|
159
|
+
versionCode = 1
|
|
160
|
+
versionName = "1.0.0"
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
packaging {
|
|
164
|
+
resources {
|
|
165
|
+
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
buildFeatures {
|
|
170
|
+
buildConfig = true
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
buildTypes {
|
|
174
|
+
// >>> cmp:feature firebase
|
|
175
|
+
getByName("debug") {
|
|
176
|
+
// Debug builds point GitLive Firebase at the local emulators (see Application/KoinHelper).
|
|
177
|
+
// 10.0.2.2 is the Android emulator's host-loopback alias.
|
|
178
|
+
buildConfigField("boolean", "USE_FIREBASE_EMULATORS", "true")
|
|
179
|
+
buildConfigField("String", "FIREBASE_EMULATOR_HOST", "\"10.0.2.2\"")
|
|
180
|
+
buildConfigField("int", "FIREBASE_AUTH_PORT", "9099")
|
|
181
|
+
buildConfigField("int", "FIREBASE_FIRESTORE_PORT", "8080")
|
|
182
|
+
buildConfigField("int", "FIREBASE_FUNCTIONS_PORT", "5001")
|
|
183
|
+
buildConfigField("int", "FIREBASE_STORAGE_PORT", "9199")
|
|
184
|
+
manifestPlaceholders["usesCleartextTraffic"] = "true"
|
|
185
|
+
}
|
|
186
|
+
getByName("release") {
|
|
187
|
+
isMinifyEnabled = true
|
|
188
|
+
isShrinkResources = true
|
|
189
|
+
buildConfigField("boolean", "USE_FIREBASE_EMULATORS", "false")
|
|
190
|
+
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
|
191
|
+
proguardFiles(
|
|
192
|
+
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
193
|
+
"proguard-rules.pro"
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
// <<< cmp:feature firebase
|
|
197
|
+
// >>> cmp:feature !firebase
|
|
198
|
+
getByName("release") {
|
|
199
|
+
isMinifyEnabled = true
|
|
200
|
+
isShrinkResources = true
|
|
201
|
+
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
|
202
|
+
proguardFiles(
|
|
203
|
+
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
204
|
+
"proguard-rules.pro"
|
|
205
|
+
)
|
|
206
|
+
}
|
|
207
|
+
getByName("debug") {
|
|
208
|
+
manifestPlaceholders["usesCleartextTraffic"] = "true"
|
|
209
|
+
}
|
|
210
|
+
// <<< cmp:feature !firebase
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
compileOptions {
|
|
214
|
+
sourceCompatibility = JavaVersion.VERSION_17
|
|
215
|
+
targetCompatibility = JavaVersion.VERSION_17
|
|
216
|
+
isCoreLibraryDesugaringEnabled = true
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
dependencies {
|
|
221
|
+
// >>> cmp:feature room
|
|
222
|
+
add("kspAndroid", libs.room.compiler)
|
|
223
|
+
// >>> cmp:feature ios
|
|
224
|
+
add("kspIosSimulatorArm64", libs.room.compiler)
|
|
225
|
+
add("kspIosX64", libs.room.compiler)
|
|
226
|
+
add("kspIosArm64", libs.room.compiler)
|
|
227
|
+
// <<< cmp:feature ios
|
|
228
|
+
// >>> cmp:feature dev-client
|
|
229
|
+
add("kspDesktop", libs.room.compiler)
|
|
230
|
+
// <<< cmp:feature dev-client
|
|
231
|
+
// <<< cmp:feature room
|
|
232
|
+
add("coreLibraryDesugaring", libs.android.desugar.jdk)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Pin the generated resources accessor package so `__PACKAGE__.generated.resources.Res`
|
|
236
|
+
// is stable regardless of the Gradle project name. The default would derive from
|
|
237
|
+
// rootProject.name (slugified), which couples imports to the app-name token.
|
|
238
|
+
compose.resources {
|
|
239
|
+
publicResClass = true
|
|
240
|
+
packageOfResClass = "__PACKAGE__.generated.resources"
|
|
241
|
+
generateResClass = ResourcesExtension.ResourceClassGeneration.Always
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// >>> cmp:feature room
|
|
245
|
+
room {
|
|
246
|
+
schemaDirectory("$projectDir/schemas")
|
|
247
|
+
}
|
|
248
|
+
// <<< cmp:feature room
|
|
249
|
+
|
|
250
|
+
// >>> cmp:feature dev-client
|
|
251
|
+
// Entry point for the desktop dev-client window (and the class Compose Hot Reload launches).
|
|
252
|
+
compose.desktop {
|
|
253
|
+
application {
|
|
254
|
+
mainClass = "__PACKAGE__.MainKt"
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// <<< cmp:feature dev-client
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"project_info": {
|
|
3
|
+
"project_number": "000000000000",
|
|
4
|
+
"project_id": "REPLACE_ME_PROJECT_ID",
|
|
5
|
+
"storage_bucket": "REPLACE_ME_PROJECT_ID.appspot.com"
|
|
6
|
+
},
|
|
7
|
+
"client": [
|
|
8
|
+
{
|
|
9
|
+
"client_info": {
|
|
10
|
+
"mobilesdk_app_id": "1:000000000000:android:0000000000000000000000",
|
|
11
|
+
"android_client_info": {
|
|
12
|
+
"package_name": "__PACKAGE__"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"oauth_client": [],
|
|
16
|
+
"api_key": [
|
|
17
|
+
{
|
|
18
|
+
"current_key": "REPLACE_ME_ANDROID_API_KEY"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"services": {
|
|
22
|
+
"appinvite_service": {
|
|
23
|
+
"other_platform_oauth_client": []
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"configuration_version": "1"
|
|
29
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Kotlin Serialization
|
|
2
|
+
-keepattributes *Annotation*, InnerClasses
|
|
3
|
+
-dontnote kotlinx.serialization.AnnotationsKt
|
|
4
|
+
-keepclassmembers class kotlinx.serialization.json.** { *** Companion; }
|
|
5
|
+
-keepclasseswithmembers class kotlinx.serialization.json.** { kotlinx.serialization.KSerializer serializer(...); }
|
|
6
|
+
-keep,includedescriptorclasses class __PACKAGE__.**$$serializer { *; }
|
|
7
|
+
-keepclassmembers class __PACKAGE__.** {
|
|
8
|
+
*** Companion;
|
|
9
|
+
}
|
|
10
|
+
-keepclasseswithmembers class __PACKAGE__.** {
|
|
11
|
+
kotlinx.serialization.KSerializer serializer(...);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
# Koin
|
|
15
|
+
-keep class org.koin.** { *; }
|
|
16
|
+
-keepnames class org.koin.**
|
|
17
|
+
|
|
18
|
+
# Firebase
|
|
19
|
+
-keep class com.google.firebase.** { *; }
|
|
20
|
+
-keep class dev.gitlive.firebase.** { *; }
|
|
21
|
+
-dontwarn com.google.firebase.**
|
|
22
|
+
|
|
23
|
+
# Coroutines
|
|
24
|
+
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
|
|
25
|
+
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
|
|
26
|
+
|
|
27
|
+
# Coil
|
|
28
|
+
-dontwarn okio.**
|
|
29
|
+
|
|
30
|
+
# Navigation
|
|
31
|
+
-keepnames class androidx.navigation.**
|
|
32
|
+
|
|
33
|
+
# Compose
|
|
34
|
+
-keep class androidx.compose.** { *; }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
3
|
+
|
|
4
|
+
<!-- >>> cmp:feature inspector -->
|
|
5
|
+
<!-- The debug inspector server needs socket permission even if a future template fork
|
|
6
|
+
drops INTERNET from the main manifest; loopback-only bind, never on the LAN. -->
|
|
7
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
8
|
+
<!-- <<< cmp:feature inspector -->
|
|
9
|
+
|
|
10
|
+
<application
|
|
11
|
+
android:networkSecurityConfig="@xml/debug_network_security_config"
|
|
12
|
+
android:usesCleartextTraffic="true" />
|
|
13
|
+
</manifest>
|
package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/ComposeRootRegistry.kt
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
package __PACKAGE__.inspector
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import androidx.compose.ui.platform.ViewRootForTest
|
|
5
|
+
import java.lang.ref.WeakReference
|
|
6
|
+
import java.util.concurrent.CopyOnWriteArrayList
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Debug-only registry of live Compose roots, discovered via the public
|
|
10
|
+
* [ViewRootForTest.Companion.onViewCreatedCallback] hook — the same mechanism the Compose
|
|
11
|
+
* test framework uses. Installed from [startInspector] in Application.onCreate, BEFORE any
|
|
12
|
+
* Activity exists, so every root (including dialogs/popups, each its own AndroidComposeView)
|
|
13
|
+
* is captured.
|
|
14
|
+
*
|
|
15
|
+
* `@SuppressLint("VisibleForTests")`: ViewRootForTest is public API carrying a lint-severity
|
|
16
|
+
* `@VisibleForTesting` annotation — debug-only usage is precisely its spirit. This class never
|
|
17
|
+
* ships in release (the whole `inspector` package exists only in the androidDebug source set).
|
|
18
|
+
*/
|
|
19
|
+
@SuppressLint("VisibleForTests")
|
|
20
|
+
object ComposeRootRegistry {
|
|
21
|
+
|
|
22
|
+
private val roots = CopyOnWriteArrayList<WeakReference<ViewRootForTest>>()
|
|
23
|
+
|
|
24
|
+
/** Install the root-discovery callback. Must run before the first Activity's setContent. */
|
|
25
|
+
fun install() {
|
|
26
|
+
ViewRootForTest.onViewCreatedCallback = { root ->
|
|
27
|
+
roots.removeAll { it.get() == null }
|
|
28
|
+
roots += WeakReference(root)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The topmost live root: attached to a window, preferring the one with window focus
|
|
34
|
+
* (so an open dialog/popup wins over the screen beneath it).
|
|
35
|
+
*/
|
|
36
|
+
fun current(): ViewRootForTest? {
|
|
37
|
+
val live = roots.mapNotNull { it.get() }.filter { it.view.isAttachedToWindow }
|
|
38
|
+
return live.lastOrNull { it.view.hasWindowFocus() } ?: live.lastOrNull()
|
|
39
|
+
}
|
|
40
|
+
}
|
package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/InspectorCatalog.kt
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
package __PACKAGE__.inspector
|
|
2
|
+
|
|
3
|
+
import androidx.compose.ui.graphics.Color
|
|
4
|
+
import androidx.compose.ui.graphics.toArgb
|
|
5
|
+
import androidx.compose.ui.unit.Dp
|
|
6
|
+
import __PACKAGE__.presentation.theme.__THEME_PREFIX__Colors
|
|
7
|
+
import __PACKAGE__.presentation.theme.__THEME_PREFIX__Tokens
|
|
8
|
+
import kotlinx.serialization.json.Json
|
|
9
|
+
import kotlinx.serialization.json.JsonElement
|
|
10
|
+
import kotlinx.serialization.json.JsonPrimitive
|
|
11
|
+
import kotlinx.serialization.json.buildJsonObject
|
|
12
|
+
import kotlinx.serialization.json.put
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The declared design-system catalog, served on GET /inspect/design-system in the shape the
|
|
16
|
+
* cmp-inspector MCP consumes: `{ "colors": {name: "#RRGGBB"}, "dimens": {name: "16dp"} }`.
|
|
17
|
+
*
|
|
18
|
+
* Hand-registry by design (no kotlin-reflect, no codegen): values are read from the REAL
|
|
19
|
+
* `__THEME_PREFIX__Colors` / `__THEME_PREFIX__Tokens` objects — never string-literal
|
|
20
|
+
* duplicates — so renaming a token breaks this file at compile time. If you ADD a token to
|
|
21
|
+
* the theme, add it here too (`create-cmp doctor` warns when a declared token is missing).
|
|
22
|
+
*/
|
|
23
|
+
object InspectorCatalog {
|
|
24
|
+
|
|
25
|
+
private val prettyJson = Json { prettyPrint = true }
|
|
26
|
+
|
|
27
|
+
fun json(): String {
|
|
28
|
+
val doc = buildJsonObject {
|
|
29
|
+
put("colors", buildJsonObject {
|
|
30
|
+
put("Primary", __THEME_PREFIX__Colors.Primary.toHex())
|
|
31
|
+
put("OnPrimary", __THEME_PREFIX__Colors.OnPrimary.toHex())
|
|
32
|
+
put("Accent", __THEME_PREFIX__Colors.Accent.toHex())
|
|
33
|
+
put("OnAccent", __THEME_PREFIX__Colors.OnAccent.toHex())
|
|
34
|
+
put("Secondary", __THEME_PREFIX__Colors.Secondary.toHex())
|
|
35
|
+
put("Error", __THEME_PREFIX__Colors.Error.toHex())
|
|
36
|
+
put("Success", __THEME_PREFIX__Colors.Success.toHex())
|
|
37
|
+
put("Warning", __THEME_PREFIX__Colors.Warning.toHex())
|
|
38
|
+
put("Info", __THEME_PREFIX__Colors.Info.toHex())
|
|
39
|
+
put("Background", __THEME_PREFIX__Colors.Background.toHex())
|
|
40
|
+
put("Surface", __THEME_PREFIX__Colors.Surface.toHex())
|
|
41
|
+
put("SurfaceVariant", __THEME_PREFIX__Colors.SurfaceVariant.toHex())
|
|
42
|
+
put("OnSurface", __THEME_PREFIX__Colors.OnSurface.toHex())
|
|
43
|
+
put("OnSurfaceVariant", __THEME_PREFIX__Colors.OnSurfaceVariant.toHex())
|
|
44
|
+
put("Outline", __THEME_PREFIX__Colors.Outline.toHex())
|
|
45
|
+
put("OutlineVariant", __THEME_PREFIX__Colors.OutlineVariant.toHex())
|
|
46
|
+
put("Divider", __THEME_PREFIX__Colors.Divider.toHex())
|
|
47
|
+
})
|
|
48
|
+
put("dimens", buildJsonObject {
|
|
49
|
+
put("ElevationCard", __THEME_PREFIX__Tokens.ElevationCard.token())
|
|
50
|
+
put("ElevationModal", __THEME_PREFIX__Tokens.ElevationModal.token())
|
|
51
|
+
put("PaddingPage", __THEME_PREFIX__Tokens.PaddingPage.token())
|
|
52
|
+
put("PaddingCard", __THEME_PREFIX__Tokens.PaddingCard.token())
|
|
53
|
+
put("GapCard", __THEME_PREFIX__Tokens.GapCard.token())
|
|
54
|
+
put("BottomNavHeight", __THEME_PREFIX__Tokens.BottomNavHeight.token())
|
|
55
|
+
put("RadiusCard", __THEME_PREFIX__Tokens.RadiusCard.token())
|
|
56
|
+
put("RadiusPill", __THEME_PREFIX__Tokens.RadiusPill.token())
|
|
57
|
+
put("RadiusModal", __THEME_PREFIX__Tokens.RadiusModal.token())
|
|
58
|
+
put("RadiusInput", __THEME_PREFIX__Tokens.RadiusInput.token())
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
return prettyJson.encodeToString(JsonElement.serializer(), doc)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** "#RRGGBB" for fully-opaque colours (the catalog convention), "#AARRGGBB" otherwise. */
|
|
65
|
+
private fun Color.toHex(): String {
|
|
66
|
+
val argb = toArgb()
|
|
67
|
+
val alpha = (argb ushr 24) and 0xFF
|
|
68
|
+
return if (alpha == 0xFF) {
|
|
69
|
+
"#%06X".format(argb and 0xFFFFFF)
|
|
70
|
+
} else {
|
|
71
|
+
"#%08X".format(argb)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** "16dp" (integer dp values render without the decimal point). */
|
|
76
|
+
private fun Dp.token(): String {
|
|
77
|
+
val v = value
|
|
78
|
+
return if (v == v.toInt().toFloat()) "${v.toInt()}dp" else "${v}dp"
|
|
79
|
+
}
|
|
80
|
+
}
|