diff --git a/.github/workflows/android-release.yml b/.github/workflows/android-release.yml index 18c5a7e8..27a16a76 100644 --- a/.github/workflows/android-release.yml +++ b/.github/workflows/android-release.yml @@ -64,17 +64,13 @@ jobs: with: path: | ~/.cargo/bin/cargo-tauri - ~/.cargo/bin/tauri-typegen - key: ${{ runner.os }}-tauri-cli-2.9.5-typegen-0.3.2 + key: ${{ runner.os }}-tauri-cli-2.9.5 - - name: Install Tauri CLI and typegen + - name: Install Tauri CLI run: | if ! command -v cargo-tauri &> /dev/null; then cargo install tauri-cli --version "=2.9.5" --locked fi - if ! command -v tauri-typegen &> /dev/null; then - cargo install tauri-typegen --version "=0.3.2" --locked - fi - name: Determine release strategy id: release_strategy @@ -117,38 +113,26 @@ jobs: run: | echo "$KEYSTORE_BASE64" | base64 -d > /tmp/upload-keystore.jks - - name: Initialize Tauri Android - working-directory: src-tauri + # gen/android is committed (Gradle skeleton + signing-aware build.gradle.kts), + # so there is no `cargo tauri android init` and no template-application script. + # The Rust .so, tauri.properties, assets/tauri.conf.json etc. are regenerated + # by the build itself; release signing reads the env vars set on the build step. + # Launcher icons are committed under gen/android too — run `cargo tauri icon + # icons/icon.png` locally and commit when the source icon changes. + - name: Configure NDK path + # local.properties is gitignored (per-runner NDK path), so write it fresh. + working-directory: src-tauri/gen/android + run: echo "ndk.dir=${{ steps.setup-ndk.outputs.ndk-path }}" > local.properties + + - name: Build Universal APK env: ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} - run: cargo tauri android init - - - name: Generate Android icons - working-directory: src-tauri - run: cargo tauri icon icons/icon.png - - - name: Apply Android templates and configuration - working-directory: src-tauri - env: + NDK_VERSION: ${{ steps.setup-ndk.outputs.ndk-full-version }} KEYSTORE_FILE: /tmp/upload-keystore.jks KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} - NDK_PATH: ${{ steps.setup-ndk.outputs.ndk-path }} - NDK_VERSION: ${{ steps.setup-ndk.outputs.ndk-full-version }} - run: | - chmod +x ./android-templates/setup-android.sh - ./android-templates/setup-android.sh - - - name: Invoke tauri-typegen - working-directory: src-tauri - run: cargo tauri-typegen generate - - - name: Build Universal APK - env: - ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} - NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} run: cargo tauri android build --apk true - name: Rename APK with version diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore index 46b6ed8e..7c1af5da 100644 --- a/src-tauri/.gitignore +++ b/src-tauri/.gitignore @@ -5,4 +5,8 @@ node_modules/ -gen/ +# Track the committed Android project skeleton (gen/android); its nested +# .gitignores still exclude build artifacts + Tauri-regenerated files. Other +# gen/ subdirs (schemas, apple) stay ignored. +gen/* +!gen/android diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 7f3a6d40..1e98385e 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -6201,6 +6201,13 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "xtask" +version = "0.0.0" +dependencies = [ + "tauri-typegen", +] + [[package]] name = "yoke" version = "0.8.2" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 83153e93..c15a0387 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -8,7 +8,12 @@ repository = "https://github.com/thwbh/librefit" edition = "2021" rust-version = "1.84.0" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[workspace] +members = [".", "xtask"] +default-members = ["."] + +[workspace.dependencies] +tauri-typegen = "0.5.1" [lib] name = "librefit_lib" @@ -16,7 +21,7 @@ crate-type = ["staticlib", "cdylib", "rlib"] [build-dependencies] tauri-build = { version = "2.0.5", features = [] } -tauri-typegen = "0.5.1" +tauri-typegen = { workspace = true } [dependencies] serde_json = "1.0.137" diff --git a/src-tauri/android-templates/README.md b/src-tauri/android-templates/README.md deleted file mode 100644 index 34f2b7c6..00000000 --- a/src-tauri/android-templates/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# Android Templates - -This directory contains template files for Android-specific configurations that need to be applied after Tauri generates the Android project files. - -## Purpose - -Tauri's `gen/android` directory contains generated files that get recreated when you run `tauri android init` or similar commands. Any manual changes to these files would be lost. This templates directory preserves those custom changes. - -## Files - -### keystore.properties.template - -Template for Android app signing configuration. Contains placeholders for environment variables. - -**Usage:** - -- Local development: Copy to `gen/android/keystore.properties` and fill in your values -- CI/CD: The setup script will replace placeholders with environment variables - -### activity_main.xml - -Custom activity layout with bugfixes applied. - -**Usage:** - -- Copied to `gen/android/app/src/main/res/layout/activity_main.xml` after Tauri generation - -### AndroidManifest.xml - -Custom Android manifest with required permissions for file access. - -**Permissions included:** - -- `READ_EXTERNAL_STORAGE` - For importing CSV files (Android 12 and below) -- `WRITE_EXTERNAL_STORAGE` - For exporting database and CSV files (Android 12 and below) - -**Usage:** - -- Copied to `gen/android/app/src/main/AndroidManifest.xml` after Tauri generation - -## Scripts - -### setup-android.sh - -Bash script that: - -1. Applies template files to the generated Android project -2. Replaces environment variable placeholders -3. Ensures the Android project is ready for building - -## CI/CD Integration - -In your GitHub Actions workflow, run `./android-templates/setup-android.sh` after Tauri Android initialization to apply these templates. - -Example: - -```yaml -- name: Initialize Tauri Android - run: cd src-tauri && cargo tauri android init - -- name: Apply Android templates - run: cd src-tauri && ./android-templates/setup-android.sh - env: - KEYSTORE_FILE: ${{ secrets.ANDROID_KEYSTORE_FILE }} - KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} - KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} - KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} -``` - -## Adding New Templates - -To add a new template: - -1. Create the template file in this directory -2. Update `setup-android.sh` to copy it to the appropriate location -3. Document it in this README diff --git a/src-tauri/android-templates/keystore.properties.template b/src-tauri/android-templates/keystore.properties.template deleted file mode 100644 index 5b6c3d97..00000000 --- a/src-tauri/android-templates/keystore.properties.template +++ /dev/null @@ -1,10 +0,0 @@ -# Android Keystore Configuration -# This file is used to configure the signing keystore for Android builds -# -# For local development: Copy this to gen/android/keystore.properties and fill in your values -# For CI/CD: These values should be set via environment variables or secrets - -storeFile=${KEYSTORE_FILE} -storePassword=${KEYSTORE_PASSWORD} -keyAlias=${KEY_ALIAS} -keyPassword=${KEY_PASSWORD} diff --git a/src-tauri/android-templates/setup-android.sh b/src-tauri/android-templates/setup-android.sh deleted file mode 100755 index 795bf9aa..00000000 --- a/src-tauri/android-templates/setup-android.sh +++ /dev/null @@ -1,142 +0,0 @@ -#!/bin/bash -set -e - -# Android Template Setup Script -# This script applies custom configuration templates to the generated Android project -# Run this after 'cargo tauri android init' or when Android files are regenerated - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ANDROID_DIR="$SCRIPT_DIR/../gen/android" - -echo "🤖 Setting up Android project with custom templates..." - -# Check if Android project exists -if [ ! -d "$ANDROID_DIR" ]; then - echo "❌ Error: Android directory not found at $ANDROID_DIR" - echo " Run 'cargo tauri android init' first" - exit 1 -fi - -# 1. Apply custom activity_main.xml -if [ -f "$SCRIPT_DIR/activity_main.xml" ]; then - echo "📝 Applying custom activity_main.xml..." - cp "$SCRIPT_DIR/activity_main.xml" "$ANDROID_DIR/app/src/main/res/layout/activity_main.xml" - echo " ✅ activity_main.xml applied" -else - echo " ⚠️ activity_main.xml template not found" -fi - -# 2. Set up keystore.properties -echo "🔑 Setting up keystore.properties..." - -# Check if we're in CI/CD (environment variables set) or local development -if [ -n "$KEYSTORE_FILE" ] && [ -n "$KEYSTORE_PASSWORD" ] && [ -n "$KEY_ALIAS" ] && [ -n "$KEY_PASSWORD" ]; then - echo " Using environment variables for keystore configuration" - - # Always create keystore.properties from environment variables - cat > "$ANDROID_DIR/keystore.properties" <> "$LOCAL_PROPS" - echo " ✅ NDK path set to: $NDK_PATH" - - # Also set ndkVersion in build.gradle.kts if NDK_VERSION is provided - if [ -n "$NDK_VERSION" ]; then - echo "🔧 Setting ndkVersion in build.gradle.kts..." - BUILD_GRADLE="$ANDROID_DIR/app/build.gradle.kts" - - # Check if ndkVersion line already exists - if grep -q "ndkVersion" "$BUILD_GRADLE"; then - # Replace existing ndkVersion - sed -i.bak "s/ndkVersion = \".*\"/ndkVersion = \"$NDK_VERSION\"/" "$BUILD_GRADLE" && rm -f "$BUILD_GRADLE.bak" - else - # Add ndkVersion after compileSdk line - sed -i.bak "/compileSdk = /a\\ - ndkVersion = \"$NDK_VERSION\"" "$BUILD_GRADLE" && rm -f "$BUILD_GRADLE.bak" - fi - echo " ✅ NDK version set to: $NDK_VERSION" - fi -else - echo " ⚠️ NDK_PATH environment variable not set, skipping NDK configuration" -fi - -echo "" -echo "✨ Android setup complete!" -echo "" -echo "Next steps:" -echo " 1. If local development: Fill in keystore.properties with your signing credentials" -echo " 2. Build your app: cargo tauri android build" -echo "" diff --git a/src-tauri/gen/android/.editorconfig b/src-tauri/gen/android/.editorconfig new file mode 100644 index 00000000..ebe51d3b --- /dev/null +++ b/src-tauri/gen/android/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false \ No newline at end of file diff --git a/src-tauri/gen/android/.gitignore b/src-tauri/gen/android/.gitignore new file mode 100644 index 00000000..b2482031 --- /dev/null +++ b/src-tauri/gen/android/.gitignore @@ -0,0 +1,19 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +build +/captures +.externalNativeBuild +.cxx +local.properties +key.properties + +/.tauri +/tauri.settings.gradle \ No newline at end of file diff --git a/src-tauri/gen/android/app/.gitignore b/src-tauri/gen/android/app/.gitignore new file mode 100644 index 00000000..0cee350d --- /dev/null +++ b/src-tauri/gen/android/app/.gitignore @@ -0,0 +1,6 @@ +/src/main/java/io/tohowabohu/librefit/generated +/src/main/jniLibs/**/*.so +/src/main/assets/tauri.conf.json +/tauri.build.gradle.kts +/proguard-tauri.pro +/tauri.properties \ No newline at end of file diff --git a/src-tauri/android-templates/build.gradle.kts b/src-tauri/gen/android/app/build.gradle.kts similarity index 74% rename from src-tauri/android-templates/build.gradle.kts rename to src-tauri/gen/android/app/build.gradle.kts index 2cb54860..15a09801 100644 --- a/src-tauri/android-templates/build.gradle.kts +++ b/src-tauri/gen/android/app/build.gradle.kts @@ -13,24 +13,24 @@ val tauriProperties = Properties().apply { } } -// Load keystore properties -val keystoreProperties = Properties().apply { - val propFile = file("../keystore.properties") - if (propFile.exists()) { - propFile.inputStream().use { load(it) } - } -} - android { compileSdk = 36 namespace = "io.tohowabohu.librefit" + // NDK version is supplied by CI (setup-ndk output). When unset (e.g. local + // builds) Gradle falls back to the NDK resolved via ndk.dir / NDK_HOME. + System.getenv("NDK_VERSION")?.let { ndkVersion = it } + signingConfigs { create("release") { - keyAlias = keystoreProperties.getProperty("keyAlias") - keyPassword = keystoreProperties.getProperty("keyPassword") - storeFile = file(keystoreProperties.getProperty("storeFile")) - storePassword = keystoreProperties.getProperty("storePassword") + // Release signing credentials come straight from the environment + // (CI secrets) — no keystore.properties file on disk to manage. + System.getenv("KEYSTORE_FILE")?.let { + storeFile = file(it) + storePassword = System.getenv("KEYSTORE_PASSWORD") + keyAlias = System.getenv("KEY_ALIAS") + keyPassword = System.getenv("KEY_PASSWORD") + } } } @@ -48,7 +48,8 @@ android { isDebuggable = true isJniDebuggable = true isMinifyEnabled = false - packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so") + packaging { + jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so") jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so") jniLibs.keepDebugSymbols.add("*/x86/*.so") jniLibs.keepDebugSymbols.add("*/x86_64/*.so") diff --git a/src-tauri/gen/android/app/proguard-rules.pro b/src-tauri/gen/android/app/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/src-tauri/gen/android/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/src-tauri/android-templates/AndroidManifest.xml b/src-tauri/gen/android/app/src/main/AndroidManifest.xml similarity index 100% rename from src-tauri/android-templates/AndroidManifest.xml rename to src-tauri/gen/android/app/src/main/AndroidManifest.xml diff --git a/src-tauri/android-templates/MainActivity.kt b/src-tauri/gen/android/app/src/main/java/io/tohowabohu/librefit/MainActivity.kt similarity index 100% rename from src-tauri/android-templates/MainActivity.kt rename to src-tauri/gen/android/app/src/main/java/io/tohowabohu/librefit/MainActivity.kt diff --git a/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 00000000..2b068d11 --- /dev/null +++ b/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml b/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..07d5da9c --- /dev/null +++ b/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-tauri/android-templates/activity_main.xml b/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml similarity index 100% rename from src-tauri/android-templates/activity_main.xml rename to src-tauri/gen/android/app/src/main/res/layout/activity_main.xml diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/src-tauri/gen/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..2ffbf24b --- /dev/null +++ b/src-tauri/gen/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..002e8b36 Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..838ca371 Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000..3e705a1b Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..cb096dfe Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..96f69b83 Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000..58294b06 Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..68205efc Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..41c33659 Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000..e2742640 Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..ed1406eb Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..7962b365 Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..3ca34fdf Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..8718cfd7 Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..b3d6402f Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..8015f87d Binary files /dev/null and b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/src-tauri/android-templates/themes.xml b/src-tauri/gen/android/app/src/main/res/values-night/themes.xml similarity index 100% rename from src-tauri/android-templates/themes.xml rename to src-tauri/gen/android/app/src/main/res/values-night/themes.xml diff --git a/src-tauri/gen/android/app/src/main/res/values/colors.xml b/src-tauri/gen/android/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..b5cfac42 --- /dev/null +++ b/src-tauri/gen/android/app/src/main/res/values/colors.xml @@ -0,0 +1,12 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + #FF1A7A8A + #FFF9F8F6 + diff --git a/src-tauri/gen/android/app/src/main/res/values/ic_launcher_background.xml b/src-tauri/gen/android/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 00000000..ea9c223a --- /dev/null +++ b/src-tauri/gen/android/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #fff + \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/values/strings.xml b/src-tauri/gen/android/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..768a8e51 --- /dev/null +++ b/src-tauri/gen/android/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + librefit + librefit + \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/values/themes.xml b/src-tauri/gen/android/app/src/main/res/values/themes.xml new file mode 100644 index 00000000..684e0811 --- /dev/null +++ b/src-tauri/gen/android/app/src/main/res/values/themes.xml @@ -0,0 +1,6 @@ + + + diff --git a/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml b/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml new file mode 100644 index 00000000..782d63b9 --- /dev/null +++ b/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src-tauri/gen/android/build.gradle.kts b/src-tauri/gen/android/build.gradle.kts new file mode 100644 index 00000000..607240bc --- /dev/null +++ b/src-tauri/gen/android/build.gradle.kts @@ -0,0 +1,22 @@ +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath("com.android.tools.build:gradle:8.11.0") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25") + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +tasks.register("clean").configure { + delete("build") +} + diff --git a/src-tauri/gen/android/buildSrc/build.gradle.kts b/src-tauri/gen/android/buildSrc/build.gradle.kts new file mode 100644 index 00000000..5c55bba7 --- /dev/null +++ b/src-tauri/gen/android/buildSrc/build.gradle.kts @@ -0,0 +1,23 @@ +plugins { + `kotlin-dsl` +} + +gradlePlugin { + plugins { + create("pluginsForCoolKids") { + id = "rust" + implementationClass = "RustPlugin" + } + } +} + +repositories { + google() + mavenCentral() +} + +dependencies { + compileOnly(gradleApi()) + implementation("com.android.tools.build:gradle:8.11.0") +} + diff --git a/src-tauri/gen/android/buildSrc/src/main/java/io/tohowabohu/librefit/kotlin/BuildTask.kt b/src-tauri/gen/android/buildSrc/src/main/java/io/tohowabohu/librefit/kotlin/BuildTask.kt new file mode 100644 index 00000000..a1b43c07 --- /dev/null +++ b/src-tauri/gen/android/buildSrc/src/main/java/io/tohowabohu/librefit/kotlin/BuildTask.kt @@ -0,0 +1,68 @@ +import java.io.File +import org.apache.tools.ant.taskdefs.condition.Os +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.logging.LogLevel +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.TaskAction + +open class BuildTask : DefaultTask() { + @Input + var rootDirRel: String? = null + @Input + var target: String? = null + @Input + var release: Boolean? = null + + @TaskAction + fun assemble() { + val executable = """cargo"""; + try { + runTauriCli(executable) + } catch (e: Exception) { + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + // Try different Windows-specific extensions + val fallbacks = listOf( + "$executable.exe", + "$executable.cmd", + "$executable.bat", + ) + + var lastException: Exception = e + for (fallback in fallbacks) { + try { + runTauriCli(fallback) + return + } catch (fallbackException: Exception) { + lastException = fallbackException + } + } + throw lastException + } else { + throw e; + } + } + } + + fun runTauriCli(executable: String) { + val rootDirRel = rootDirRel ?: throw GradleException("rootDirRel cannot be null") + val target = target ?: throw GradleException("target cannot be null") + val release = release ?: throw GradleException("release cannot be null") + val args = listOf("tauri", "android", "android-studio-script"); + + project.exec { + workingDir(File(project.projectDir, rootDirRel)) + executable(executable) + args(args) + if (project.logger.isEnabled(LogLevel.DEBUG)) { + args("-vv") + } else if (project.logger.isEnabled(LogLevel.INFO)) { + args("-v") + } + if (release) { + args("--release") + } + args(listOf("--target", target)) + }.assertNormalExitValue() + } +} \ No newline at end of file diff --git a/src-tauri/gen/android/buildSrc/src/main/java/io/tohowabohu/librefit/kotlin/RustPlugin.kt b/src-tauri/gen/android/buildSrc/src/main/java/io/tohowabohu/librefit/kotlin/RustPlugin.kt new file mode 100644 index 00000000..4aa7fcaf --- /dev/null +++ b/src-tauri/gen/android/buildSrc/src/main/java/io/tohowabohu/librefit/kotlin/RustPlugin.kt @@ -0,0 +1,85 @@ +import com.android.build.api.dsl.ApplicationExtension +import org.gradle.api.DefaultTask +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.get + +const val TASK_GROUP = "rust" + +open class Config { + lateinit var rootDirRel: String +} + +open class RustPlugin : Plugin { + private lateinit var config: Config + + override fun apply(project: Project) = with(project) { + config = extensions.create("rust", Config::class.java) + + val defaultAbiList = listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64"); + val abiList = (findProperty("abiList") as? String)?.split(',') ?: defaultAbiList + + val defaultArchList = listOf("arm64", "arm", "x86", "x86_64"); + val archList = (findProperty("archList") as? String)?.split(',') ?: defaultArchList + + val targetsList = (findProperty("targetList") as? String)?.split(',') ?: listOf("aarch64", "armv7", "i686", "x86_64") + + extensions.configure { + @Suppress("UnstableApiUsage") + flavorDimensions.add("abi") + productFlavors { + create("universal") { + dimension = "abi" + ndk { + abiFilters += abiList + } + } + defaultArchList.forEachIndexed { index, arch -> + create(arch) { + dimension = "abi" + ndk { + abiFilters.add(defaultAbiList[index]) + } + } + } + } + } + + afterEvaluate { + for (profile in listOf("debug", "release")) { + val profileCapitalized = profile.replaceFirstChar { it.uppercase() } + val buildTask = tasks.maybeCreate( + "rustBuildUniversal$profileCapitalized", + DefaultTask::class.java + ).apply { + group = TASK_GROUP + description = "Build dynamic library in $profile mode for all targets" + } + + tasks["mergeUniversal${profileCapitalized}JniLibFolders"].dependsOn(buildTask) + + for (targetPair in targetsList.withIndex()) { + val targetName = targetPair.value + val targetArch = archList[targetPair.index] + val targetArchCapitalized = targetArch.replaceFirstChar { it.uppercase() } + val targetBuildTask = project.tasks.maybeCreate( + "rustBuild$targetArchCapitalized$profileCapitalized", + BuildTask::class.java + ).apply { + group = TASK_GROUP + description = "Build dynamic library in $profile mode for $targetArch" + rootDirRel = config.rootDirRel + target = targetName + release = profile == "release" + } + + buildTask.dependsOn(targetBuildTask) + tasks["merge$targetArchCapitalized${profileCapitalized}JniLibFolders"].dependsOn( + targetBuildTask + ) + } + } + } + } +} \ No newline at end of file diff --git a/src-tauri/gen/android/gradle.properties b/src-tauri/gen/android/gradle.properties new file mode 100644 index 00000000..2a7ec695 --- /dev/null +++ b/src-tauri/gen/android/gradle.properties @@ -0,0 +1,24 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true +android.nonFinalResIds=false \ No newline at end of file diff --git a/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar b/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..e708b1c0 Binary files /dev/null and b/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties b/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..c5f9a53c --- /dev/null +++ b/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue May 10 19:22:52 CST 2022 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/src-tauri/gen/android/gradlew b/src-tauri/gen/android/gradlew new file mode 100755 index 00000000..4f906e0c --- /dev/null +++ b/src-tauri/gen/android/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/src-tauri/gen/android/gradlew.bat b/src-tauri/gen/android/gradlew.bat new file mode 100644 index 00000000..107acd32 --- /dev/null +++ b/src-tauri/gen/android/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src-tauri/gen/android/settings.gradle b/src-tauri/gen/android/settings.gradle new file mode 100644 index 00000000..39391166 --- /dev/null +++ b/src-tauri/gen/android/settings.gradle @@ -0,0 +1,3 @@ +include ':app' + +apply from: 'tauri.settings.gradle' diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 7be191ed..30f62442 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -15,7 +15,7 @@ ] }, "build": { - "beforeBuildCommand": "cargo tauri-typegen generate && npm run build", + "beforeBuildCommand": "cargo run --manifest-path src-tauri/Cargo.toml -p xtask -- generate && npm run build", "beforeDevCommand": "npm run dev", "devUrl": "http://localhost:1420", "frontendDist": "../build" diff --git a/src-tauri/xtask/Cargo.toml b/src-tauri/xtask/Cargo.toml new file mode 100644 index 00000000..caca5a95 --- /dev/null +++ b/src-tauri/xtask/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "xtask" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +tauri-typegen = { workspace = true } diff --git a/src-tauri/xtask/src/main.rs b/src-tauri/xtask/src/main.rs new file mode 100644 index 00000000..da1be0a8 --- /dev/null +++ b/src-tauri/xtask/src/main.rs @@ -0,0 +1,39 @@ +//! Build automation: generate TypeScript bindings from the Tauri commands. +//! +//! Run from the workspace (`src-tauri`): +//! +//! ```text +//! cargo run -p xtask -- generate +//! ``` +//! +//! This invokes tauri-typegen through the Cargo dependency graph (the version pinned +//! in `[workspace.dependencies]`), so no separate `cargo install` is needed and there +//! is a single source of truth for the typegen version. +//! +//! NOTE: this scaffold is not yet wired into `beforeBuildCommand` / `build.rs` — those +//! stay as-is until the test pipeline is checked. + +use std::path::Path; + +use tauri_typegen::{generate_from_config, GenerateConfig}; + +fn main() { + // This crate lives at `src-tauri/xtask`, so its parent is `src-tauri`. Run from there + // so the relative `projectPath`/`outputPath` in tauri.conf.json resolve exactly the + // way the `cargo tauri-typegen generate` CLI resolves them (it runs from src-tauri). + let src_tauri = Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .expect("xtask must live under src-tauri/"); + std::env::set_current_dir(src_tauri).expect("failed to chdir to src-tauri"); + + // Single source of config: read the existing `plugins.typegen` block from tauri.conf.json. + let config = GenerateConfig::from_tauri_config("tauri.conf.json") + .expect("failed to read tauri.conf.json") + .expect("no `plugins.typegen` configuration found in tauri.conf.json"); + + generate_from_config(&config).expect("tauri-typegen generation failed"); + eprintln!( + "tauri-typegen: bindings generated into {}", + config.output_path + ); +}