app.cljs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. (ns capacitor.app
  2. (:require ["@capacitor/app" :refer [App]]
  3. ["@capacitor/status-bar" :refer [StatusBar Style]]
  4. ["./externals.js"]
  5. [clojure.string :as string]
  6. [logseq.shui.dialog.core :as shui-dialog]
  7. [logseq.shui.popup.core :as shui-popup]
  8. [logseq.shui.toaster.core :as shui-toaster]
  9. [rum.core :as rum]
  10. [frontend.rum :as frum]
  11. [promesa.core :as p]
  12. [capacitor.ionic :as ionic]
  13. [capacitor.state :as state]
  14. [capacitor.handler :as handler]
  15. [capacitor.components.nav-utils :as cc-utils]
  16. [capacitor.components.blocks :as cc-blocks]
  17. [capacitor.components.ui :as ui]
  18. [frontend.db.conn :as db-conn]
  19. [frontend.db-mixins :as db-mixins]
  20. [frontend.state :as fstate]
  21. [frontend.db.utils :as db-util]
  22. [frontend.date :as frontend-date]
  23. [frontend.handler.repo :as repo-handler]
  24. [frontend.mobile.util :as mobile-util]
  25. [goog.date :as gdate]
  26. [logseq.db :as ldb]
  27. [capacitor.components.settings :as settings]))
  28. (rum/defc app-graphs-select
  29. []
  30. (let [current-repo (fstate/get-current-repo)
  31. graphs (fstate/get-repos)
  32. short-repo-name (if current-repo
  33. (db-conn/get-short-repo-name current-repo)
  34. "Select a Graph")]
  35. [:<>
  36. (ionic/ion-button
  37. {:fill "clear" :mode "ios"
  38. :class "border-none w-full rounded-lg font-semibold pt-2"
  39. :on-click (fn []
  40. (ui/open-modal! "Switch graph"
  41. {:type :action-sheet
  42. :buttons (for [repo graphs]
  43. {:text (some-> (:url repo) (string/replace #"^logseq_db_" ""))
  44. :role (:url repo)})
  45. :inputs []
  46. :on-action (fn [e]
  47. (when-let [url (:role e)]
  48. (when (string/starts-with? url "logseq_db_")
  49. (fstate/pub-event! [:graph/switch url]))))}))}
  50. short-repo-name)
  51. (ionic/ion-button
  52. {:class "relative -left-2 pt-1.5 opacity-50"
  53. :on-click (fn []
  54. (when-let [db-name (js/prompt "Create new db")]
  55. (when-not (string/blank? db-name)
  56. (-> (repo-handler/new-db! db-name)
  57. (p/then #())))))}
  58. (ionic/tabler-icon "plus" {:size 24}))]))
  59. (rum/defc app-sidebar []
  60. (ionic/ion-menu {:content-id "app-main-content"
  61. :type "push"}
  62. (ionic/ion-header
  63. (ionic/ion-toolbar
  64. [:strong.px-2 {:slot "start"} "Navigations"]))
  65. (ionic/ion-content
  66. [:div.p-4
  67. [:strong "hello, logseq?"]])))
  68. (rum/defc app-tabbar []
  69. (ionic/ion-tab-bar {:color "light"
  70. :class "w-full fixed bottom-4"}
  71. (ionic/ion-tab-button {:tab "tab1"
  72. :selected true
  73. :on-click #(js/alert "home")}
  74. (ionic/tabler-icon "home" {:size 22}) "Journals")
  75. (ionic/ion-tab-button {:tab "tab0"
  76. :selected false}
  77. (ionic/tabler-icon "circle-plus" {:size 24}) "Capture New")
  78. (ionic/ion-tab-button {:tab "tab2"}
  79. (ionic/tabler-icon "settings" {:size 22}) "Settings")))
  80. (rum/defc journals-list < rum/reactive db-mixins/query
  81. []
  82. (let [journals (handler/sub-journals)]
  83. [:ul.app-journals-list
  84. (for [journal-id journals]
  85. (let [journal (db-util/entity journal-id)]
  86. [:li.flex.py-1.flex-col.w-full
  87. [:h1.font-semibold.opacity-90.active:opacity-50
  88. {:on-click #(cc-utils/nav-to-block! journal {:reload-pages! (fn [] ())})}
  89. (:block/title journal)]
  90. ;; blocks editor
  91. (cc-blocks/page-blocks journal)
  92. ]))]))
  93. (rum/defc contents-playground < rum/reactive db-mixins/query
  94. []
  95. [:div.py-4
  96. [:h1.text-4xl.flex.gap-1.items-center.mb-4.pt-2.font-mono
  97. (ionic/tabler-icon "file" {:size 30}) "Contents"]
  98. (cc-blocks/page-blocks "Contents")])
  99. (rum/defc keep-keyboard-open
  100. []
  101. (let [*input (rum/use-ref nil)]
  102. (rum/use-effect!
  103. (fn []
  104. (let [f (fn []
  105. (js/requestAnimationFrame #(.focus (rum/deref *input))))]
  106. (set! (. js/window -keepKeyboardOpen) f)))
  107. [])
  108. [:input.absolute.top-4.left-0.w-1.h-1.opacity-0
  109. {:id "app-keep-keyboard-open-input"
  110. :ref *input}]))
  111. (rum/defc home []
  112. (let [[reload set-reload!] (rum/use-state 0)]
  113. (ionic/ion-content
  114. (ionic/ion-refresher
  115. {:slot "fixed"
  116. :pull-factor 0.5
  117. :pull-min 100
  118. :pull-max 200
  119. :on-ion-refresh (fn [^js e]
  120. (js/setTimeout
  121. (fn [] (.complete (.-detail e))
  122. (set-reload! (inc reload)))
  123. 1000))}
  124. (ionic/ion-refresher-content))
  125. [:div.pt-4.px-4
  126. (journals-list)
  127. ;(contents-playground)
  128. ]
  129. ;; tabbar
  130. ;(app-tabbar)
  131. )
  132. ))
  133. (rum/defc root < rum/reactive
  134. []
  135. (let [db-restoring? (fstate/sub :db/restoring?)]
  136. [:<>
  137. (ionic/ion-page
  138. {:id "app-main-content"}
  139. (ionic/ion-header
  140. (ionic/ion-toolbar
  141. (ionic/ion-buttons {:slot "start"}
  142. (app-graphs-select))
  143. (ionic/ion-buttons {:slot "end"}
  144. (ionic/ion-button
  145. {:size "small" :fill "clear"
  146. :on-click (fn []
  147. (let [apply-date! (fn [date]
  148. (let [page-name (frontend-date/journal-name (gdate/Date. (js/Date. date)))
  149. nav-to-journal! #(cc-utils/nav-to-block! % {:reload-pages! (fn [] ())})]
  150. (if-let [journal (handler/local-page page-name)]
  151. (nav-to-journal! journal)
  152. (-> (handler/<create-page! page-name)
  153. (p/then #(nav-to-journal! (handler/local-page page-name)))))))]
  154. (if (mobile-util/native-android?)
  155. (-> (.showDatePicker mobile-util/ui-local)
  156. (p/then (fn [^js e] (some-> e (.-value) (apply-date!)))))
  157. (ui/open-modal!
  158. (fn [{:keys [close!]}]
  159. (ionic/ion-datetime
  160. {:presentation "date"
  161. :onIonChange (fn [^js e]
  162. (let [val (.-value (.-detail e))]
  163. (apply-date! val)
  164. (close!)))}))))))}
  165. [:span {:slot "icon-only"} (ionic/tabler-icon "calendar-month" {:size 26})])
  166. (ionic/ion-button {:fill "clear"}
  167. (ionic/ion-nav-link
  168. {:routerDirection "forward"
  169. :class "w-full"
  170. :component settings/page}
  171. [:span {:slot "icon-only"} (ionic/tabler-icon "dots-circle-horizontal" {:size 26})])))))
  172. ;; main content
  173. (if db-restoring?
  174. (ionic/ion-content
  175. [:strong.flex.justify-center.items-center.py-24
  176. (ionic/tabler-icon "loader" {:class "animate animate-spin opacity-50" :size 30})])
  177. (home)))]))
  178. (rum/defc main []
  179. (let [nav-ref (rum/use-ref nil)
  180. [_ set-nav-root!] (state/use-nav-root)
  181. current-repo (frum/use-atom-in fstate/state :git/current-repo)]
  182. ;; global
  183. (rum/use-effect!
  184. (fn []
  185. (some-> js/window.externalsjs (.settleStatusBar))
  186. (some-> js/window.externalsjs
  187. (.initGlobalListeners #js {:onKeyboardHide (fn [] (state/exit-editing!))})))
  188. [current-repo])
  189. ;; navigation
  190. (rum/use-effect!
  191. (fn []
  192. (let [handle-back!
  193. (fn []
  194. (cond
  195. (not (nil? (state/get-editing-block)))
  196. (state/exit-editing!)
  197. :else
  198. (cc-utils/nav-pop!)))
  199. ^js back-listener (.addListener App "backButton" handle-back!)]
  200. #(.remove back-listener)))
  201. [])
  202. (rum/use-effect!
  203. (fn []
  204. (set-nav-root! (rum/deref nav-ref))
  205. #())
  206. [(rum/deref nav-ref)])
  207. [:> (.-IonApp ionic/ionic-react)
  208. [:<>
  209. (ionic/ion-nav {:ref nav-ref
  210. :root root ;;settings/page
  211. :animated true
  212. :swipeGesture false})
  213. (keep-keyboard-open)
  214. (ui/install-notifications)
  215. (ui/install-modals)
  216. (shui-toaster/install-toaster)
  217. (shui-dialog/install-modals)
  218. (shui-popup/install-popups)
  219. ]]))