Просмотр исходного кода

fix(mobile): reset navigation stack when switching tab or searching

when it's a page view
Tienson Qin 2 месяцев назад
Родитель
Сommit
bf95e92ab2

+ 19 - 0
ios/App/App/AppDelegate.swift

@@ -134,6 +134,22 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UINavigationControllerDel
     // MARK: Navigation operations
     // ---------------------------------------------------------
 
+    private func emptyNavStack(path: String) {
+        let path = normalizedPath(path)
+        guard let nav = navController else { return }
+
+        ignoreRoutePopCount = 0
+        popSnapshotView?.removeFromSuperview()
+        popSnapshotView = nil
+
+        let vc = NativePageViewController(path: path, push: false)
+        pathStack = [path]
+
+        nav.setViewControllers([vc], animated: false)
+        SharedWebViewController.instance.clearPlaceholder()
+        SharedWebViewController.instance.attach(to: vc)
+    }
+
     private func pushIfNeeded(path: String, animated: Bool) {
         let path = normalizedPath(path)
         guard let nav = navController else { return }
@@ -317,6 +333,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UINavigationControllerDel
             let navigationType = (notification.userInfo?["navigationType"] as? String) ?? "push"
 
             switch navigationType {
+            case "reset":
+                self.emptyNavStack(path: path)
+
             case "replace":
                 self.replaceTop(path: path)
 

+ 27 - 18
src/main/mobile/bottom_tabs.cljs

@@ -3,10 +3,10 @@
   (:require [cljs-bean.core :as bean]
             [clojure.string :as string]
             [frontend.handler.editor :as editor-handler]
-            [frontend.handler.route :as route-handler]
             [frontend.state :as state]
             [frontend.util :as util]
             [logseq.common.util :as common-util]
+            [mobile.navigation :as mobile-nav]
             [mobile.state :as mobile-state]))
 
 ;; Capacitor plugin instance:
@@ -79,34 +79,43 @@
                (editor-handler/keydown-new-block-handler nil))))
          nil)))))
 
+(defonce *previous-tab (atom nil))
 (defonce add-tab-listeners!
   (do
     (add-tab-selected-listener!
      (fn [tab]
-       (reset! mobile-state/*search-input "")
-       (when-not (= tab "quick-add")
-         (mobile-state/set-tab! tab))
-       (case tab
-         "home"
-         (do
-           (route-handler/redirect-to-home!)
-           (util/scroll-to-top false))
-         "quick-add"
-         (editor-handler/show-quick-add)
-         ;; TODO: support longPress detection
-         ;; (if (= "longPress" interaction)
-         ;;   (state/pub-event! [:mobile/start-audio-record])
-         ;;   (editor-handler/show-quick-add))
-         nil)))
+       (let [exit-quick-add? (= @*previous-tab "quick-add")]
+         (reset! mobile-state/*search-input "")
+         (when-not (contains? #{"quick-add"} tab)
+           (when-not exit-quick-add?
+             (mobile-nav/reset-route!))
+           (mobile-state/set-tab! tab))
+
+         (case tab
+           "home"
+           (when-not exit-quick-add?
+             (util/scroll-to-top false))
+           "quick-add"
+           (editor-handler/show-quick-add)
+             ;; TODO: support longPress detection
+             ;; (if (= "longPress" interaction)
+             ;;   (state/pub-event! [:mobile/start-audio-record])
+             ;;   (editor-handler/show-quick-add))
+           nil)
+
+         (reset! *previous-tab tab))))
+
     (add-watch mobile-state/*tab ::select-tab
                (fn [_ _ _old new]
                  (when new (select! new))))
     (add-search-listener!
      (fn [q]
-      ;; wire up search handler
+       ;; wire up search handler
        (js/console.log "Native search query" q)
        (reset! mobile-state/*search-input q)
-       (reset! mobile-state/*search-last-input-at (common-util/time-ms))))
+       (reset! mobile-state/*search-last-input-at (common-util/time-ms))
+       (when (= :page (get-in (state/get-route-match) [:data :name]))
+         (mobile-nav/reset-route!))))
     (add-keyboard-hack-listener!)))
 
 (defn configure

+ 10 - 8
src/main/mobile/components/app.cljs

@@ -87,15 +87,17 @@
 
 (rum/defc other-page
   [view tab route-match]
-  [:div#main-content-container.px-5.ls-layer
-   (if view
-     (view route-match)
-     (case (keyword tab)
-       :home nil
-       :favorites (favorites/favorites)
+  (let [tab' (keyword tab)]
+    [:div#main-content-container.px-5.ls-layer
+     (case tab'
        :settings (settings/page)
-       :search (search/search)
-       nil))])
+       (if view
+         (view route-match)
+         (case tab'
+           :home nil
+           :favorites (favorites/favorites)
+           :search (search/search)
+           nil)))]))
 
 (rum/defc main-content < rum/static
   [tab route-match]

+ 21 - 10
src/main/mobile/navigation.cljs

@@ -1,6 +1,7 @@
 (ns mobile.navigation
   "Native navigation bridge for mobile (iOS)."
   (:require [clojure.string :as string]
+            [frontend.handler.route :as route-handler]
             [frontend.mobile.util :as mobile-util]
             [lambdaisland.glogi :as log]
             [promesa.core :as p]))
@@ -26,6 +27,14 @@
       (compare-and-set! initialised? false true) "replace" ;; first load
       :else "push")))
 
+(defn- notify-route-payload!
+  [payload]
+  (-> (.routeDidChange mobile-util/ui-local (clj->js payload))
+      (p/catch (fn [err]
+                 (log/warn :mobile-native-navigation/route-report-failed
+                           {:error err
+                            :payload payload})))))
+
 (defn notify-route-change!
   "Inform native iOS layer of a route change to keep native stack in sync.
    {route {to keyword, path-params map, query-params map}
@@ -35,13 +44,15 @@
   (when (and (mobile-util/native-ios?)
              mobile-util/ui-local)
     (let [nav-type (navigation-type push)
-          payload (clj->js (cond-> {:navigationType nav-type
-                                    :push (not= nav-type "replace")}
-                             route (assoc :route route)
-                             (or path (.-hash js/location))
-                             (assoc :path (strip-fragment (or path (.-hash js/location))))))]
-      (-> (.routeDidChange mobile-util/ui-local payload)
-          (p/catch (fn [err]
-                     (log/warn :mobile-native-navigation/route-report-failed
-                               {:error err
-                                :payload payload})))))))
+          payload (cond-> {:navigationType nav-type
+                           :push (not= nav-type "replace")}
+                    route (assoc :route route)
+                    (or path (.-hash js/location))
+                    (assoc :path (strip-fragment (or path (.-hash js/location)))))]
+      (notify-route-payload! payload))))
+
+(defn reset-route!
+  []
+  (route-handler/redirect-to-home! false)
+  (notify-route-payload!
+   {:navigationType "reset"}))