From c31e804b79f94f5739ac5482f50f58f1cb58cac3 Mon Sep 17 00:00:00 2001 From: Shellishack <40737228+Shellishack@users.noreply.github.com> Date: Thu, 6 Nov 2025 04:22:50 +0800 Subject: [PATCH 1/2] react-api: add rebounce option to save file --- .changeset/beige-pumas-run.md | 6 +++ .changeset/pre.json | 1 + npm-packages/react-api/CHANGELOG.md | 8 ++++ npm-packages/react-api/package.json | 7 +++- .../react-api/src/hooks/editor/use-file.ts | 37 +++++++++++++------ npm-packages/shared-utils/CHANGELOG.md | 6 +++ npm-packages/shared-utils/package.json | 2 +- package-lock.json | 9 +++-- 8 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 .changeset/beige-pumas-run.md diff --git a/.changeset/beige-pumas-run.md b/.changeset/beige-pumas-run.md new file mode 100644 index 0000000..a13d585 --- /dev/null +++ b/.changeset/beige-pumas-run.md @@ -0,0 +1,6 @@ +--- +"@pulse-editor/shared-utils": patch +"@pulse-editor/react-api": patch +--- + +Add rebounce option for useFile hook's saveFile diff --git a/.changeset/pre.json b/.changeset/pre.json index 37845fa..321e35b 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -12,6 +12,7 @@ "afraid-moments-punch", "angry-llamas-smash", "beige-pandas-rhyme", + "beige-pumas-run", "bumpy-parents-pull", "calm-rivers-march", "chatty-trains-beam", diff --git a/npm-packages/react-api/CHANGELOG.md b/npm-packages/react-api/CHANGELOG.md index be5a27f..704f74c 100644 --- a/npm-packages/react-api/CHANGELOG.md +++ b/npm-packages/react-api/CHANGELOG.md @@ -1,5 +1,13 @@ # @pulse-editor/react-api +## 0.1.1-beta.57 + +### Patch Changes + +- Add rebounce option for useFile hook's saveFile +- Updated dependencies + - @pulse-editor/shared-utils@0.1.1-beta.57 + ## 0.1.1-beta.56 ### Patch Changes diff --git a/npm-packages/react-api/package.json b/npm-packages/react-api/package.json index 4f8d4c7..3852579 100644 --- a/npm-packages/react-api/package.json +++ b/npm-packages/react-api/package.json @@ -1,6 +1,6 @@ { "name": "@pulse-editor/react-api", - "version": "0.1.1-beta.56", + "version": "0.1.1-beta.57", "main": "dist/main.js", "files": [ "dist" @@ -37,8 +37,11 @@ "typescript-eslint": "^8.30.1" }, "peerDependencies": { - "@pulse-editor/shared-utils": "0.1.1-beta.56", + "@pulse-editor/shared-utils": "0.1.1-beta.57", "react": "^19.0.0", "react-dom": "^19.0.0" + }, + "dependencies": { + "use-debounce": "^10.0.6" } } diff --git a/npm-packages/react-api/src/hooks/editor/use-file.ts b/npm-packages/react-api/src/hooks/editor/use-file.ts index 66d0f6e..73c141d 100644 --- a/npm-packages/react-api/src/hooks/editor/use-file.ts +++ b/npm-packages/react-api/src/hooks/editor/use-file.ts @@ -1,8 +1,15 @@ import { IMCMessage, IMCMessageTypeEnum } from "@pulse-editor/shared-utils"; import { useCallback, useEffect, useState } from "react"; +import { useDebouncedCallback } from "use-debounce"; import useIMC from "../imc/use-imc"; -export default function useFile(uri: string | undefined) { +/** + * + * @param uri The file URI to read/write + * @param debounce Debounce time in ms for write operations + * @returns + */ +export default function useFile(uri: string | undefined, debounce = 0) { const [file, setFile] = useState(undefined); const receiverHandlerMap = new Map< @@ -20,26 +27,32 @@ export default function useFile(uri: string | undefined) { const { imc, isReady } = useIMC(receiverHandlerMap, "file"); + const sendFileDebounced = useDebouncedCallback( + async (newFile: File) => { + if (!isReady || !uri) return; + await imc?.sendMessage(IMCMessageTypeEnum.PlatformWriteFile, { + uri, + file: newFile, + }); + }, + debounce, + { maxWait: debounce * 2 }, + ); + const saveFile = useCallback( - (fileContent: string) => { - if (!uri) return; - else if (!file) return; + async (fileContent: string) => { + if (!uri || !file) return; - // Update file content const newFile = new File([fileContent], file.name, { type: file.type, lastModified: Date.now(), }); setFile(newFile); - if (isReady && uri) { - imc?.sendMessage(IMCMessageTypeEnum.PlatformWriteFile, { - uri, - file: newFile, - }); - } + // ✅ This now waits until the debounced write actually finishes + await sendFileDebounced(newFile); }, - [uri, file, isReady], + [file, uri, sendFileDebounced], ); // Read file when uri changes diff --git a/npm-packages/shared-utils/CHANGELOG.md b/npm-packages/shared-utils/CHANGELOG.md index 431f4b3..b2b0c96 100644 --- a/npm-packages/shared-utils/CHANGELOG.md +++ b/npm-packages/shared-utils/CHANGELOG.md @@ -1,5 +1,11 @@ # @pulse-editor/shared-utils +## 0.1.1-beta.57 + +### Patch Changes + +- Add rebounce option for useFile hook's saveFile + ## 0.1.1-beta.56 ### Patch Changes diff --git a/npm-packages/shared-utils/package.json b/npm-packages/shared-utils/package.json index 07e828c..1da495f 100644 --- a/npm-packages/shared-utils/package.json +++ b/npm-packages/shared-utils/package.json @@ -1,6 +1,6 @@ { "name": "@pulse-editor/shared-utils", - "version": "0.1.1-beta.56", + "version": "0.1.1-beta.57", "main": "dist/main.js", "files": [ "dist" diff --git a/package-lock.json b/package-lock.json index 6f614b6..4d96ebf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25633,7 +25633,10 @@ }, "npm-packages/react-api": { "name": "@pulse-editor/react-api", - "version": "0.1.1-beta.55", + "version": "0.1.1-beta.56", + "dependencies": { + "use-debounce": "^10.0.6" + }, "devDependencies": { "@babel/core": "^7.26.10", "@babel/preset-env": "^7.26.9", @@ -25656,7 +25659,7 @@ "typescript-eslint": "^8.30.1" }, "peerDependencies": { - "@pulse-editor/shared-utils": "0.1.1-beta.55", + "@pulse-editor/shared-utils": "0.1.1-beta.56", "react": "^19.0.0", "react-dom": "^19.0.0" } @@ -25862,7 +25865,7 @@ }, "npm-packages/shared-utils": { "name": "@pulse-editor/shared-utils", - "version": "0.1.1-beta.55", + "version": "0.1.1-beta.56", "devDependencies": { "@babel/core": "^7.26.10", "@babel/preset-env": "^7.26.9", From f63270c3fa74529d06a5c4d390a22962e42b25c7 Mon Sep 17 00:00:00 2001 From: Shellishack <40737228+Shellishack@users.noreply.github.com> Date: Thu, 6 Nov 2025 06:03:45 +0800 Subject: [PATCH 2/2] Add android publishing github action --- .github/workflows/publish-android.yml | 92 +++++++++++++++++++++++++++ mobile/README.md | 6 +- mobile/android/app/build.gradle | 2 +- 3 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/publish-android.yml diff --git a/.github/workflows/publish-android.yml b/.github/workflows/publish-android.yml new file mode 100644 index 0000000..88836fd --- /dev/null +++ b/.github/workflows/publish-android.yml @@ -0,0 +1,92 @@ +name: Publish Android + +env: + ANDROID_SDK_VERSION: "36.1.0" + +on: + push: + tags: + - "v*.*.*" + +permissions: + contents: read + +jobs: + build: + strategy: + matrix: + target: [android] + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v3 + with: + java-version: "21" + distribution: "temurin" + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Install Android SDK build tools + run: | + sdkmanager "build-tools;${{env.ANDROID_SDK_VERSION}}" + echo "$ANDROID_SDK_ROOT/build-tools/${{env.ANDROID_SDK_VERSION}}" >> $GITHUB_PATH + + - name: Get Keystore + run: | + mkdir ~/.keystore + echo ${{ secrets.ANDROID_KEYSTORE }} | base64 --decode > ~/.keystore/pulse-editor.keystore + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install shared-utils dependencies + run: npm install --workspace=npm-packages/shared-utils + + - name: Build shared-utils + run: npm run shared-utils-build + + - name: Install web dependencies + run: npm install --workspace=web + + - name: Save public env variables into .env file + run: | + echo NEXT_PUBLIC_BACKEND_URL=$NEXT_PUBLIC_BACKEND_URL >> ./web/.env + echo NEXT_PUBLIC_CDN_URL=$NEXT_PUBLIC_CDN_URL >> ./web/.env + echo NEXT_PUBLIC_STORAGE_CONTAINER=$NEXT_PUBLIC_STORAGE_CONTAINER >> ./web/.env + env: + NEXT_PUBLIC_BACKEND_URL: ${{ vars.NEXT_PUBLIC_BACKEND_URL }} + NEXT_PUBLIC_CDN_URL: ${{ vars.NEXT_PUBLIC_CDN_URL }} + NEXT_PUBLIC_STORAGE_CONTAINER: ${{ vars.NEXT_PUBLIC_STORAGE_CONTAINER }} + + - name: Build Web App + run: npm run web-build + + - name: Install mobile dependencies + run: npm install --workspace=mobile + + - name: Change Android Project Permission + run: chmod +x mobile/android/gradlew + + - name: Sync Capacitor App + run: npx cap sync + working-directory: mobile + + - name: Build Capacitor App + run: npx cap build android --keystorepath ~/.keystore/pulse-editor.keystore --keystorepass ${{ secrets.ANDROID_KEYSTORE_PASS }} --keystorealias ${{ secrets.ANDROID_KEYSTORE_ALIAS }} --keystorealiaspass ${{ secrets.ANDROID_KEYSTORE_ALIAS_PASS }} --androidreleasetype AAB --signing-type jarsigner + working-directory: mobile + + - name: Publish to Play Store + uses: r0adkll/upload-google-play@v1 + with: + serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }} + packageName: com.pulse_editor.app + releaseFiles: mobile/android/app/build/outputs/bundle/release/app-release-signed.aab + track: internal + status: draft diff --git a/mobile/README.md b/mobile/README.md index f0509a5..06a1967 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -1,10 +1,8 @@ # Android release ```bash npx cap sync -# Build .aab file (will fail signing, use the next command to fix) -npx cap build android --keystorepath "" --keystorepass "" --keystorealias "" --keystorealiaspass "" --androidreleasetype AAB -# Sign the .aab -jarsigner -verbose -keystore "" "" "" +# Build .aab file +npx cap build android --keystorepath "" --keystorepass "" --keystorealias "" --keystorealiaspass "" --androidreleasetype AAB --signing-type jarsigner ``` Then, `mobile/android/app/build/outputs/bundle/release/app-released.aab` is a signed .aab ready for publishing. \ No newline at end of file diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle index 4b0a6b9..25453f3 100644 --- a/mobile/android/app/build.gradle +++ b/mobile/android/app/build.gradle @@ -7,7 +7,7 @@ android { applicationId "com.pulse_editor.app" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1 + versionCode 2 versionName "v0.1.1-beta" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions {