Pārlūkot izejas kodu

refactor(mobile): use the same code base as electron quick-capture (#8529)

Andelf 2 gadi atpakaļ
vecāks
revīzija
fbb6731740

+ 1 - 53
src/main/electron/listener.cljs

@@ -2,13 +2,10 @@
   "System-component-like ns that defines listeners by event name to receive ipc
   "System-component-like ns that defines listeners by event name to receive ipc
   messages from electron's main process"
   messages from electron's main process"
   (:require [cljs-bean.core :as bean]
   (:require [cljs-bean.core :as bean]
-            [clojure.string :as string]
             [datascript.core :as d]
             [datascript.core :as d]
             [dommy.core :as dom]
             [dommy.core :as dom]
             [electron.ipc :as ipc]
             [electron.ipc :as ipc]
-            [frontend.config :as config]
             [frontend.context.i18n :refer [t]]
             [frontend.context.i18n :refer [t]]
-            [frontend.date :as date]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.db.model :as db-model]
             [frontend.db.model :as db-model]
             [frontend.fs.sync :as sync]
             [frontend.fs.sync :as sync]
@@ -16,7 +13,6 @@
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.file-sync :as file-sync-handler]
             [frontend.handler.file-sync :as file-sync-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
-            [frontend.handler.page :as page-handler]
             [frontend.handler.repo :as repo-handler]
             [frontend.handler.repo :as repo-handler]
             [frontend.handler.route :as route-handler]
             [frontend.handler.route :as route-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.ui :as ui-handler]
@@ -157,55 +153,7 @@
 
 
   (js/window.apis.on "quickCapture"
   (js/window.apis.on "quickCapture"
                      (fn [args]
                      (fn [args]
-                       (let [{:keys [url title content page append]} (bean/->clj args)
-                             insert-today? (get-in (state/get-config)
-                                                   [:quick-capture-options :insert-today?]
-                                                   false)
-                             redirect-page? (get-in (state/get-config)
-                                                    [:quick-capture-options :redirect-page?]
-                                                    false)
-                             today-page (when (state/enable-journals?)
-                                          (string/lower-case (date/today)))
-                             page (if (or (= page "TODAY")
-                                          (and (string/blank? page) insert-today?))
-                                    today-page
-                                    (or (not-empty page)
-                                        (state/get-current-page)
-                                        today-page))
-                             page (or page "quick capture") ;; default to quick capture page, if journals are not enabled
-                             format (db/get-page-format page)
-                             time (date/get-current-time)
-                             text (or (and content (not-empty (string/trim content))) "")
-                             link (if (string/includes? url "www.youtube.com/watch")
-                                    (str title " {{video " url "}}")
-                                    (if (not-empty title)
-                                      (config/link-format format title url)
-                                      url))
-                             template (get-in (state/get-config)
-                                              [:quick-capture-templates :text]
-                                              "**{time}** [[quick capture]]: {text} {url}")
-                             content (-> template
-                                         (string/replace "{time}" time)
-                                         (string/replace "{url}" link)
-                                         (string/replace "{text}" text))
-                             edit-content (state/get-edit-content)
-                             edit-content-blank? (string/blank? edit-content)
-                             edit-content-include-capture? (and (not-empty edit-content)
-                                                                (string/includes? edit-content "[[quick capture]]"))]
-                         (if (and (state/editing?) (not append) (not edit-content-include-capture?))
-                           (if edit-content-blank?
-                             (editor-handler/insert content)
-                             (editor-handler/insert (str "\n" content)))
-
-                           (do
-                             (editor-handler/escape-editing)
-                             (when (not= page (state/get-current-page))
-                               (page-handler/create! page {:redirect? redirect-page?}))
-                             ;; Or else this will clear the newly inserted content
-                             (js/setTimeout #(editor-handler/api-insert-new-block! content {:page page
-                                                                                            :edit-block? true
-                                                                                            :replace-empty-target? true})
-                                            100))))))
+                       (state/pub-event! [:editor/quick-capture args])))
 
 
   (js/window.apis.on "openNewWindowOfGraph"
   (js/window.apis.on "openNewWindowOfGraph"
                      ;; Handle open new window in renderer, until the destination graph doesn't rely on setting local storage
                      ;; Handle open new window in renderer, until the destination graph doesn't rely on setting local storage

+ 1 - 1
src/main/frontend/config.cljs

@@ -219,7 +219,7 @@
 
 
 (defn link-format
 (defn link-format
   [format label link]
   [format label link]
-  (if label
+  (if (not-empty label)
     (case format
     (case format
       :org
       :org
       (util/format "[[%s][%s]]" link label)
       (util/format "[[%s][%s]]" link label)

+ 19 - 15
src/main/frontend/handler/events.cljs

@@ -4,18 +4,24 @@
   one of these events using state/pub-event!"
   one of these events using state/pub-event!"
   (:refer-clojure :exclude [run!])
   (:refer-clojure :exclude [run!])
   (:require ["@capacitor/filesystem" :refer [Directory Filesystem]]
   (:require ["@capacitor/filesystem" :refer [Directory Filesystem]]
+            ["@sentry/react" :as Sentry]
+            [cljs-bean.core :as bean]
             [clojure.core.async :as async]
             [clojure.core.async :as async]
             [clojure.core.async.interop :refer [p->c]]
             [clojure.core.async.interop :refer [p->c]]
             [clojure.set :as set]
             [clojure.set :as set]
             [clojure.string :as string]
             [clojure.string :as string]
             [datascript.core :as d]
             [datascript.core :as d]
             [frontend.commands :as commands]
             [frontend.commands :as commands]
+            [frontend.components.command-palette :as command-palette]
+            [frontend.components.conversion :as conversion-component]
             [frontend.components.diff :as diff]
             [frontend.components.diff :as diff]
+            [frontend.components.encryption :as encryption]
+            [frontend.components.file-sync :as file-sync]
             [frontend.components.git :as git-component]
             [frontend.components.git :as git-component]
             [frontend.components.plugins :as plugin]
             [frontend.components.plugins :as plugin]
             [frontend.components.search :as component-search]
             [frontend.components.search :as component-search]
             [frontend.components.shell :as shell]
             [frontend.components.shell :as shell]
-            [frontend.components.command-palette :as command-palette]
+            [frontend.components.whiteboard :as whiteboard]
             [frontend.config :as config]
             [frontend.config :as config]
             [frontend.context.i18n :refer [t]]
             [frontend.context.i18n :refer [t]]
             [frontend.db :as db]
             [frontend.db :as db]
@@ -28,46 +34,41 @@
             [frontend.fs.nfs :as nfs]
             [frontend.fs.nfs :as nfs]
             [frontend.fs.sync :as sync]
             [frontend.fs.sync :as sync]
             [frontend.fs.watcher-handler :as fs-watcher]
             [frontend.fs.watcher-handler :as fs-watcher]
+            [frontend.handler.command-palette :as cp]
             [frontend.handler.common :as common-handler]
             [frontend.handler.common :as common-handler]
+            [frontend.handler.config :as config-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.file :as file-handler]
             [frontend.handler.file :as file-handler]
+            [frontend.handler.file-sync :as file-sync-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
             [frontend.handler.page :as page-handler]
             [frontend.handler.page :as page-handler]
             [frontend.handler.plugin :as plugin-handler]
             [frontend.handler.plugin :as plugin-handler]
             [frontend.handler.repo :as repo-handler]
             [frontend.handler.repo :as repo-handler]
             [frontend.handler.repo-config :as repo-config-handler]
             [frontend.handler.repo-config :as repo-config-handler]
-            [frontend.handler.config :as config-handler]
             [frontend.handler.route :as route-handler]
             [frontend.handler.route :as route-handler]
             [frontend.handler.search :as search-handler]
             [frontend.handler.search :as search-handler]
+            [frontend.handler.shell :as shell-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.user :as user-handler]
             [frontend.handler.user :as user-handler]
-            [frontend.handler.shell :as shell-handler]
             [frontend.handler.web.nfs :as nfs-handler]
             [frontend.handler.web.nfs :as nfs-handler]
-            [frontend.handler.command-palette :as cp]
             [frontend.mobile.core :as mobile]
             [frontend.mobile.core :as mobile]
-            [frontend.mobile.util :as mobile-util]
             [frontend.mobile.graph-picker :as graph-picker]
             [frontend.mobile.graph-picker :as graph-picker]
+            [frontend.mobile.util :as mobile-util]
             [frontend.modules.instrumentation.posthog :as posthog]
             [frontend.modules.instrumentation.posthog :as posthog]
+            [frontend.modules.instrumentation.sentry :as sentry-event]
             [frontend.modules.outliner.file :as outliner-file]
             [frontend.modules.outliner.file :as outliner-file]
             [frontend.modules.shortcut.core :as st]
             [frontend.modules.shortcut.core :as st]
+            [frontend.quick-capture :as quick-capture]
             [frontend.search :as search]
             [frontend.search :as search]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.ui :as ui]
             [frontend.util :as util]
             [frontend.util :as util]
             [frontend.util.persist-var :as persist-var]
             [frontend.util.persist-var :as persist-var]
-            [frontend.handler.file-sync :as file-sync-handler]
-            [frontend.components.file-sync :as file-sync]
-            [frontend.components.encryption :as encryption]
-            [frontend.components.conversion :as conversion-component]
-            [frontend.components.whiteboard :as whiteboard]
             [goog.dom :as gdom]
             [goog.dom :as gdom]
             [logseq.db.schema :as db-schema]
             [logseq.db.schema :as db-schema]
-            [promesa.core :as p]
-            [rum.core :as rum]
             [logseq.graph-parser.config :as gp-config]
             [logseq.graph-parser.config :as gp-config]
-            [cljs-bean.core :as bean]
-            ["@sentry/react" :as Sentry]
-            [frontend.modules.instrumentation.sentry :as sentry-event]))
+            [promesa.core :as p]
+            [rum.core :as rum]))
 
 
 ;; TODO: should we move all events here?
 ;; TODO: should we move all events here?
 
 
@@ -920,6 +921,9 @@
   (when (and command (not (string/blank? content)))
   (when (and command (not (string/blank? content)))
     (shell-handler/run-cli-command-wrapper! command content)))
     (shell-handler/run-cli-command-wrapper! command content)))
 
 
+(defmethod handle :editor/quick-capture [[_ args]]
+  (quick-capture/quick-capture args))
+
 (defn run!
 (defn run!
   []
   []
   (let [chan (state/get-events-chan)]
   (let [chan (state/get-events-chan)]

+ 32 - 68
src/main/frontend/mobile/intent.cljs

@@ -13,52 +13,16 @@
             [frontend.mobile.util :as mobile-util]
             [frontend.mobile.util :as mobile-util]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.util :as util]
             [frontend.util :as util]
-            [frontend.util.text :as text-util]
             [lambdaisland.glogi :as log]
             [lambdaisland.glogi :as log]
             [logseq.graph-parser.util :as gp-util]
             [logseq.graph-parser.util :as gp-util]
             [frontend.util.fs :as fs-util]
             [frontend.util.fs :as fs-util]
             [logseq.graph-parser.config :as gp-config]
             [logseq.graph-parser.config :as gp-config]
-            [logseq.graph-parser.mldoc :as gp-mldoc]
             [logseq.graph-parser.util.page-ref :as page-ref]
             [logseq.graph-parser.util.page-ref :as page-ref]
             [promesa.core :as p]))
             [promesa.core :as p]))
 
 
-(defn- handle-received-text [result]
-  (let [{:keys [title url]} result
-        page (or (state/get-current-page)
-                 (string/lower-case (date/journal-name)))
-        format (db/get-page-format page)
-        time (date/get-current-time)
-        url (if (and (gp-mldoc/link? format title) (not url))
-              title
-              url)
-        text (if (= url title) nil title)
-        [text url] (if (or (gp-mldoc/link? format url) (not url))
-                     [text url]
-                     (string/split url "\"\n"))
-        text (some-> text (string/replace #"^\"" ""))
-        url (and url
-                 (cond (boolean (text-util/get-matched-video url))
-                       (util/format "{{video %s}}" url)
-
-                       (and (string/includes? url "twitter.com")
-                            (string/includes? url "status"))
-                       (util/format "{{twitter %s}}" url)
-
-                       :else
-                       (if text
-                         (config/link-format format text url)
-                         url)))
-        template (get-in (state/get-config)
-                         [:quick-capture-templates :text]
-                         "**{time}** [[quick capture]]: {text} {url}")
-        values (-> (string/replace template "{time}" time)
-                   (string/replace "{text}" (or text ""))
-                   (string/replace "{url}" (or url "")))]
-    (if (state/get-edit-block)
-      (editor-handler/insert values)
-      (editor-handler/api-insert-new-block! values {:page page
-                                                    :edit-block? false
-                                                    :replace-empty-target? true}))))
+(defn- handle-received-text [args]
+  ;; {:title :type :url}
+  (state/pub-event! [:editor/quick-capture args]))
 
 
 (defn- embed-asset-file [url format]
 (defn- embed-asset-file [url format]
   (p/let [basename (path/basename url)
   (p/let [basename (path/basename url)
@@ -66,9 +30,9 @@
           time (date/get-current-time)
           time (date/get-current-time)
           path (editor-handler/get-asset-path basename)
           path (editor-handler/get-asset-path basename)
           _file (p/catch
           _file (p/catch
-                    (.copy Filesystem (clj->js {:from url :to path}))
-                    (fn [error]
-                      (log/error :copy-file-error {:error error})))
+                 (.copy Filesystem (clj->js {:from url :to path}))
+                 (fn [error]
+                   (log/error :copy-file-error {:error error})))
           url (util/format "../assets/%s" basename)
           url (util/format "../assets/%s" basename)
           url (editor-handler/get-asset-file-link format url label true)
           url (editor-handler/get-asset-file-link format url label true)
           template (get-in (state/get-config)
           template (get-in (state/get-config)
@@ -90,9 +54,9 @@
                           (config/get-pages-directory)
                           (config/get-pages-directory)
                           (str (js/encodeURI (fs-util/file-name-sanity title)) (path/extname url)))
                           (str (js/encodeURI (fs-util/file-name-sanity title)) (path/extname url)))
           _ (p/catch
           _ (p/catch
-                (.copy Filesystem (clj->js {:from url :to path}))
-                (fn [error]
-                  (log/error :copy-file-error {:error error})))
+             (.copy Filesystem (clj->js {:from url :to path}))
+             (fn [error]
+               (log/error :copy-file-error {:error error})))
           url (page-ref/->page-ref title)
           url (page-ref/->page-ref title)
           template (get-in (state/get-config)
           template (get-in (state/get-config)
                            [:quick-capture-templates :text]
                            [:quick-capture-templates :text]
@@ -154,32 +118,32 @@
 (defn handle-result [result]
 (defn handle-result [result]
   (let [result (decode-received-result result)]
   (let [result (decode-received-result result)]
     (when-let [type (:type result)]
     (when-let [type (:type result)]
-          (cond
-            (string/starts-with? type "text/")
-            (handle-received-text result)
-
-            (or (string/starts-with? type "image/")
-                (string/starts-with? type "video/")
-                (string/starts-with? type "audio/"))
-            (handle-received-media result)
-
-            (string/starts-with? type "application/")
-            (handle-received-application result)
-
-            :else
-            (notification/show!
-             [:div
-              "Parsing current shared content are not supported. Please report the following codes on "
-              [:a {:href "https://github.com/logseq/logseq/issues/new?labels=from:in-app&template=bug_report.yaml"
-                   :target "_blank"} "Github"]
-              ". We will look into it soon."
-              [:pre.code (with-out-str (pprint/pprint result))]] :warning false)))))
+      (cond
+        (string/starts-with? type "text/")
+        (handle-received-text result)
+
+        (or (string/starts-with? type "image/")
+            (string/starts-with? type "video/")
+            (string/starts-with? type "audio/"))
+        (handle-received-media result)
+
+        (string/starts-with? type "application/")
+        (handle-received-application result)
+
+        :else
+        (notification/show!
+         [:div
+          "Parsing current shared content are not supported. Please report the following codes on "
+          [:a {:href "https://github.com/logseq/logseq/issues/new?labels=from:in-app&template=bug_report.yaml"
+               :target "_blank"} "Github"]
+          ". We will look into it soon."
+          [:pre.code (with-out-str (pprint/pprint result))]] :warning false)))))
 
 
 (defn handle-received []
 (defn handle-received []
   (p/let [received (p/catch
   (p/let [received (p/catch
-                       (.checkSendIntentReceived SendIntent)
-                       (fn [error]
-                         (log/error :intent-received-error {:error error})))]
+                    (.checkSendIntentReceived SendIntent)
+                    (fn [error]
+                      (prn :intent-received-error {:error error})))]
     (when received
     (when received
       (let [result (js->clj received :keywordize-keys true)]
       (let [result (js->clj received :keywordize-keys true)]
         (handle-result result)))))
         (handle-result result)))))

+ 86 - 0
src/main/frontend/quick_capture.cljs

@@ -0,0 +1,86 @@
+(ns frontend.quick-capture
+  "Quick-capture for both mobile and electron"
+  (:require [cljs-bean.core :as bean]
+            [clojure.string :as string]
+            [frontend.config :as config]
+            [frontend.date :as date]
+            [frontend.db :as db]
+            [frontend.handler.editor :as editor-handler]
+            [frontend.handler.page :as page-handler]
+            [frontend.state :as state]
+            [frontend.util :as util]
+            [frontend.util.text :as text-util]))
+
+
+(defn- extract-highlight
+  "Extract highlighted text and url from mobile browser intent share"
+  [url]
+  (let [[_ highlight link] (re-matches #"(?s)\"(.*)\"\s+([a-z0-9]+://.*)$" url)]
+    (if (not-empty highlight)
+      [highlight link]
+      [nil url])))
+
+(defn- is-tweet-link
+  [url]
+  (re-matches #"^https://twitter\.com/.*?/status/.*?$" url))
+
+(defn quick-capture [args]
+  (let [{:keys [url title content page append]} (bean/->clj args)
+        insert-today? (get-in (state/get-config)
+                              [:quick-capture-options :insert-today?]
+                              false)
+        redirect-page? (get-in (state/get-config)
+                               [:quick-capture-options :redirect-page?]
+                               false)
+        today-page (when (state/enable-journals?)
+                     (string/lower-case (date/today)))
+        page (if (or (= page "TODAY")
+                     (and (string/blank? page) insert-today?))
+               today-page
+               (or (not-empty page)
+                   (state/get-current-page)
+                   today-page))
+        [content url] (if (string/blank? content)
+                        (extract-highlight url)
+                        [content url])
+        page (or page "quick capture") ;; default to "quick capture" page, if journals are not enabled
+        format (db/get-page-format page)
+        time (date/get-current-time)
+        text (or (and content (not-empty (string/trim content))) "")
+        link (cond
+               (boolean (text-util/get-matched-video url))
+               (str title " {{video " url "}}")
+
+               (is-tweet-link url)
+               (util/format "{{twitter %s}}" url)
+
+               (= title url)
+               (config/link-format format nil url)
+
+               :else
+               (config/link-format format title url))
+        template (get-in (state/get-config)
+                         [:quick-capture-templates :text]
+                         "**{time}** [[quick capture]]: {text} {url}")
+        content (-> template
+                    (string/replace "{time}" time)
+                    (string/replace "{url}" link)
+                    (string/replace "{text}" text))
+        edit-content (state/get-edit-content)
+        edit-content-blank? (string/blank? edit-content)
+        edit-content-include-capture? (and (not-empty edit-content)
+                                           (string/includes? edit-content "[[quick capture]]"))]
+    (if (and (state/editing?) (not append) (not edit-content-include-capture?))
+      (if edit-content-blank?
+        (editor-handler/insert content)
+        (editor-handler/insert (str "\n" content)))
+
+      (do
+        (editor-handler/escape-editing)
+        (when (not= page (state/get-current-page))
+          (page-handler/create! page {:redirect? redirect-page?}))
+                             ;; Or else this will clear the newly inserted content
+        (js/setTimeout #(editor-handler/api-insert-new-block! content {:page page
+                                                                       :edit-block? true
+                                                                       :replace-empty-target? true})
+                       100)))))