From 99fb07586ee703ffa2fa8ef452248e9188a4ecb2 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 24 Feb 2026 21:57:30 +0800 Subject: [PATCH] fix: notify when no microphone permission --- src/main/frontend/mobile/audio_recorder.cljs | 26 +++++++++++++ src/main/mobile/components/recorder.cljs | 3 +- .../frontend/mobile/audio_recorder_test.cljs | 38 +++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/main/frontend/mobile/audio_recorder.cljs create mode 100644 src/test/frontend/mobile/audio_recorder_test.cljs diff --git a/src/main/frontend/mobile/audio_recorder.cljs b/src/main/frontend/mobile/audio_recorder.cljs new file mode 100644 index 0000000000..4888d6834a --- /dev/null +++ b/src/main/frontend/mobile/audio_recorder.cljs @@ -0,0 +1,26 @@ +(ns frontend.mobile.audio-recorder + (:require [clojure.string :as string] + [frontend.handler.notification :as notification] + [lambdaisland.glogi :as log] + [logseq.shui.ui :as shui] + [promesa.core :as p])) + +(defn- microphone-permission-denied-error? + [error] + (let [message (some-> error str string/lower-case)] + (and (string/includes? message "microphone") + (or (string/includes? message "denied") + (string/includes? message "not authorized") + (string/includes? message "permission"))))) + +(defn start-recording! + [recorder] + (-> (.startRecording ^js recorder) + (p/catch (fn [error] + (log/error :audio/record-start-failed {:error error}) + (when (microphone-permission-denied-error? error) + (notification/show! + "Microphone access is denied. Enable it in Settings > Logseq." + :warning) + (shui/popup-hide!)) + nil)))) diff --git a/src/main/mobile/components/recorder.cljs b/src/main/mobile/components/recorder.cljs index 4ab446bf92..de16db1b13 100644 --- a/src/main/mobile/components/recorder.cljs +++ b/src/main/mobile/components/recorder.cljs @@ -8,6 +8,7 @@ [frontend.db :as db] [frontend.db.model :as db-model] [frontend.handler.editor :as editor-handler] + [frontend.mobile.audio-recorder :as audio-recorder] [frontend.mobile.util :as mobile-util] [frontend.state :as state] [frontend.util :as util] @@ -144,7 +145,7 @@ (.notify beats value'))))) ;; auto start - (.startRecording r) + (audio-recorder/start-recording! r) #(stop))) []) diff --git a/src/test/frontend/mobile/audio_recorder_test.cljs b/src/test/frontend/mobile/audio_recorder_test.cljs new file mode 100644 index 0000000000..5f528976d7 --- /dev/null +++ b/src/test/frontend/mobile/audio_recorder_test.cljs @@ -0,0 +1,38 @@ +(ns frontend.mobile.audio-recorder-test + (:require [cljs.test :refer [is testing]] + [frontend.handler.notification :as notification] + [frontend.mobile.audio-recorder :as audio-recorder] + [frontend.test.helper :include-macros true :refer [deftest-async]] + [logseq.shui.ui :as shui] + [promesa.core :as p])) + +(deftest-async start-recording-shows-warning-when-microphone-permission-denied + (testing "Shows actionable warning and closes recorder popup when mic permission is denied" + (let [warning (atom nil) + popup-hidden? (atom false)] + (p/with-redefs + [notification/show! (fn [content & _] + (reset! warning content)) + shui/popup-hide! (fn [] + (reset! popup-hidden? true))] + (p/let [_ (audio-recorder/start-recording! #js {:startRecording + (fn [] + (p/rejected (js/Error. "Error accessing the microphone: Permission denied")))})] + (is (string? @warning)) + (is (re-find #"Settings" @warning)) + (is (true? @popup-hidden?))))))) + +(deftest-async start-recording-does-not-show-warning-for-non-permission-errors + (testing "Avoids permission warning for unrelated start recording failures" + (let [warning (atom nil) + popup-hidden? (atom false)] + (p/with-redefs + [notification/show! (fn [content & _] + (reset! warning content)) + shui/popup-hide! (fn [] + (reset! popup-hidden? true))] + (p/let [_ (audio-recorder/start-recording! #js {:startRecording + (fn [] + (p/rejected (js/Error. "Error: No microphone device found")))})] + (is (nil? @warning)) + (is (false? @popup-hidden?)))))))