| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268 |
- (ns frontend.state
- (:require [frontend.storage :as storage]
- [rum.core :as rum]
- [frontend.util :as util :refer-macros [profile]]
- [clojure.string :as string]
- [cljs-bean.core :as bean]
- [medley.core :as medley]
- [goog.object :as gobj]
- [goog.dom :as gdom]
- [dommy.core :as dom]
- [cljs.core.async :as async]
- [lambdaisland.glogi :as log]
- [cljs-time.core :as t]
- [cljs-time.format :as tf]))
- (defonce ^:private state
- (atom
- {:route-match nil
- :today nil
- :system/events (async/chan 100)
- :db/batch-txs (async/chan 100)
- :file/writes (async/chan 100)
- :notification/show? false
- :notification/content nil
- :repo/cloning? false
- :repo/loading-files? nil
- :repo/importing-to-db? nil
- :repo/sync-status {}
- :repo/changed-files nil
- :nfs/user-granted? {}
- :nfs/refreshing? nil
- :sentry/disabled? (storage/get "sentry-disabled")
- ;; TODO: how to detect the network reliably?
- :network/online? true
- :indexeddb/support? true
- :me nil
- :git/current-repo (storage/get :git/current-repo)
- :git/status {}
- :format/loading {}
- :draw? false
- :db/restoring? nil
- :journals-length 2
- :search/q ""
- :search/mode :global
- :search/result nil
- ;; modals
- :modal/show? false
- ;; right sidebar
- :ui/settings-open? false
- :ui/sidebar-open? false
- :ui/left-sidebar-open? false
- :ui/theme (or (storage/get :ui/theme) "dark")
- :ui/wide-mode? false
- ;; :show-all, :hide-block-body, :hide-block-children
- :ui/cycle-collapse :show-all
- :ui/sidebar-collapsed-blocks {}
- :ui/root-component nil
- :ui/file-component nil
- :ui/custom-query-components {}
- :ui/show-recent? false
- :ui/developer-mode? (or (= (storage/get "developer-mode") "true")
- false)
- :document/mode? (or (storage/get :document/mode?) false)
- :github/contents {}
- :config {}
- :block/component-editing-mode? false
- :editor/draw-mode? false
- :editor/show-page-search? false
- :editor/show-page-search-hashtag? false
- :editor/show-date-picker? false
- ;; With label or other data
- :editor/show-input nil
- :editor/last-saved-cursor nil
- :editor/editing? nil
- :editor/last-edit-block-id nil
- :editor/in-composition? false
- :editor/content {}
- :editor/block nil
- :editor/block-dom-id nil
- :editor/set-timestamp-block nil
- :editor/last-input-time nil
- :editor/new-block-toggle? false
- :editor/args nil
- :db/last-transact-time {}
- :db/last-persist-transact-ids {}
- ;; whether database is persisted
- :db/persisted? {}
- :db/latest-txs (or (storage/get-transit :db/latest-txs) {})
- :cursor-range nil
- :selection/mode false
- :selection/blocks []
- :selection/start-block nil
- ;; either :up or :down, defaults to down
- ;; used to determine selection direction when two or more blocks are selected
- :selection/direction :down
- :custom-context-menu/show? false
- :custom-context-menu/links nil
- ;; pages or blocks in the right sidebar
- ;; It is a list of `[repo db-id block-type block-data]` 4-tuple
- :sidebar/blocks '()
- :preferred-language (storage/get :preferred-language)
- ;; electron
- :electron/updater-pending? false
- :electron/updater {}
- ;; plugin
- :plugin/indicator-text nil
- :plugin/installed-plugins {}
- :plugin/installed-themes []
- :plugin/installed-commands {}
- :plugin/simple-commands {}
- :plugin/selected-theme nil
- :plugin/selected-unpacked-pkg nil
- :plugin/active-readme nil
- ;; all notification contents as k-v pairs
- :notification/contents {}
- :graph/syncing? false
- ;; copied blocks
- :copy/blocks {:copy/content nil :copy/block-tree nil}
- :date-picker/date nil}))
- (defn get-route-match
- []
- (:route-match @state))
- (defn get-current-route
- []
- (get-in (get-route-match) [:data :name]))
- (defn home?
- []
- (= :home (get-current-route)))
- (defn get-current-page
- []
- (and
- (= :page (get-current-route))
- (get-in (get-route-match)
- [:path-params :name])))
- (defn route-has-p?
- []
- (get-in (get-route-match) [:query-params :p]))
- (defn sub
- [ks]
- (if (coll? ks)
- (util/react (rum/cursor-in state ks))
- (util/react (rum/cursor state ks))))
- (defn set-state!
- [path value]
- (if (vector? path)
- (swap! state assoc-in path value)
- (swap! state assoc path value)))
- (defn update-state!
- [path f]
- (if (vector? path)
- (swap! state update-in path f)
- (swap! state update path f)))
- (defn get-current-repo
- []
- (or (:git/current-repo @state) "local"))
- (defn get-config
- ([]
- (get-config (get-current-repo)))
- ([repo-url]
- (get-in @state [:config repo-url])))
- (defonce built-in-macros
- {"img" "[:img.$4 {:src \"$1\" :style {:width $2 :height $3}}]"})
- (defn get-macros
- []
- (merge
- built-in-macros
- (:macros (get-config))))
- (defn sub-config
- []
- (sub :config))
- (defn get-custom-css-link
- []
- (:custom-css-url (get-config)))
- (defn all-pages-public?
- []
- (true? (:all-pages-public? (get-config))))
- (defn enable-grammarly?
- []
- (true? (:feature/enable-grammarly?
- (get (sub-config) (get-current-repo)))))
- (defn store-all-ids-in-text?
- []
- (true? (:text/store-all-ids (get-config))))
- (defn scheduled-deadlines-disabled?
- []
- (true? (:feature/disable-scheduled-and-deadline-query?
- (get (sub-config) (get-current-repo)))))
- (defn enable-timetracking?
- []
- (not (false? (:feature/enable-timetracking?
- (get (sub-config) (get-current-repo))))))
- (defn enable-journals?
- [repo]
- (not (false? (:feature/enable-journals?
- (get (sub-config) repo)))))
- (defn export-heading-to-list?
- []
- (not (false? (:export/heading-to-list?
- (get (sub-config) (get-current-repo))))))
- (defn enable-encryption?
- [repo]
- (:feature/enable-encryption?
- (get (sub-config) repo)))
- (defn enable-git-auto-push?
- [repo]
- (not (false? (:git-auto-push
- (get (sub-config) repo)))))
- (defn enable-block-time?
- []
- ;; (true? (:feature/enable-block-time?
- ;; (get (sub-config) (get-current-repo))))
- ;; Disable block timestamps for now, because it doesn't work with undo/redo
- false)
- ;; Enable by default
- (defn show-brackets?
- []
- (not (false? (:ui/show-brackets?
- (get (sub-config) (get-current-repo))))))
- (defn get-default-home
- []
- (:default-home (get-config)))
- (defn sub-default-home-page
- []
- (get-in (sub-config) [(get-current-repo) :default-home :page] ""))
- (defn custom-home-page?
- []
- (some? (:page (get-default-home))))
- (defn get-preferred-format
- ([]
- (get-preferred-format (get-current-repo)))
- ([repo-url]
- (keyword
- (or
- (when-let [fmt (:preferred-format (get-config repo-url))]
- (string/lower-case (name fmt)))
- (get-in @state [:me :preferred_format] "markdown")))))
- (defn markdown?
- []
- (= (keyword (get-preferred-format))
- :markdown))
- (defn get-pages-directory
- []
- (or
- (when-let [repo (get-current-repo)]
- (:pages-directory (get-config repo)))
- "pages"))
- (defn get-journals-directory
- []
- (or
- (when-let [repo (get-current-repo)]
- (:journals-directory (get-config repo)))
- "journals"))
- (defn org-mode-file-link?
- [repo]
- (:org-mode/insert-file-link? (get-config repo)))
- (defn get-journal-file-name-format
- []
- (when-let [repo (get-current-repo)]
- (:journal/file-name-format (get-config repo))))
- (defn get-preferred-workflow
- []
- (keyword
- (or
- (when-let [workflow (:preferred-workflow (get-config))]
- (let [workflow (name workflow)]
- (if (re-find #"now|NOW" workflow)
- :now
- :todo)))
- (get-in @state [:me :preferred_workflow] :now))))
- (defn get-preferred-todo
- []
- (if (= (get-preferred-workflow) :now)
- "LATER"
- "TODO"))
- (defn hide-file?
- []
- (:hide-file-in-page? (get-config)))
- (defn page-name-order
- "Decide whether to use file name or :title as page name. If it returns \"file\", use the file
- name unless it is missing."
- []
- (:page-name-order (get-config)))
- (defn get-repos
- []
- (get-in @state [:me :repos]))
- (defn set-repos!
- [repos]
- (set-state! [:me :repos] repos))
- (defn add-repo!
- [repo]
- (when repo
- (update-state! [:me :repos]
- (fn [repos]
- (->> (conj repos repo)
- (distinct))))))
- (defn set-current-repo!
- [repo]
- (swap! state assoc :git/current-repo repo)
- (if repo
- (storage/set :git/current-repo repo)
- (storage/remove :git/current-repo)))
- (defn set-preferred-format!
- [format]
- (swap! state assoc-in [:me :preferred_format] (name format)))
- (defn set-preferred-workflow!
- [workflow]
- (swap! state assoc-in [:me :preferred_workflow] (name workflow)))
- (defn set-preferred-language!
- [language]
- (set-state! :preferred-language (name language))
- (storage/set :preferred-language (name language)))
- (defn delete-repo!
- [repo]
- (swap! state update-in [:me :repos]
- (fn [repos]
- (->> (remove #(= (:url repo)
- (:url %))
- repos)
- (util/distinct-by :url))))
- (when (= (get-current-repo) (:url repo))
- (set-current-repo! (:url (first (get-repos))))))
- (defn next-collapse-mode
- []
- (case (:ui/cycle-collapse @state)
- :show-all
- :hide-block-body
- :hide-block-body
- :hide-block-children
- :hide-block-children
- :show-all))
- (defn cycle-collapse!
- []
- (set-state! :ui/cycle-collapse (next-collapse-mode)))
- (defn set-timestamp-block!
- [value]
- (set-state! :editor/set-timestamp-block value))
- (defn get-timestamp-block
- []
- (:editor/set-timestamp-block @state))
- (defn set-edit-content!
- ([input-id value] (set-edit-content! input-id value true))
- ([input-id value set-input-value?]
- (when input-id
- (when set-input-value?
- (when-let [input (gdom/getElement input-id)]
- (util/set-change-value input value)))
- (update-state! :editor/content (fn [m]
- (assoc m input-id value)))
- ;; followers
- ;; (when-let [s (util/extract-uuid input-id)]
- ;; (let [input (gdom/getElement input-id)
- ;; leader-parent (util/rec-get-block-node input)
- ;; followers (->> (array-seq (js/document.getElementsByClassName s))
- ;; (remove #(= leader-parent %)))]
- ;; (prn "followers: " (count followers))
- ;; ))
- )))
- (defn get-edit-input-id
- []
- (ffirst (:editor/editing? @state)))
- (defn get-input
- []
- (when-let [id (get-edit-input-id)]
- (gdom/getElement id)))
- (defn get-last-edit-input-id
- []
- (:editor/last-edit-block-id @state))
- (defn editing?
- []
- (let [input (get-input)]
- (and input (= input (.-activeElement js/document)))))
- (defn get-edit-content
- []
- (get (:editor/content @state) (get-edit-input-id)))
- (defn append-current-edit-content!
- [append-text]
- (when-not (string/blank? append-text)
- (when-let [input-id (get-edit-input-id)]
- (when-let [input (gdom/getElement input-id)]
- (let [value (gobj/get input "value")
- new-value (str value append-text)
- new-value (if (or (= (last value) " ")
- (= (last value) "\n"))
- new-value
- (str "\n" new-value))]
- (js/document.execCommand "insertText" false append-text)
- (update-state! :editor/content (fn [m]
- (assoc m input-id new-value))))))))
- (defn get-cursor-range
- []
- (:cursor-range @state))
- (defn set-cursor-range!
- [range]
- (set-state! :cursor-range range))
- (defn set-cloning!
- [value]
- (set-state! :repo/cloning? value))
- (defn set-q!
- [value]
- (set-state! :search/q value))
- (defn set-search-mode!
- [value]
- (set-state! :search/mode value))
- (defn set-editor-show-page-search!
- [value]
- (set-state! :editor/show-page-search? value))
- (defn get-editor-show-page-search?
- []
- (get @state :editor/show-page-search?))
- (defn set-editor-show-page-search-hashtag!
- [value]
- (set-state! :editor/show-page-search? value)
- (set-state! :editor/show-page-search-hashtag? value))
- (defn get-editor-show-page-search-hashtag?
- []
- (get @state :editor/show-page-search-hashtag?))
- (defn set-editor-show-block-search!
- [value]
- (set-state! :editor/show-block-search? value))
- (defn get-editor-show-block-search?
- []
- (get @state :editor/show-block-search?))
- (defn set-editor-show-template-search!
- [value]
- (set-state! :editor/show-template-search? value))
- (defn get-editor-show-template-search?
- []
- (get @state :editor/show-template-search?))
- (defn set-editor-show-date-picker!
- [value]
- (set-state! :editor/show-date-picker? value))
- (defn get-editor-show-date-picker?
- []
- (get @state :editor/show-date-picker?))
- (defn set-editor-show-input!
- [value]
- (set-state! :editor/show-input value))
- (defn get-editor-show-input
- []
- (get @state :editor/show-input))
- (defn set-edit-input-id!
- [input-id]
- (swap! state update :editor/editing?
- (fn [m]
- (and input-id {input-id true}))))
- (defn get-edit-pos
- []
- (.-selectionStart (get-input)))
- (defn set-selection-start-block!
- [start-block]
- (swap! state assoc :selection/start-block start-block))
- (defn get-selection-start-block
- []
- (get @state :selection/start-block))
- (defn set-selection-blocks!
- ([blocks]
- (set-selection-blocks! blocks :down))
- ([blocks direction]
- (when (seq blocks)
- (swap! state assoc
- :selection/mode true
- :selection/blocks blocks
- :selection/direction direction))))
- (defn into-selection-mode!
- []
- (swap! state assoc :selection/mode true))
- (defn clear-selection!
- []
- (swap! state assoc
- :selection/mode false
- :selection/blocks nil
- :selection/direction :down))
- (defn clear-selection-blocks!
- []
- (swap! state assoc :selection/blocks nil))
- (defn get-selection-blocks
- []
- (:selection/blocks @state))
- (defn in-selection-mode?
- []
- (:selection/mode @state))
- (defn selection?
- "True sense of selection mode with valid selected block"
- []
- (and (in-selection-mode?) (seq (get-selection-blocks))))
- (defn conj-selection-block!
- [block direction]
- (dom/add-class! block "selected noselect")
- (swap! state assoc
- :selection/mode true
- :selection/blocks (conj (:selection/blocks @state) block)
- :selection/direction direction))
- (defn drop-last-selection-block!
- []
- (let [last-block (peek (:selection/blocks @state))]
- (swap! state assoc
- :selection/mode true
- :selection/blocks (vec (pop (:selection/blocks @state))))
- last-block))
- (defn get-selection-direction
- []
- (:selection/direction @state))
- (defn show-custom-context-menu!
- [links]
- (swap! state assoc
- :custom-context-menu/show? true
- :custom-context-menu/links links))
- (defn hide-custom-context-menu!
- []
- (swap! state assoc
- :custom-context-menu/show? false
- :custom-context-menu/links nil))
- (defn set-github-token!
- [repo token-result]
- (when token-result
- (let [{:keys [token expires_at]} token-result]
- (swap! state update-in [:me :repos]
- (fn [repos]
- (map (fn [r]
- (if (= repo (:url r))
- (merge r {:token token :expires_at expires_at})
- repo)) repos))))))
- (defn set-github-installation-tokens!
- [tokens]
- (when (seq tokens)
- (let [tokens (medley/index-by :installation_id tokens)
- repos (get-repos)]
- (when (seq repos)
- (let [set-token-f
- (fn [{:keys [installation_id] :as repo}]
- (let [{:keys [token] :as m} (get tokens installation_id)]
- (if (string? token)
- ;; Github API returns a expires_at key which is a timestamp (expires after 60 minutes at present),
- ;; however, user's system time may be inaccurate. Here, based on the client system time, we use
- ;; 40-minutes interval to deal with some critical conditions, for e.g. http request time consume.
- (let [formatter (tf/formatters :date-time-no-ms)
- expires-at (->> (t/plus (t/now) (t/minutes 40))
- (tf/unparse formatter))]
- (merge repo {:token token :expires_at expires-at}))
- (do
- (when (and
- (:url repo)
- (string/starts-with? (:url repo) "https://"))
- (log/error :token/cannot-set-token {:repo-m repo :token-m m}))
- repo))))
- repos (mapv set-token-f repos)]
- (swap! state assoc-in [:me :repos] repos))))))
- (defn get-github-token
- [repo]
- (when repo
- (let [repos (get-repos)]
- (some #(when (= repo (:url %)) %) repos))))
- (defn toggle-sidebar-open?!
- []
- (swap! state update :ui/sidebar-open? not))
- (defn open-right-sidebar!
- []
- (swap! state assoc :ui/sidebar-open? true))
- (defn hide-right-sidebar!
- []
- (swap! state assoc :ui/sidebar-open? false))
- (defn sidebar-add-block!
- [repo db-id block-type block-data]
- (when db-id
- (update-state! :sidebar/blocks (fn [blocks]
- (->> (remove #(= (second %) db-id) blocks)
- (cons [repo db-id block-type block-data])
- ; FIXME: No need to call `distinct`?
- (distinct))))
- (open-right-sidebar!)
- (when-let [elem (gdom/getElementByClass "cp__right-sidebar-scollable")]
- (util/scroll-to elem 0))))
- (defn sidebar-remove-block!
- [idx]
- (update-state! :sidebar/blocks (fn [blocks]
- (if (string? idx)
- (remove #(= (second %) idx) blocks)
- (util/drop-nth idx blocks))))
- (when (empty? (:sidebar/blocks @state))
- (hide-right-sidebar!)))
- (defn sidebar-block-exists?
- [idx]
- (some #(= (second %) idx) (:sidebar/blocks @state)))
- (defn get-sidebar-blocks
- []
- (:sidebar/blocks @state))
- (defn sidebar-block-toggle-collapse!
- [db-id]
- (when db-id
- (update-state! [:ui/sidebar-collapsed-blocks db-id] not)))
- (defn get-edit-block
- []
- (get @state :editor/block))
- (defn get-last-edit-block
- []
- (let [edit-input-id (get-edit-input-id)
- edit-block (get-edit-block)
- block-element (when edit-input-id (gdom/getElement (string/replace edit-input-id "edit-block" "ls-block")))
- container (when block-element
- (util/get-block-container block-element))]
- (when container
- {:last-edit-block edit-block
- :container (gobj/get container "id")
- :pos (util/get-input-pos (gdom/getElement edit-input-id))})))
- (defn set-editing!
- ([edit-input-id content block cursor-range]
- (set-editing! edit-input-id content block cursor-range true))
- ([edit-input-id content block cursor-range move-cursor?]
- (when (and edit-input-id block)
- (let [block-element (gdom/getElement (string/replace edit-input-id "edit-block" "ls-block"))
- container (util/get-block-container block-element)
- block (if container
- (assoc block
- :block/container (gobj/get container "id"))
- block)
- content (string/trim (or content ""))]
- (swap! state
- (fn [state]
- (-> state
- (assoc-in [:editor/content edit-input-id] content)
- (assoc
- :editor/block block
- :editor/editing? {edit-input-id true}
- :editor/last-edit-block-id edit-input-id
- :cursor-range cursor-range))))
- (when-let [input (gdom/getElement edit-input-id)]
- (let [pos (count cursor-range)]
- (when content
- (util/set-change-value input content)
- ;; FIXME
- ;; use set-change-value for now
- ;; until somebody can figure out why set! value doesn't work here
- ;; it seems to me textarea autoresize is completely broken
- #_
- (set! (.-value input) (string/trim content)))
- (when move-cursor?
- (util/move-cursor-to input pos))))))))
- (defn clear-edit!
- []
- (swap! state merge {:editor/editing? nil
- :editor/block nil
- :cursor-range nil}))
- (defn set-last-pos!
- [new-pos]
- (set-state! :editor/last-saved-cursor new-pos))
- (defn set-block-content-and-last-pos!
- [edit-input-id content new-pos]
- (when edit-input-id
- (set-edit-content! edit-input-id content)
- (set-state! :editor/last-saved-cursor new-pos)))
- (defn set-theme!
- [theme]
- (set-state! :ui/theme theme)
- (storage/set :ui/theme theme))
- (defn dark?
- []
- (= "dark" (:ui/theme @state)))
- (defn set-editing-block-dom-id!
- [block-dom-id]
- (set-state! :editor/block-dom-id block-dom-id))
- (defn get-editing-block-dom-id
- []
- (:editor/block-dom-id @state))
- (defn toggle-theme!
- []
- (let [theme (:ui/theme @state)
- theme' (if (= theme "dark") "white" "dark")]
- (set-theme! theme')))
- (defn- file-content-key
- [repo path]
- (str "ls_file_content_" repo path))
- (defn update-sync-status!
- [status]
- (when (seq status)
- (when-let [current-repo (get-current-repo)]
- (set-state! [:repo/sync-status current-repo] status))))
- (defn set-root-component!
- [component]
- (set-state! :ui/root-component component))
- (defn get-root-component
- []
- (get @state :ui/root-component))
- (defn setup-electron-updater!
- []
- (when (util/electron?)
- (js/window.apis.setUpdatesCallback
- (fn [_ args]
- (let [data (bean/->clj args)
- pending? (not= (:type data) "completed")]
- (set-state! :electron/updater-pending? pending?)
- (when pending? (set-state! :electron/updater data))
- nil)))))
- (defn set-file-component!
- [component]
- (set-state! :ui/file-component component))
- (defn clear-file-component!
- []
- (set-state! :ui/file-component nil))
- (defn get-file-component
- []
- (get @state :ui/file-component))
- (defn set-journals-length!
- [value]
- (when value
- (set-state! :journals-length value)))
- (defn add-custom-query-component!
- [query-string component]
- (update-state! :ui/custom-query-components
- (fn [m]
- (assoc m query-string component))))
- (defn remove-custom-query-component!
- [query-string]
- (update-state! :ui/custom-query-components
- (fn [m]
- (dissoc m query-string))))
- (defn get-custom-query-components
- []
- (vals (get @state :ui/custom-query-components)))
- (defn get-journal-template
- []
- (when-let [repo (get-current-repo)]
- (get-in @state [:config repo :default-templates :journals])))
- (defn set-today!
- [value]
- (set-state! :today value))
- (defn toggle-document-mode!
- []
- (let [mode (get @state :document/mode?)]
- (set-state! :document/mode? (not mode))
- (storage/set :document/mode? (not mode))))
- (defn get-date-formatter
- []
- (or
- (when-let [repo (get-current-repo)]
- (get-in @state [:config repo :date-formatter]))
- ;; TODO:
- (get-in @state [:me :settings :date-formatter])
- "MMM do, yyyy"))
- (defn set-git-status!
- [repo-url value]
- (swap! state assoc-in [:git/status repo-url] value))
- (defn get-shortcut
- ([key]
- (get-shortcut (get-current-repo) key))
- ([repo key]
- (or
- (get (storage/get (str repo "-shortcuts")) key)
- (get-in @state [:config repo :shortcuts key]))))
- (defn get-me
- []
- (:me @state))
- (defn github-authed?
- []
- (:github-authed? (get-me)))
- (defn get-name
- []
- (:name (get-me)))
- (defn logged?
- "Whether the user has logged in."
- []
- (some? (get-name)))
- (defn set-draw!
- [value]
- (set-state! :draw? value))
- (defn in-draw-mode?
- []
- (:draw? @state))
- (defn set-db-restoring!
- [value]
- (set-state! :db/restoring? value))
- (defn get-default-branch
- [repo-url]
- (or
- (some->> (get-repos)
- (filter (fn [m]
- (= (:url m) repo-url)))
- (first)
- :branch)
- "master"))
- (defn get-current-project
- []
- (when-let [project (get-in (get-config) [:project :name])]
- (when-not (string/blank? project)
- project)))
- (defn update-current-project
- [& kv]
- {:pre [(even? (count kv))]}
- (when-let [current-repo (get-current-repo)]
- (let [new-kvs (apply array-map (vec kv))
- projects (:projects (get-me))
- new-projects (reduce (fn [acc project]
- (if (= (:repo project) current-repo)
- (conj acc (merge project new-kvs))
- (conj acc project)))
- []
- projects)]
- (set-state! [:me :projects] new-projects))))
- (defn remove-current-project
- []
- (when-let [current-repo (get-current-repo)]
- (update-state! [:me :projects]
- (fn [projects]
- (remove #(= (:repo %) current-repo) projects)))))
- (defn set-indexedb-support!
- [value]
- (set-state! :indexeddb/support? value))
- (defn set-modal!
- ([modal-panel-content]
- (set-modal! modal-panel-content false))
- ([modal-panel-content fullscreen?]
- (swap! state assoc
- :modal/show? (boolean modal-panel-content)
- :modal/panel-content modal-panel-content
- :modal/fullscreen? fullscreen?)))
- (defn close-modal!
- []
- (swap! state assoc
- :modal/show? false
- :modal/panel-content nil))
- (defn get-db-batch-txs-chan
- []
- (:db/batch-txs @state))
- (defn get-file-write-chan
- []
- (:file/writes @state))
- (defn get-write-chan-length
- []
- (let [c (get-file-write-chan)]
- (count (gobj/get c "buf"))))
- (defn add-tx!
- ;; TODO: replace f with data for batch transactions
- [f]
- (when f
- (when-let [chan (get-db-batch-txs-chan)]
- (async/put! chan f))))
- (defn get-left-sidebar-open?
- []
- (get-in @state [:ui/left-sidebar-open?]))
- (defn set-left-sidebar-open!
- [value]
- (set-state! :ui/left-sidebar-open? value))
- (defn set-developer-mode!
- [value]
- (set-state! :ui/developer-mode? value)
- (storage/set "developer-mode" (str value)))
- (defn get-notification-contents
- []
- (get @state :notification/contents))
- (defn get-new-block-toggle?
- []
- (get @state :editor/new-block-toggle?))
- (defn toggle-new-block-shortcut!
- []
- (update-state! :editor/new-block-toggle? not))
- (defn set-config!
- [repo-url value]
- (set-state! [:config repo-url] value)
- (let [shortcuts (or (:shortcuts value) {})]
- (storage/set (str repo-url "-shortcuts") shortcuts)))
- (defn get-git-auto-push?
- ([]
- (get-git-auto-push? (get-current-repo)))
- ([repo]
- (true? (:git-auto-push (get-config repo)))))
- (defn set-changed-files!
- [repo changed-files]
- (set-state! [:repo/changed-files repo] changed-files))
- (defn get-changed-files
- []
- (get-in @state [:repo/changed-files (get-current-repo)]))
- (defn get-wide-mode?
- []
- (:ui/wide-mode? @state))
- (defn toggle-wide-mode!
- []
- (update-state! :ui/wide-mode? not))
- (defn set-online!
- [value]
- (set-state! :network/online? value))
- (defn online?
- []
- (:network/online? @state))
- (defn get-commands
- []
- (:commands (get-config)))
- (defn get-plugins-commands
- []
- (mapcat seq (flatten (vals (:plugin/installed-commands @state)))))
- (defn get-plugins-commands-with-type
- [type]
- (filterv #(= (keyword (first %)) (keyword type))
- (apply concat (vals (:plugin/simple-commands @state)))))
- (defn get-scheduled-future-days
- []
- (let [days (:scheduled/future-days (get-config))]
- (or (when (int? days) days) 0)))
- (defn set-graph-syncing?
- [value]
- (set-state! :graph/syncing? value))
- (defn set-editor-in-composition!
- [value]
- (set-state! :editor/in-composition? value))
- (defn editor-in-composition?
- []
- (:editor/in-composition? @state))
- (defn set-loading-files!
- [value]
- (set-state! :repo/loading-files? value))
- (defn set-importing-to-db!
- [value]
- (set-state! :repo/importing-to-db? value))
- (defn set-editor-last-input-time!
- [repo time]
- (swap! state assoc-in [:editor/last-input-time repo] time))
- (defn set-last-transact-time!
- [repo time]
- (swap! state assoc-in [:db/last-transact-time repo] time)
- ;; THINK: new block, indent/outdent, drag && drop, etc.
- (set-editor-last-input-time! repo time))
- (defn set-published-pages
- [pages]
- (when-let [repo (get-current-repo)]
- (set-state! [:me :published-pages repo] pages)))
- (defn reset-published-pages
- []
- (set-published-pages []))
- (defn set-db-persisted!
- [repo value]
- (swap! state assoc-in [:db/persisted? repo] value))
- (defn db-idle?
- [repo]
- (when repo
- (when-let [last-time (get-in @state [:db/last-transact-time repo])]
- (let [now (util/time-ms)]
- (>= (- now last-time) 3000)))))
- (defn input-idle?
- [repo]
- (when repo
- (or
- (when-let [last-time (get-in @state [:editor/last-input-time repo])]
- (let [now (util/time-ms)]
- (>= (- now last-time) 500)))
- ;; not in editing mode
- (not (get-edit-input-id)))))
- (defn set-last-persist-transact-id!
- [repo files? id]
- (swap! state assoc-in [:db/last-persist-transact-ids :repo files?] id))
- (defn get-last-persist-transact-id
- [repo files?]
- (get-in @state [:db/last-persist-transact-ids :repo files?]))
- (defn persist-transaction!
- [repo files? tx-id tx-data]
- (when (seq tx-data)
- (let [latest-txs (:db/latest-txs @state)
- last-persist-tx-id (get-last-persist-transact-id repo files?)
- latest-txs (if last-persist-tx-id
- (update-in latest-txs [repo files?]
- (fn [result]
- (remove (fn [tx] (<= (:tx-id tx) last-persist-tx-id)) result)))
- latest-txs)
- new-txs (update-in latest-txs [repo files?] (fn [result]
- (vec (conj result {:tx-id tx-id
- :tx-data tx-data}))))]
- (storage/set-transit! :db/latest-txs new-txs)
- (set-state! :db/latest-txs new-txs))))
- (defn get-repo-latest-txs
- [repo file?]
- (get-in (:db/latest-txs @state) [repo file?]))
- (defn set-nfs-refreshing!
- [value]
- (set-state! :nfs/refreshing? value))
- (defn nfs-refreshing?
- []
- (:nfs/refreshing? @state))
- (defn set-search-result!
- [value]
- (set-state! :search/result value))
- (defn clear-search-result!
- []
- (set-search-result! nil))
- (defn get-search-mode
- []
- (:search/mode @state))
- (defn toggle!
- [path]
- (update-state! path not))
- (defn toggle-settings!
- []
- (toggle! :ui/settings-open?))
- ;; TODO: Move those to the uni `state`
- (defonce editor-op (atom nil))
- (defn set-editor-op!
- [value]
- (reset! editor-op value))
- (defn get-editor-op
- []
- @editor-op)
- (defn get-start-of-week
- []
- (or
- (when-let [repo (get-current-repo)]
- (get-in @state [:config repo :start-of-week]))
- (get-in @state [:me :settings :start-of-week])
- 6))
- (defn get-events-chan
- []
- (:system/events @state))
- (defn pub-event!
- [payload]
- (let [chan (get-events-chan)]
- (async/put! chan payload)))
- (defonce diffs (atom nil))
- (defn get-copied-blocks
- []
- (:copy/blocks @state))
- (defn set-copied-blocks
- [content ids]
- (set-state! :copy/blocks {:copy/content content :copy/block-tree ids}))
- (defn set-editor-args!
- [args]
- (set-state! :editor/args args))
- (defn block-component-editing?
- []
- (:block/component-editing-mode? @state))
- (defn set-block-component-editing-mode!
- [value]
- (set-state! :block/component-editing-mode? value))
- (defn sentry-disabled?
- []
- (:sentry/disabled? @state))
- (defn set-sentry-disabled!
- [value]
- (set-state! :sentry/disabled? value)
- (storage/set "sentry-disabled" value)
- (when value
- (.close js/window.Sentry)))
- (defn logical-outdenting?
- []
- (:editor/logical-outdenting?
- (get (sub-config) (get-current-repo))))
- (defn get-editor-args
- []
- (:editor/args @state))
- (defn get-export-bullet-indentation
- []
- (case (get (get-config) :export/bullet-indentation :two-spaces)
- :eight-spaces
- " "
- :four-spaces
- " "
- :two-spaces
- " "
- :tab
- "\t"))
|