@jetstart/cli 1.7.0 → 2.0.2
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/README.md +133 -41
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +11 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/android-emulator.d.ts.map +1 -0
- package/dist/commands/android-emulator.js.map +1 -0
- package/dist/commands/build.d.ts +13 -1
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +279 -29
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/clean.d.ts +23 -0
- package/dist/commands/clean.d.ts.map +1 -0
- package/dist/commands/clean.js +191 -0
- package/dist/commands/clean.js.map +1 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +41 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +51 -9
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/install-audit.d.ts.map +1 -0
- package/dist/commands/install-audit.js.map +1 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/android-sdk.d.ts.map +1 -0
- package/dist/utils/android-sdk.js +2 -2
- package/dist/utils/android-sdk.js.map +1 -0
- package/dist/utils/downloader.d.ts.map +1 -0
- package/dist/utils/downloader.js.map +1 -0
- package/dist/utils/emulator-deployer.d.ts.map +1 -0
- package/dist/utils/emulator-deployer.js.map +1 -0
- package/dist/utils/emulator.d.ts.map +1 -0
- package/dist/utils/emulator.js +5 -4
- package/dist/utils/emulator.js.map +1 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/java.d.ts.map +1 -0
- package/dist/utils/java.js +5 -5
- package/dist/utils/java.js.map +1 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/open.d.ts.map +1 -0
- package/dist/utils/open.js.map +1 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js.map +1 -0
- package/dist/utils/spinner.d.ts.map +1 -0
- package/dist/utils/spinner.js.map +1 -0
- package/dist/utils/system-tools.d.ts.map +1 -0
- package/dist/utils/system-tools.js.map +1 -0
- package/dist/utils/template.d.ts +13 -1
- package/dist/utils/template.d.ts.map +1 -0
- package/dist/utils/template.js +134 -1000
- package/dist/utils/template.js.map +1 -0
- package/maven-repo/com/jetstart/hot-reload/com.jetstart.hot-reload.gradle.plugin/1.0.0/com.jetstart.hot-reload.gradle.plugin-1.0.0.pom +15 -0
- package/maven-repo/com/jetstart/hot-reload/com.jetstart.hot-reload.gradle.plugin/1.0.0/com.jetstart.hot-reload.gradle.plugin-1.0.0.pom.md5 +1 -0
- package/maven-repo/com/jetstart/hot-reload/com.jetstart.hot-reload.gradle.plugin/1.0.0/com.jetstart.hot-reload.gradle.plugin-1.0.0.pom.sha1 +1 -0
- package/maven-repo/com/jetstart/hot-reload/com.jetstart.hot-reload.gradle.plugin/1.0.0/com.jetstart.hot-reload.gradle.plugin-1.0.0.pom.sha256 +1 -0
- package/maven-repo/com/jetstart/hot-reload/com.jetstart.hot-reload.gradle.plugin/1.0.0/com.jetstart.hot-reload.gradle.plugin-1.0.0.pom.sha512 +1 -0
- package/maven-repo/com/jetstart/hot-reload/com.jetstart.hot-reload.gradle.plugin/maven-metadata.xml +13 -0
- package/maven-repo/com/jetstart/hot-reload/com.jetstart.hot-reload.gradle.plugin/maven-metadata.xml.md5 +1 -0
- package/maven-repo/com/jetstart/hot-reload/com.jetstart.hot-reload.gradle.plugin/maven-metadata.xml.sha1 +1 -0
- package/maven-repo/com/jetstart/hot-reload/com.jetstart.hot-reload.gradle.plugin/maven-metadata.xml.sha256 +1 -0
- package/maven-repo/com/jetstart/hot-reload/com.jetstart.hot-reload.gradle.plugin/maven-metadata.xml.sha512 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0-sources.jar +0 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0-sources.jar.md5 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0-sources.jar.sha1 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0-sources.jar.sha256 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0-sources.jar.sha512 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.aar +0 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.aar.md5 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.aar.sha1 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.aar.sha256 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.aar.sha512 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.module +124 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.module.md5 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.module.sha1 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.module.sha256 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.module.sha512 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.pom +46 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.pom.md5 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.pom.sha1 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.pom.sha256 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/1.0.0/hot-reload-runtime-1.0.0.pom.sha512 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/maven-metadata.xml +13 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/maven-metadata.xml.md5 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/maven-metadata.xml.sha1 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/maven-metadata.xml.sha256 +1 -0
- package/maven-repo/com/jetstart/hot-reload-runtime/maven-metadata.xml.sha512 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.jar +0 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.jar.md5 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.jar.sha1 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.jar.sha256 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.jar.sha512 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.module +103 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.module.md5 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.module.sha1 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.module.sha256 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.module.sha512 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.pom +38 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.pom.md5 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.pom.sha1 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.pom.sha256 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/1.0.0/jetstart-gradle-plugin-1.0.0.pom.sha512 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/maven-metadata.xml +13 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/maven-metadata.xml.md5 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/maven-metadata.xml.sha1 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/maven-metadata.xml.sha256 +1 -0
- package/maven-repo/com/jetstart/jetstart-gradle-plugin/maven-metadata.xml.sha512 +1 -0
- package/package.json +14 -5
- package/scripts/build-java.js +34 -0
- package/template/base/README.md +34 -0
- package/template/base/app/build.gradle +80 -0
- package/template/base/app/proguard-rules.pro +33 -0
- package/template/base/app/src/main/AndroidManifest.xml +33 -0
- package/template/base/app/src/main/java/__PACKAGE_PATH__/MainActivity.kt +64 -0
- package/template/base/app/src/main/java/__PACKAGE_PATH__/data/AppDatabase.kt +46 -0
- package/template/base/app/src/main/java/__PACKAGE_PATH__/data/Note.kt +12 -0
- package/template/base/app/src/main/java/__PACKAGE_PATH__/data/NoteDao.kt +23 -0
- package/template/base/app/src/main/java/__PACKAGE_PATH__/logic/TaggingEngine.kt +26 -0
- package/template/base/app/src/main/java/__PACKAGE_PATH__/ui/NotesScreen.kt +185 -0
- package/template/base/app/src/main/java/__PACKAGE_PATH__/ui/NotesViewModel.kt +58 -0
- package/template/base/app/src/main/java/__PACKAGE_PATH__/ui/TestScreen.kt +12 -0
- package/template/base/app/src/main/res/values/colors.xml +10 -0
- package/template/base/app/src/main/res/values/strings.xml +4 -0
- package/template/base/app/src/main/res/values/themes.xml +9 -0
- package/template/base/app/src/main/res/xml/network_security_config.xml +8 -0
- package/template/base/app/src/main/res/xml/provider_paths.xml +4 -0
- package/template/base/build.gradle +28 -0
- package/template/base/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/template/base/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/template/base/gradle.properties +13 -0
- package/template/base/gradlew +248 -0
- package/template/base/gradlew.bat +92 -0
- package/template/base/jetstart.config.json +11 -0
- package/template/base/settings.gradle +20 -0
- package/.eslintrc.json +0 -6
- package/src/cli.ts +0 -99
- package/src/commands/android-emulator.ts +0 -304
- package/src/commands/build.ts +0 -60
- package/src/commands/create.ts +0 -232
- package/src/commands/dev.ts +0 -198
- package/src/commands/index.ts +0 -10
- package/src/commands/install-audit.ts +0 -227
- package/src/commands/logs.ts +0 -117
- package/src/index.ts +0 -17
- package/src/types/index.ts +0 -53
- package/src/utils/android-sdk.ts +0 -512
- package/src/utils/downloader.ts +0 -201
- package/src/utils/emulator-deployer.ts +0 -210
- package/src/utils/emulator.ts +0 -463
- package/src/utils/index.ts +0 -8
- package/src/utils/java.ts +0 -369
- package/src/utils/logger.ts +0 -42
- package/src/utils/open.ts +0 -36
- package/src/utils/prompt.ts +0 -56
- package/src/utils/spinner.ts +0 -25
- package/src/utils/system-tools.ts +0 -648
- package/src/utils/template.ts +0 -1214
- package/tests/create.test.ts +0 -33
- package/tests/utils.test.ts +0 -17
- package/tsconfig.json +0 -25
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
A JetStart project with Kotlin and Jetpack Compose.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Start development server
|
|
9
|
+
jetstart dev
|
|
10
|
+
|
|
11
|
+
# Build production APK
|
|
12
|
+
jetstart build
|
|
13
|
+
|
|
14
|
+
# View logs
|
|
15
|
+
jetstart logs
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Project Structure
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
{{PROJECT_NAME}}/
|
|
22
|
+
├── app/
|
|
23
|
+
│ └── src/
|
|
24
|
+
│ └── main/
|
|
25
|
+
│ ├── java/ # Kotlin source files
|
|
26
|
+
│ └── res/ # Resources
|
|
27
|
+
├── jetstart.config.json # JetStart configuration
|
|
28
|
+
└── build.gradle # Gradle build file
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Learn More
|
|
32
|
+
|
|
33
|
+
- [JetStart Documentation](https://github.com/phantom/jetstart)
|
|
34
|
+
- [Jetpack Compose](https://developer.android.com/jetpack/compose)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
plugins {
|
|
2
|
+
id 'com.android.application'
|
|
3
|
+
id 'org.jetbrains.kotlin.android'
|
|
4
|
+
id 'com.google.devtools.ksp'
|
|
5
|
+
id 'com.jetstart.hot-reload' version '1.0.0' // True hot reload instrumentation
|
|
6
|
+
id 'org.jetbrains.kotlin.plugin.compose'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
android {
|
|
10
|
+
namespace '{{PACKAGE_NAME}}'
|
|
11
|
+
compileSdk 34
|
|
12
|
+
|
|
13
|
+
defaultConfig {
|
|
14
|
+
applicationId "{{PACKAGE_NAME}}"
|
|
15
|
+
minSdk 24
|
|
16
|
+
targetSdk 34
|
|
17
|
+
versionCode 1
|
|
18
|
+
versionName "1.0.0"
|
|
19
|
+
|
|
20
|
+
// JetStart injected fields
|
|
21
|
+
buildConfigField "String", "JETSTART_SERVER_URL", "\"\"" // injected by: jetstart dev
|
|
22
|
+
buildConfigField "String", "JETSTART_SESSION_ID", "\"\"" // injected by: jetstart dev
|
|
23
|
+
// End JetStart fields
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
buildTypes {
|
|
27
|
+
debug {
|
|
28
|
+
debuggable true
|
|
29
|
+
}
|
|
30
|
+
release {
|
|
31
|
+
debuggable false
|
|
32
|
+
minifyEnabled true
|
|
33
|
+
shrinkResources true
|
|
34
|
+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
|
35
|
+
// Signing config is injected by `jetstart build --sign` via keystore.properties
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
compileOptions {
|
|
40
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
41
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
kotlinOptions {
|
|
45
|
+
jvmTarget = '17'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
buildFeatures {
|
|
49
|
+
compose true
|
|
50
|
+
buildConfig true // Required for JetStart hot reload
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
dependencies {
|
|
57
|
+
implementation 'androidx.core:core-ktx:1.12.0'
|
|
58
|
+
implementation 'androidx.appcompat:appcompat:1.6.1'
|
|
59
|
+
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
|
|
60
|
+
implementation 'androidx.activity:activity-compose:1.8.1'
|
|
61
|
+
implementation platform('androidx.compose:compose-bom:2023.10.01')
|
|
62
|
+
implementation 'androidx.compose.ui:ui'
|
|
63
|
+
implementation 'androidx.compose.ui:ui-graphics'
|
|
64
|
+
implementation 'androidx.compose.ui:ui-tooling-preview'
|
|
65
|
+
implementation 'androidx.compose.material3:material3'
|
|
66
|
+
|
|
67
|
+
// Room
|
|
68
|
+
implementation 'androidx.room:room-runtime:2.6.1'
|
|
69
|
+
implementation 'androidx.room:room-ktx:2.6.1'
|
|
70
|
+
ksp 'androidx.room:room-compiler:2.6.1'
|
|
71
|
+
|
|
72
|
+
// Gson
|
|
73
|
+
implementation 'com.google.code.gson:gson:2.10.1'
|
|
74
|
+
|
|
75
|
+
// JetStart Hot Reload Runtime
|
|
76
|
+
implementation 'com.jetstart:hot-reload-runtime:1.0.0'
|
|
77
|
+
|
|
78
|
+
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2"
|
|
79
|
+
|
|
80
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# JetStart default ProGuard/R8 rules
|
|
2
|
+
# Add your project-specific rules at the bottom.
|
|
3
|
+
# Kotlin
|
|
4
|
+
-keep class kotlin.** { *; }
|
|
5
|
+
-keepclassmembers class **$WhenMappings { <fields>; }
|
|
6
|
+
-dontwarn kotlin.**
|
|
7
|
+
# Jetpack Compose
|
|
8
|
+
-keep class androidx.compose.** { *; }
|
|
9
|
+
-keepclassmembers class androidx.compose.** { *; }
|
|
10
|
+
-dontwarn androidx.compose.**
|
|
11
|
+
# Room
|
|
12
|
+
-keep class * extends androidx.room.RoomDatabase { *; }
|
|
13
|
+
-keep @androidx.room.Entity class * { *; }
|
|
14
|
+
-keep @androidx.room.Dao class * { *; }
|
|
15
|
+
-dontwarn androidx.room.**
|
|
16
|
+
# Gson (JSON serialization)
|
|
17
|
+
-keepclassmembers class * {
|
|
18
|
+
@com.google.gson.annotations.SerializedName <fields>;
|
|
19
|
+
}
|
|
20
|
+
-keep class * implements com.google.gson.TypeAdapterFactory { *; }
|
|
21
|
+
# OkHttp + WebSocket
|
|
22
|
+
# Only used by HotReload (debug only). R8 strips the entire
|
|
23
|
+
# HotReload code path in release builds via BuildConfig.DEBUG = false.
|
|
24
|
+
-dontwarn okhttp3.**
|
|
25
|
+
-dontwarn okio.**
|
|
26
|
+
# DivKit
|
|
27
|
+
-keep class com.yandex.div.** { *; }
|
|
28
|
+
-dontwarn com.yandex.div.**
|
|
29
|
+
# Enum names (required for serialization)
|
|
30
|
+
-keepclassmembers enum * { *; }
|
|
31
|
+
# App data classes used by Room
|
|
32
|
+
-keep class {{PACKAGE_NAME}}.data.** { *; }
|
|
33
|
+
# Add your own keep rules below this line
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
3
|
+
|
|
4
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
5
|
+
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
|
6
|
+
|
|
7
|
+
<application
|
|
8
|
+
android:allowBackup="true"
|
|
9
|
+
android:label="@string/app_name"
|
|
10
|
+
android:theme="@style/Theme.{{THEME_NAME}}"
|
|
11
|
+
android:networkSecurityConfig="@xml/network_security_config">
|
|
12
|
+
|
|
13
|
+
<provider
|
|
14
|
+
android:name="androidx.core.content.FileProvider"
|
|
15
|
+
android:authorities="${applicationId}.fileprovider"
|
|
16
|
+
android:exported="false"
|
|
17
|
+
android:grantUriPermissions="true">
|
|
18
|
+
<meta-data
|
|
19
|
+
android:name="android.support.FILE_PROVIDER_PATHS"
|
|
20
|
+
android:resource="@xml/provider_paths" />
|
|
21
|
+
</provider>
|
|
22
|
+
|
|
23
|
+
<activity
|
|
24
|
+
android:name=".MainActivity"
|
|
25
|
+
android:exported="true">
|
|
26
|
+
<intent-filter>
|
|
27
|
+
<action android:name="android.intent.action.MAIN" />
|
|
28
|
+
<category android:name="android.intent.category.LAUNCHER" />
|
|
29
|
+
</intent-filter>
|
|
30
|
+
</activity>
|
|
31
|
+
</application>
|
|
32
|
+
|
|
33
|
+
</manifest>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
package {{PACKAGE_NAME}}
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import androidx.appcompat.app.AppCompatActivity
|
|
5
|
+
import androidx.activity.compose.setContent
|
|
6
|
+
import androidx.compose.foundation.layout.*
|
|
7
|
+
import androidx.compose.material3.*
|
|
8
|
+
import androidx.compose.runtime.*
|
|
9
|
+
import androidx.compose.ui.Alignment
|
|
10
|
+
import androidx.compose.ui.Modifier
|
|
11
|
+
import androidx.compose.ui.unit.dp
|
|
12
|
+
import {{PACKAGE_NAME}}.ui.NotesScreen
|
|
13
|
+
import com.jetstart.hotreload.HotReload
|
|
14
|
+
|
|
15
|
+
class MainActivity : AppCompatActivity() {
|
|
16
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
17
|
+
super.onCreate(savedInstanceState)
|
|
18
|
+
|
|
19
|
+
// Hot reload is ONLY active in debug builds.
|
|
20
|
+
// In release builds this block is completely eliminated by R8 (BuildConfig.DEBUG = false).
|
|
21
|
+
if (BuildConfig.DEBUG) {
|
|
22
|
+
try {
|
|
23
|
+
val serverUrl = BuildConfig.JETSTART_SERVER_URL
|
|
24
|
+
val sessionId = BuildConfig.JETSTART_SESSION_ID
|
|
25
|
+
if (serverUrl.isNotEmpty()) {
|
|
26
|
+
HotReload.connect(this, serverUrl, sessionId)
|
|
27
|
+
}
|
|
28
|
+
} catch (e: Exception) {
|
|
29
|
+
android.util.Log.w("MainActivity", "Hot reload not configured: ${e.message}")
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
setContent {
|
|
34
|
+
MaterialTheme {
|
|
35
|
+
Surface(
|
|
36
|
+
modifier = Modifier.fillMaxSize(),
|
|
37
|
+
color = MaterialTheme.colorScheme.background
|
|
38
|
+
) {
|
|
39
|
+
// Observe reload version - forces recomposition when DEX hot reload happens
|
|
40
|
+
val reloadVersion by HotReload.reloadVersion.collectAsState()
|
|
41
|
+
|
|
42
|
+
// Use reloadVersion as key to force recomposition of entire tree
|
|
43
|
+
key(reloadVersion) {
|
|
44
|
+
// Normal mode: render actual Compose code
|
|
45
|
+
AppContent()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
override fun onDestroy() {
|
|
53
|
+
super.onDestroy()
|
|
54
|
+
if (BuildConfig.DEBUG) { HotReload.disconnect() }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Main App Content
|
|
60
|
+
*/
|
|
61
|
+
@Composable
|
|
62
|
+
fun AppContent() {
|
|
63
|
+
NotesScreen()
|
|
64
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
package {{PACKAGE_NAME}}.data
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import androidx.room.Database
|
|
5
|
+
import androidx.room.Room
|
|
6
|
+
import androidx.room.RoomDatabase
|
|
7
|
+
import androidx.room.TypeConverter
|
|
8
|
+
import androidx.room.TypeConverters
|
|
9
|
+
import com.google.gson.Gson
|
|
10
|
+
import com.google.gson.reflect.TypeToken
|
|
11
|
+
|
|
12
|
+
@Database(entities = [Note::class], version = 1, exportSchema = false)
|
|
13
|
+
@TypeConverters(Converters::class)
|
|
14
|
+
abstract class AppDatabase : RoomDatabase() {
|
|
15
|
+
abstract fun noteDao(): NoteDao
|
|
16
|
+
|
|
17
|
+
companion object {
|
|
18
|
+
@Volatile
|
|
19
|
+
private var INSTANCE: AppDatabase? = null
|
|
20
|
+
|
|
21
|
+
fun getDatabase(context: Context): AppDatabase {
|
|
22
|
+
return INSTANCE ?: synchronized(this) {
|
|
23
|
+
val instance = Room.databaseBuilder(
|
|
24
|
+
context.applicationContext,
|
|
25
|
+
AppDatabase::class.java,
|
|
26
|
+
"note_database"
|
|
27
|
+
).build()
|
|
28
|
+
INSTANCE = instance
|
|
29
|
+
instance
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class Converters {
|
|
36
|
+
@TypeConverter
|
|
37
|
+
fun fromString(value: String): List<String> {
|
|
38
|
+
val listType = object : TypeToken<List<String>>() {}.type
|
|
39
|
+
return Gson().fromJson(value, listType)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@TypeConverter
|
|
43
|
+
fun fromList(list: List<String>): String {
|
|
44
|
+
return Gson().toJson(list)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
package {{PACKAGE_NAME}}.data
|
|
2
|
+
|
|
3
|
+
import androidx.room.Entity
|
|
4
|
+
import androidx.room.PrimaryKey
|
|
5
|
+
|
|
6
|
+
@Entity(tableName = "notes")
|
|
7
|
+
data class Note(
|
|
8
|
+
@PrimaryKey(autoGenerate = true) val id: Int = 0,
|
|
9
|
+
val content: String,
|
|
10
|
+
val tags: List<String>,
|
|
11
|
+
val timestamp: Long = System.currentTimeMillis()
|
|
12
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
package {{PACKAGE_NAME}}.data
|
|
2
|
+
|
|
3
|
+
import androidx.room.Dao
|
|
4
|
+
import androidx.room.Delete
|
|
5
|
+
import androidx.room.Insert
|
|
6
|
+
import androidx.room.OnConflictStrategy
|
|
7
|
+
import androidx.room.Query
|
|
8
|
+
import kotlinx.coroutines.flow.Flow
|
|
9
|
+
|
|
10
|
+
@Dao
|
|
11
|
+
interface NoteDao {
|
|
12
|
+
@Query("SELECT * FROM notes ORDER BY timestamp DESC")
|
|
13
|
+
fun getAllNotes(): Flow<List<Note>>
|
|
14
|
+
|
|
15
|
+
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
|
16
|
+
suspend fun insertNote(note: Note)
|
|
17
|
+
|
|
18
|
+
@Delete
|
|
19
|
+
suspend fun deleteNote(note: Note)
|
|
20
|
+
|
|
21
|
+
@Query("SELECT * FROM notes WHERE content LIKE '%' || :query || '%'")
|
|
22
|
+
fun searchNotes(query: String): Flow<List<Note>>
|
|
23
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
package {{PACKAGE_NAME}}.logic
|
|
2
|
+
|
|
3
|
+
class TaggingEngine {
|
|
4
|
+
fun autoTag(content: String): List<String> {
|
|
5
|
+
val tags = mutableListOf<String>()
|
|
6
|
+
val lowerContent = content.lowercase()
|
|
7
|
+
|
|
8
|
+
if (lowerContent.contains("work") || lowerContent.contains("meeting") || lowerContent.contains("job")) {
|
|
9
|
+
tags.add("work")
|
|
10
|
+
}
|
|
11
|
+
if (lowerContent.contains("idea") || lowerContent.contains("concept") || lowerContent.contains("think")) {
|
|
12
|
+
tags.add("idea")
|
|
13
|
+
}
|
|
14
|
+
if (lowerContent.contains("money") || lowerContent.contains("cost") || lowerContent.contains("price") || lowerContent.contains("$") || lowerContent.contains("€")) {
|
|
15
|
+
tags.add("money")
|
|
16
|
+
}
|
|
17
|
+
if (lowerContent.contains("bug") || lowerContent.contains("fix") || lowerContent.contains("error") || lowerContent.contains("crash")) {
|
|
18
|
+
tags.add("bug")
|
|
19
|
+
}
|
|
20
|
+
if (lowerContent.contains("todo") || lowerContent.contains("must") || lowerContent.contains("should")) {
|
|
21
|
+
tags.add("todo")
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return tags
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
package {{PACKAGE_NAME}}.ui
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.*
|
|
4
|
+
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
|
|
5
|
+
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
|
|
6
|
+
import androidx.compose.foundation.lazy.staggeredgrid.items
|
|
7
|
+
import androidx.compose.foundation.rememberScrollState
|
|
8
|
+
import androidx.compose.foundation.horizontalScroll
|
|
9
|
+
import androidx.compose.material.icons.Icons
|
|
10
|
+
import androidx.compose.material.icons.filled.Add
|
|
11
|
+
import androidx.compose.material.icons.filled.Delete
|
|
12
|
+
import androidx.compose.material3.*
|
|
13
|
+
import androidx.compose.runtime.*
|
|
14
|
+
import androidx.compose.ui.Alignment
|
|
15
|
+
import androidx.compose.ui.Modifier
|
|
16
|
+
import androidx.compose.ui.unit.dp
|
|
17
|
+
import androidx.compose.ui.window.Dialog
|
|
18
|
+
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
19
|
+
import {{PACKAGE_NAME}}.data.Note
|
|
20
|
+
import java.text.SimpleDateFormat
|
|
21
|
+
import java.util.*
|
|
22
|
+
|
|
23
|
+
import androidx.compose.ui.graphics.Color
|
|
24
|
+
|
|
25
|
+
@OptIn(ExperimentalMaterial3Api::class)
|
|
26
|
+
@Composable
|
|
27
|
+
fun NotesScreen(viewModel: NotesViewModel = viewModel()) {
|
|
28
|
+
val searchQuery by viewModel.searchQuery.collectAsState()
|
|
29
|
+
val searchResults by viewModel.searchResults.collectAsState()
|
|
30
|
+
|
|
31
|
+
var showAddDialog by remember { mutableStateOf(false) }
|
|
32
|
+
|
|
33
|
+
Scaffold(
|
|
34
|
+
floatingActionButton = {
|
|
35
|
+
FloatingActionButton(
|
|
36
|
+
onClick = { showAddDialog = true },
|
|
37
|
+
containerColor = MaterialTheme.colorScheme.primary
|
|
38
|
+
) {
|
|
39
|
+
Icon(Icons.Default.Add, contentDescription = "Add Note")
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
) { padding ->
|
|
43
|
+
Column(modifier = Modifier.padding(padding).fillMaxSize()) {
|
|
44
|
+
// Header
|
|
45
|
+
Text(
|
|
46
|
+
text = "✅ DESUGARING ! 🚀 HOT ",
|
|
47
|
+
style = MaterialTheme.typography.displaySmall,
|
|
48
|
+
modifier = Modifier.padding(start = 16.dp, top = 16.dp, bottom = 20.dp)
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
// Search Bar
|
|
52
|
+
OutlinedTextField(
|
|
53
|
+
value = searchQuery,
|
|
54
|
+
onValueChange = viewModel::onSearchQueryChanged,
|
|
55
|
+
placeholder = { Text("Search note or ...") },
|
|
56
|
+
modifier = Modifier
|
|
57
|
+
.fillMaxWidth()
|
|
58
|
+
.padding(horizontal = 16.dp, vertical = 8.dp),
|
|
59
|
+
shape = MaterialTheme.shapes.extraLarge,
|
|
60
|
+
colors = TextFieldDefaults.colors(
|
|
61
|
+
focusedIndicatorColor = Color.Transparent,
|
|
62
|
+
unfocusedIndicatorColor = Color.Transparent
|
|
63
|
+
)
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
LazyVerticalStaggeredGrid(
|
|
67
|
+
columns = StaggeredGridCells.Fixed(2),
|
|
68
|
+
contentPadding = PaddingValues(16.dp),
|
|
69
|
+
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
|
70
|
+
verticalItemSpacing = 12.dp
|
|
71
|
+
) {
|
|
72
|
+
items(searchResults) { note ->
|
|
73
|
+
NoteItem(note = note, onDelete = { viewModel.deleteNote(note) })
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (showAddDialog) {
|
|
79
|
+
AddNoteDialog(
|
|
80
|
+
onDismiss = { showAddDialog = false },
|
|
81
|
+
onAdd = { content ->
|
|
82
|
+
viewModel.addNote(content)
|
|
83
|
+
showAddDialog = false
|
|
84
|
+
},
|
|
85
|
+
viewModel = viewModel
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@Composable
|
|
92
|
+
fun NoteItem(note: Note, onDelete: () -> Unit) {
|
|
93
|
+
Card(
|
|
94
|
+
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
|
|
95
|
+
shape = MaterialTheme.shapes.medium
|
|
96
|
+
) {
|
|
97
|
+
Column(modifier = Modifier.padding(12.dp)) {
|
|
98
|
+
Text(
|
|
99
|
+
text = note.content,
|
|
100
|
+
style = MaterialTheme.typography.bodyLarge,
|
|
101
|
+
color = MaterialTheme.colorScheme.onSurfaceVariant
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if (note.tags.isNotEmpty()) {
|
|
105
|
+
Spacer(modifier = Modifier.height(12.dp))
|
|
106
|
+
Row(
|
|
107
|
+
modifier = Modifier.horizontalScroll(rememberScrollState()),
|
|
108
|
+
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
|
109
|
+
) {
|
|
110
|
+
note.tags.forEach { tag ->
|
|
111
|
+
AssistChip(
|
|
112
|
+
onClick = {},
|
|
113
|
+
label = { Text("#$tag", style = MaterialTheme.typography.labelSmall) },
|
|
114
|
+
modifier = Modifier.height(24.dp)
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Timestamp (optional, maybe too much clutter)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@Composable
|
|
126
|
+
fun AddNoteDialog(onDismiss: () -> Unit, onAdd: (String) -> Unit, viewModel: NotesViewModel) {
|
|
127
|
+
var content by remember { mutableStateOf("") }
|
|
128
|
+
// Live tagging
|
|
129
|
+
val suggestedTags = viewModel.getSuggestedTags(content)
|
|
130
|
+
|
|
131
|
+
AlertDialog(
|
|
132
|
+
onDismissRequest = onDismiss,
|
|
133
|
+
title = { Text("New Note") },
|
|
134
|
+
text = {
|
|
135
|
+
Column {
|
|
136
|
+
OutlinedTextField(
|
|
137
|
+
value = content,
|
|
138
|
+
onValueChange = { content = it },
|
|
139
|
+
placeholder = { Text("Type something...") },
|
|
140
|
+
minLines = 3,
|
|
141
|
+
modifier = Modifier.fillMaxWidth()
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
Spacer(modifier = Modifier.height(16.dp))
|
|
145
|
+
|
|
146
|
+
Text("Detected Tags:", style = MaterialTheme.typography.labelMedium)
|
|
147
|
+
if (suggestedTags.isEmpty()) {
|
|
148
|
+
Text("None", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.outline)
|
|
149
|
+
} else {
|
|
150
|
+
Row(
|
|
151
|
+
modifier = Modifier.horizontalScroll(rememberScrollState()),
|
|
152
|
+
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
|
153
|
+
) {
|
|
154
|
+
suggestedTags.forEach { tag ->
|
|
155
|
+
SuggestionChip(
|
|
156
|
+
onClick = {},
|
|
157
|
+
label = { Text(tag) }
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
confirmButton = {
|
|
165
|
+
Button(
|
|
166
|
+
onClick = { onAdd(content) },
|
|
167
|
+
enabled = content.isNotBlank()
|
|
168
|
+
) {
|
|
169
|
+
Text("Save")
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
dismissButton = {
|
|
173
|
+
TextButton(onClick = onDismiss) {
|
|
174
|
+
Text("Cancel")
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
// Trigger hot reload 10
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
package {{PACKAGE_NAME}}.ui
|
|
2
|
+
|
|
3
|
+
import android.app.Application
|
|
4
|
+
import androidx.lifecycle.AndroidViewModel
|
|
5
|
+
import androidx.lifecycle.viewModelScope
|
|
6
|
+
import {{PACKAGE_NAME}}.data.AppDatabase
|
|
7
|
+
import {{PACKAGE_NAME}}.data.Note
|
|
8
|
+
import {{PACKAGE_NAME}}.logic.TaggingEngine
|
|
9
|
+
import kotlinx.coroutines.flow.MutableStateFlow
|
|
10
|
+
import kotlinx.coroutines.flow.SharingStarted
|
|
11
|
+
import kotlinx.coroutines.flow.StateFlow
|
|
12
|
+
import kotlinx.coroutines.flow.asStateFlow
|
|
13
|
+
import kotlinx.coroutines.flow.combine
|
|
14
|
+
import kotlinx.coroutines.flow.stateIn
|
|
15
|
+
import kotlinx.coroutines.launch
|
|
16
|
+
|
|
17
|
+
class NotesViewModel(application: Application) : AndroidViewModel(application) {
|
|
18
|
+
private val dao = AppDatabase.getDatabase(application).noteDao()
|
|
19
|
+
private val taggingEngine = TaggingEngine()
|
|
20
|
+
|
|
21
|
+
// For search
|
|
22
|
+
private val _searchQuery = MutableStateFlow("")
|
|
23
|
+
val searchQuery = _searchQuery.asStateFlow()
|
|
24
|
+
|
|
25
|
+
// All notes from DB
|
|
26
|
+
val notes = dao.getAllNotes()
|
|
27
|
+
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
|
|
28
|
+
|
|
29
|
+
// Search results: Use combine to filter locally for responsiveness, or use DAO search
|
|
30
|
+
val searchResults = combine(notes, _searchQuery) { list, query ->
|
|
31
|
+
if (query.isBlank()) list
|
|
32
|
+
else list.filter { it.content.contains(query, ignoreCase = true) || it.tags.any { tag -> tag.contains(query, ignoreCase = true) } }
|
|
33
|
+
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
|
|
34
|
+
|
|
35
|
+
fun onSearchQueryChanged(query: String) {
|
|
36
|
+
_searchQuery.value = query
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fun addNote(content: String) {
|
|
40
|
+
if (content.isBlank()) return
|
|
41
|
+
val tags = taggingEngine.autoTag(content)
|
|
42
|
+
val note = Note(content = content, tags = tags)
|
|
43
|
+
viewModelScope.launch {
|
|
44
|
+
dao.insertNote(note)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fun deleteNote(note: Note) {
|
|
49
|
+
viewModelScope.launch {
|
|
50
|
+
dao.deleteNote(note)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Trigger full build for client update 7 (Fix Duplicate Renderers)
|
|
55
|
+
fun getSuggestedTags(content: String): List<String> {
|
|
56
|
+
return taggingEngine.autoTag(content)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
package {{PACKAGE_NAME}}.ui
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.Column
|
|
4
|
+
import androidx.compose.material3.Text
|
|
5
|
+
import androidx.compose.runtime.Composable
|
|
6
|
+
|
|
7
|
+
@Composable
|
|
8
|
+
fun TestScreen() {
|
|
9
|
+
Column {
|
|
10
|
+
Text("Hello Test 12 - HOT RELOAD TEST")
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<resources>
|
|
3
|
+
<color name="purple_200">#FFBB86FC</color>
|
|
4
|
+
<color name="purple_500">#FF6200EE</color>
|
|
5
|
+
<color name="purple_700">#FF3700B3</color>
|
|
6
|
+
<color name="teal_200">#FF03DAC5</color>
|
|
7
|
+
<color name="teal_700">#FF018786</color>
|
|
8
|
+
<color name="black">#FF000000</color>
|
|
9
|
+
<color name="white">#FFFFFFFF</color>
|
|
10
|
+
</resources>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<resources>
|
|
3
|
+
<style name="Theme.{{THEME_NAME}}" parent="Theme.AppCompat.Light.NoActionBar">
|
|
4
|
+
<!-- Customize your theme here -->
|
|
5
|
+
<item name="colorPrimary">@color/purple_500</item>
|
|
6
|
+
<item name="colorPrimaryDark">@color/purple_700</item>
|
|
7
|
+
<item name="colorAccent">@color/teal_200</item>
|
|
8
|
+
</style>
|
|
9
|
+
</resources>
|