mirror of
https://github.com/status-im/status-mobile.git
synced 2025-01-12 17:54:32 +00:00
new structure continue, move utils, move fx macro to re-frame utils n… (#14373)
* new structure continue, move utils, move fx macro to re-frame utils namespace
This commit is contained in:
parent
433f9185c8
commit
31b6e076be
@ -2,12 +2,13 @@
|
||||
status-im.utils.views/letsubs clojure.core/let
|
||||
reagent.core/with-let clojure.core/let
|
||||
status-im.utils.fx/defn clj-kondo.lint-as/def-catch-all
|
||||
utils.re-frame/defn clj-kondo.lint-as/def-catch-all
|
||||
quo.react/with-deps-check clojure.core/fn
|
||||
quo.previews.preview/list-comp clojure.core/for
|
||||
status-im.utils.styles/def clojure.core/def
|
||||
status-im.utils.styles/defn clojure.core/defn
|
||||
taoensso.tufte/defnp clojure.core/defn}
|
||||
:linters {:invalid-arity {:skip-args [status-im.utils.fx/defn]}
|
||||
:linters {:invalid-arity {:skip-args [status-im.utils.fx/defn utils.re-frame/defn]}
|
||||
;;TODO remove number when this is fixed
|
||||
;;https://github.com/borkdude/clj-kondo/issues/867
|
||||
:unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY number]}}}
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
CHANGES=$(git diff --no-ext-diff --diff-filter=d --cached --unified=0 --no-prefix --minimal --exit-code src/quo src/quo2 | grep '^+' || echo '')
|
||||
|
||||
INVALID_CHANGES=$(echo "$CHANGES" | grep -E '(re-frame/dispatch|rf/dispatch|re-frame/subscribe|rf/subscribe|rf/sub|<sub|>evt)')
|
||||
INVALID_CHANGES=$(echo "$CHANGES" | grep -E '(re-frame/dispatch|rf/dispatch|re-frame/subscribe|rf/subscribe|rf/sub|<sub|>evt|status-im)')
|
||||
|
||||
if test -n "$INVALID_CHANGES"; then
|
||||
echo "re-frame dispatch/subscribe is not allowed in quo/quo2 components"
|
||||
echo "re-frame dispatch/subscribe and status-im are not allowed in quo/quo2 components"
|
||||
echo ''
|
||||
echo "$INVALID_CHANGES"
|
||||
exit 1
|
||||
|
@ -6,7 +6,7 @@
|
||||
[quo2.components.avatars.user-avatar :as user-avatar]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[utils :as utils]))
|
||||
[utils.string :as utils]))
|
||||
|
||||
(def themes-landed {:pinned colors/primary-50-opa-5
|
||||
:added colors/primary-50-opa-5
|
||||
|
@ -3,7 +3,8 @@
|
||||
[react-native.core :as rn]
|
||||
[quo2.components.tabs.tab :as tab]
|
||||
[reagent.core :as reagent]
|
||||
[utils :as utils]
|
||||
[utils.number :as utils.number]
|
||||
[utils.collection :as utils.collection]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.notifications.notification-dot :refer [notification-dot]]
|
||||
[react-native.masked-view :as masked-view]
|
||||
@ -50,7 +51,7 @@
|
||||
;; Truncate to avoid unnecessary rendering.
|
||||
(if (> fade-percentage 0.99)
|
||||
0.99
|
||||
(utils/naive-round fade-percentage 2))))
|
||||
(utils.number/naive-round fade-percentage 2))))
|
||||
|
||||
(defn scrollable-tabs
|
||||
"Just like the component `tabs`, displays horizontally scrollable tabs with
|
||||
@ -120,7 +121,7 @@
|
||||
:scroll-on-press?
|
||||
:size)
|
||||
(when scroll-on-press?
|
||||
{:initial-scroll-index (utils/first-index #(= @active-tab-id (:id %)) data)})
|
||||
{:initial-scroll-index (utils.collection/first-index #(= @active-tab-id (:id %)) data)})
|
||||
{:ref #(reset! flat-list-ref %)
|
||||
:extra-data (str @active-tab-id)
|
||||
:horizontal true
|
||||
|
@ -3,7 +3,7 @@
|
||||
[status-im.chat.models :as chat.models]
|
||||
[status-im.chat.models.pin-message :as models.pin-message]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.utils.re-frame :as rf]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im.ui2.screens.common.core :as common]
|
||||
[status-im.constants :as constants]
|
||||
[quo2.components.drawers.action-drawers :as drawer]))
|
||||
|
@ -8,7 +8,7 @@
|
||||
[quo.platform :as platform]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[status-im.ui2.screens.chat.components.message-home-item.style :as style]
|
||||
[status-im.utils.re-frame :as rf]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im.ui2.screens.chat.actions :as actions]))
|
||||
|
||||
(defn open-chat [chat-id]
|
||||
|
@ -1,6 +1,6 @@
|
||||
(ns status-im.ui2.screens.chat.components.message-home-item.view
|
||||
(:require [clojure.string :as string]
|
||||
[status-im.utils.re-frame :as rf]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im.utils.datetime :as time]
|
||||
[quo2.foundations.typography :as typography]
|
||||
[quo2.components.icon :as icons]
|
||||
|
@ -249,7 +249,6 @@
|
||||
contacts (prepare-contacts contacts)
|
||||
notifications (<sub [:activity.center/notifications-grouped-by-date])
|
||||
{requests :received-requests new-info :has-unread?} (find-contact-requests notifications)]
|
||||
(println "wtfff" items contacts)
|
||||
[rn/view {:style {:flex 1}}
|
||||
[discover-card/discover-card {:title (i18n/label :t/invite-friends-to-status)
|
||||
:description (i18n/label :t/share-invite-link)}]
|
||||
@ -378,4 +377,3 @@
|
||||
[quo2.text/text {:size :heading-1 :weight :semi-bold} (i18n/label :t/messages)]
|
||||
[plus-button]]
|
||||
[chats-list]])])
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
||||
[status-im.ui.screens.communities.icon :as communities.icon]
|
||||
[status-im.ui2.screens.chat.components.reply :as components.reply]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.utils.re-frame :as rf]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im.utils.security :as security]
|
||||
[quo2.components.icon :as icons]
|
||||
[status-im.utils.datetime :as time]
|
||||
|
@ -2,7 +2,7 @@
|
||||
(:require
|
||||
[reagent.core :as reagent]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.utils.re-frame :as rf]
|
||||
[utils.re-frame :as rf]
|
||||
[quo2.components.markdown.text :as quo2.text]
|
||||
[react-native.core :as rn]
|
||||
[quo2.core :as quo2]
|
||||
|
@ -8,7 +8,7 @@
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.community.discover-card :as discover-card]
|
||||
[quo2.components.navigation.top-nav :as topnav]
|
||||
[status-im.utils.re-frame :as rf]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.ui.components.react :as rn]
|
||||
|
@ -4,34 +4,6 @@
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.utils.debounce :as debounce]))
|
||||
|
||||
(defn- parse-json
|
||||
;; NOTE(dmitryn) Expects JSON response like:
|
||||
;; {"error": "msg"} or {"result": true}
|
||||
[s]
|
||||
(try
|
||||
(let [res (-> s
|
||||
js/JSON.parse
|
||||
(js->clj :keywordize-keys true))]
|
||||
;; NOTE(dmitryn): AddPeer() may return {"error": ""}
|
||||
;; assuming empty error is a success response
|
||||
;; by transforming {"error": ""} to {:result true}
|
||||
(if (and (:error res)
|
||||
(= (:error res) ""))
|
||||
{:result true}
|
||||
res))
|
||||
(catch :default ^js e
|
||||
{:error (.-message e)})))
|
||||
|
||||
(defn response-handler [success-fn error-fn]
|
||||
(fn handle-response
|
||||
([response]
|
||||
(let [{:keys [error result]} (parse-json response)]
|
||||
(handle-response error result)))
|
||||
([error result]
|
||||
(if error
|
||||
(error-fn error)
|
||||
(success-fn result)))))
|
||||
|
||||
(defn- pretty-print-event [ctx]
|
||||
(let [[first _] (get-coeffect ctx :event)]
|
||||
first))
|
||||
|
@ -1,7 +0,0 @@
|
||||
(ns status-im.utils.re-frame
|
||||
(:require [re-frame.core :as re-frame]))
|
||||
|
||||
(def sub (comp deref re-frame/subscribe))
|
||||
|
||||
(def dispatch re-frame/dispatch)
|
||||
|
@ -6,15 +6,14 @@
|
||||
[react-native.platform :as platform]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im2.navigation.roots :as roots]
|
||||
[status-im2.navigation.state :as state]
|
||||
[status-im2.navigation.view :as views]
|
||||
[utils.re-frame :as rf]
|
||||
|
||||
;; TODO (14/11/22 flexsurfer) move to status-im2 namespace
|
||||
[status-im.multiaccounts.login.core :as login-core]
|
||||
[status-im2.navigation.view :as views]
|
||||
[status-im.utils.fx :as fx]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
[status-im.multiaccounts.login.core :as login-core]))
|
||||
|
||||
;; REGISTER COMPONENT (LAZY)
|
||||
(defn reg-comp [key]
|
||||
@ -171,7 +170,7 @@
|
||||
(reset! state/root-id @state/root-comp-id)
|
||||
(navigation/set-root (get (roots/roots) new-root-id))))
|
||||
|
||||
(fx/defn set-multiaccount-root
|
||||
(rf/defn set-multiaccount-root
|
||||
{:events [::set-multiaccount-root]}
|
||||
[{:keys [db]}]
|
||||
(log/debug :set-multiaccounts-root)
|
||||
|
@ -1,5 +1,5 @@
|
||||
(ns status-im2.navigation.events
|
||||
(:require [status-im.utils.fx :as fx]
|
||||
(:require [utils.re-frame :as rf]
|
||||
[status-im2.setup.hot-reload :as hot-reload]))
|
||||
|
||||
(defn- all-screens-params [db view screen-params]
|
||||
@ -10,39 +10,39 @@
|
||||
(seq screen-params)
|
||||
(assoc-in [:navigation/screen-params view] screen-params)))
|
||||
|
||||
(fx/defn navigate-to-cofx
|
||||
(rf/defn navigate-to-cofx
|
||||
[{:keys [db]} go-to-view-id screen-params]
|
||||
{:db
|
||||
(-> (assoc db :view-id go-to-view-id)
|
||||
(all-screens-params go-to-view-id screen-params))
|
||||
:navigate-to-fx go-to-view-id})
|
||||
|
||||
(fx/defn navigate-to
|
||||
(rf/defn navigate-to
|
||||
{:events [:navigate-to]}
|
||||
[cofx go-to-view-id screen-params]
|
||||
(navigate-to-cofx cofx go-to-view-id screen-params))
|
||||
|
||||
(fx/defn navigate-back
|
||||
(rf/defn navigate-back
|
||||
{:events [:navigate-back]}
|
||||
[_]
|
||||
{:navigate-back-fx nil})
|
||||
|
||||
(fx/defn pop-to-root-tab
|
||||
(rf/defn pop-to-root-tab
|
||||
{:events [:pop-to-root-tab]}
|
||||
[_ tab]
|
||||
{:pop-to-root-tab-fx tab})
|
||||
|
||||
(fx/defn set-stack-root
|
||||
(rf/defn set-stack-root
|
||||
{:events [:set-stack-root]}
|
||||
[_ stack root]
|
||||
{:set-stack-root-fx [stack root]})
|
||||
|
||||
(fx/defn change-tab
|
||||
(rf/defn change-tab
|
||||
{:events [:navigate-change-tab]}
|
||||
[_ tab]
|
||||
{:change-tab-fx tab})
|
||||
|
||||
(fx/defn navigate-replace
|
||||
(rf/defn navigate-replace
|
||||
{:events [:navigate-replace]}
|
||||
[{:keys [db]} go-to-view-id screen-params]
|
||||
(let [db (cond-> (assoc db :view-id go-to-view-id)
|
||||
@ -51,49 +51,49 @@
|
||||
{:db db
|
||||
:navigate-replace-fx go-to-view-id}))
|
||||
|
||||
(fx/defn open-modal
|
||||
(rf/defn open-modal
|
||||
{:events [:open-modal]}
|
||||
[{:keys [db]} comp screen-params]
|
||||
{:db (-> (assoc db :view-id comp)
|
||||
(all-screens-params comp screen-params))
|
||||
:open-modal-fx comp})
|
||||
|
||||
(fx/defn init-root
|
||||
(rf/defn init-root
|
||||
{:events [:init-root]}
|
||||
[_ root-id]
|
||||
{:init-root-fx root-id})
|
||||
|
||||
(fx/defn init-root-with-component
|
||||
(rf/defn init-root-with-component
|
||||
{:events [:init-root-with-component]}
|
||||
[_ root-id comp-id]
|
||||
{:init-root-with-component-fx [root-id comp-id]})
|
||||
|
||||
(fx/defn change-tab-count
|
||||
(rf/defn change-tab-count
|
||||
{:events [:change-tab-count]}
|
||||
[_ tab cnt]
|
||||
{:change-tab-count-fx [tab cnt]})
|
||||
|
||||
(fx/defn hide-signing-sheet
|
||||
(rf/defn hide-signing-sheet
|
||||
{:events [:hide-signing-sheet]}
|
||||
[_]
|
||||
{:hide-signing-sheet nil})
|
||||
|
||||
(fx/defn hide-select-acc-sheet
|
||||
(rf/defn hide-select-acc-sheet
|
||||
{:events [:hide-select-acc-sheet]}
|
||||
[_]
|
||||
{:hide-select-acc-sheet nil})
|
||||
|
||||
(fx/defn hide-wallet-connect-sheet
|
||||
(rf/defn hide-wallet-connect-sheet
|
||||
{:events [:hide-wallet-connect-sheet]}
|
||||
[_]
|
||||
{:hide-wallet-connect-sheet nil})
|
||||
|
||||
(fx/defn hide-wallet-connect-success-sheet
|
||||
(rf/defn hide-wallet-connect-success-sheet
|
||||
{:events [:hide-wallet-connect-success-sheet]}
|
||||
[_]
|
||||
{:hide-wallet-connect-success-sheet nil})
|
||||
|
||||
(fx/defn hide-wallet-connect-app-management-sheet
|
||||
(rf/defn hide-wallet-connect-app-management-sheet
|
||||
{:events [:hide-wallet-connect-app-management-sheet]}
|
||||
[{:keys [db]}]
|
||||
{:db (-> db
|
||||
@ -102,7 +102,7 @@
|
||||
:hide-wallet-connect-app-management-sheet nil})
|
||||
|
||||
;; NAVIGATION 2
|
||||
(fx/defn reload-new-ui
|
||||
(rf/defn reload-new-ui
|
||||
{:events [:reload-new-ui]}
|
||||
[_]
|
||||
(hot-reload/reload)
|
||||
@ -123,7 +123,7 @@
|
||||
:id id
|
||||
:clock now})}))
|
||||
|
||||
(fx/defn navigate-to-nav2
|
||||
(rf/defn navigate-to-nav2
|
||||
{:events [:navigate-to-nav2]}
|
||||
[{:keys [db now]} go-to-view-id id _ from-switcher?]
|
||||
(let [view-id (:view-id db)
|
||||
@ -135,7 +135,7 @@
|
||||
;; TODO(parvesh) - new stacks created from other screens should be stacked on current stack, instead of creating new entry
|
||||
(navigate-from-shell-stack go-to-view-id id db now)))))
|
||||
|
||||
(fx/defn change-root-status-bar-style
|
||||
(rf/defn change-root-status-bar-style
|
||||
{:events [:change-root-status-bar-style]}
|
||||
[_ style]
|
||||
{:change-root-status-bar-style-fx style})
|
||||
|
@ -18,7 +18,6 @@
|
||||
[status-im2.setup.i18n-resources :as i18n-resources]
|
||||
[status-im2.setup.config :as config]
|
||||
[status-im2.setup.log :as log]
|
||||
|
||||
status-im.events
|
||||
|
||||
;; TODO (14/11/22 flexsurfer move to status-im2 namespace
|
||||
|
@ -1,10 +1,23 @@
|
||||
(ns status-im2.setup.dev
|
||||
(:require [react-native.platform :as platform]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
["react-native" :refer (DevSettings LogBox)]))
|
||||
|
||||
(.ignoreAllLogs LogBox)
|
||||
|
||||
(defn setup []
|
||||
(rf/set-mergeable-keys #{:filters/load-filters
|
||||
:pairing/set-installation-metadata
|
||||
:dispatch-n
|
||||
:status-im.ens.core/verify-names
|
||||
:shh/send-direct-message
|
||||
:shh/remove-filter
|
||||
:transport/confirm-messages-processed
|
||||
:group-chats/extract-membership-signature
|
||||
:utils/dispatch-later
|
||||
::json-rpc/call})
|
||||
|
||||
(when (and js/goog.DEBUG platform/ios? DevSettings)
|
||||
;;on Android this method doesn't work
|
||||
(when-let [nm (.-_nativeModule DevSettings)]
|
||||
|
@ -4,10 +4,11 @@
|
||||
[status-im2.setup.db :as db]
|
||||
[status-im2.common.theme.core :as theme]
|
||||
[quo2.theme :as quo2.theme]
|
||||
[utils.re-frame :as rf]
|
||||
|
||||
;; TODO (14/11/22 flexsurfer move to status-im2 namespace
|
||||
[status-im.multiaccounts.login.core :as multiaccounts.login]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.utils.keychain.core :as keychain]
|
||||
[status-im2.navigation.events :as navigation]))
|
||||
|
||||
@ -22,7 +23,7 @@
|
||||
(theme/add-mode-change-listener #(re-frame/dispatch [:system-theme-mode-changed %]))
|
||||
(quo2.theme/set-theme (if (theme/dark-mode?) :dark :light))))
|
||||
|
||||
(fx/defn initialize-views
|
||||
(rf/defn initialize-views
|
||||
{:events [:setup/initialize-view]}
|
||||
[cofx]
|
||||
(let [{{:multiaccounts/keys [multiaccounts]} :db} cofx]
|
||||
@ -30,14 +31,14 @@
|
||||
;; We specifically pass a bunch of fields instead of the whole multiaccount
|
||||
;; as we want store some fields in multiaccount that are not here
|
||||
(let [multiaccount (first (sort-by :timestamp > (vals multiaccounts)))]
|
||||
(fx/merge cofx
|
||||
(rf/merge cofx
|
||||
(multiaccounts.login/open-login (select-keys
|
||||
multiaccount
|
||||
[:key-uid :name :public-key :identicon :images]))
|
||||
(keychain/get-auth-method (:key-uid multiaccount))))
|
||||
(navigation/init-root cofx :intro))))
|
||||
|
||||
(fx/defn initialize-multiaccounts
|
||||
(rf/defn initialize-multiaccounts
|
||||
{:events [:setup/initialize-multiaccounts]}
|
||||
[{:keys [db] :as cofx} all-multiaccounts {:keys [logout?]}]
|
||||
(let [multiaccounts (reduce (fn [acc {:keys [key-uid keycard-pairing]
|
||||
@ -48,7 +49,7 @@
|
||||
keycard-pairing))))
|
||||
{}
|
||||
all-multiaccounts)]
|
||||
(fx/merge cofx
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc :multiaccounts/multiaccounts multiaccounts)
|
||||
(assoc :multiaccounts/logout? logout?)
|
||||
@ -57,7 +58,7 @@
|
||||
[:get-opted-in-to-new-terms-of-service]
|
||||
[:load-information-box-states]]})))
|
||||
|
||||
(fx/defn initialize-app-db
|
||||
(rf/defn initialize-app-db
|
||||
"Initialize db to initial state"
|
||||
[{{:keys [keycard supported-biometric-auth goto-key-storage?]
|
||||
:network/keys [type] :keycard/keys [banner-hidden]} :db}]
|
||||
@ -69,10 +70,10 @@
|
||||
:goto-key-storage? goto-key-storage?
|
||||
:multiaccounts/loading true)})
|
||||
|
||||
(fx/defn start-app
|
||||
(rf/defn start-app
|
||||
{:events [:setup/app-started]}
|
||||
[cofx]
|
||||
(fx/merge cofx
|
||||
(rf/merge cofx
|
||||
{:setup/init-theme nil
|
||||
:get-supported-biometric-auth nil
|
||||
:network/listen-to-network-info nil
|
||||
|
@ -3,8 +3,7 @@
|
||||
[clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im2.setup.config :as config]
|
||||
;; TODO (14/11/22 flexsurfer move to status-im2 namespace
|
||||
[status-im.utils.fx :as fx]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def logs-queue (atom #queue[]))
|
||||
(def max-log-entries 1000)
|
||||
@ -32,7 +31,7 @@
|
||||
(fn [level]
|
||||
(setup level)))
|
||||
|
||||
(fx/defn set-log-level
|
||||
(rf/defn set-log-level
|
||||
[{:keys [db]} log-level]
|
||||
(let [log-level (or log-level config/log-level)]
|
||||
{:db (assoc-in db [:multiaccount :log-level] log-level)
|
||||
|
@ -1,50 +0,0 @@
|
||||
(ns utils
|
||||
(:require [goog.string.format]))
|
||||
|
||||
(defn naive-round
|
||||
"Quickly and naively round number `n` up to `decimal-places`.
|
||||
|
||||
Example usage: use it to avoid re-renders caused by floating-point number
|
||||
changes in Reagent atoms. Such numbers can be rounded up to a certain number
|
||||
of `decimal-places` in order to avoid re-rendering due to tiny fractional
|
||||
changes.
|
||||
|
||||
Don't use this function for arbitrary-precision arithmetic."
|
||||
[n decimal-places]
|
||||
(let [scale (Math/pow 10 decimal-places)]
|
||||
(/ (Math/round (* n scale))
|
||||
scale)))
|
||||
|
||||
(defn truncate-str-memo
|
||||
"Given string and max threshold, trims the string to threshold length with `...`
|
||||
appended to end or in the middle if length of the string exceeds max threshold,
|
||||
returns the same string if threshold is not exceeded"
|
||||
[s threshold & [middle?]]
|
||||
(if (and s (< threshold (count s)))
|
||||
(if middle?
|
||||
(let [str-len (count s)
|
||||
max-len (- threshold 3)
|
||||
start-len (Math/ceil (/ max-len 2))
|
||||
end-len (Math/floor (/ max-len 2))
|
||||
start (subs s 0 start-len)
|
||||
end (subs s (- str-len end-len) str-len)]
|
||||
(str start "..." end))
|
||||
(str (subs s 0 (- threshold 3)) "..."))
|
||||
s))
|
||||
|
||||
(def truncate-str (memoize truncate-str-memo))
|
||||
|
||||
(defn first-index
|
||||
"Returns first index in coll where predicate on coll element is truthy"
|
||||
[pred coll]
|
||||
(->> coll
|
||||
(keep-indexed (fn [idx e]
|
||||
(when (pred e)
|
||||
idx)))
|
||||
first))
|
||||
|
||||
(defn index-by
|
||||
"Given a collection and a unique key function, returns a map that indexes the collection.
|
||||
Similar to group-by except that the map values are single objects (depends on key uniqueness)."
|
||||
[key coll]
|
||||
(into {} (map #(vector (key %) %) coll)))
|
16
src/utils/collection.cljs
Normal file
16
src/utils/collection.cljs
Normal file
@ -0,0 +1,16 @@
|
||||
(ns utils.collection)
|
||||
|
||||
(defn first-index
|
||||
"Returns first index in coll where predicate on coll element is truthy"
|
||||
[pred coll]
|
||||
(->> coll
|
||||
(keep-indexed (fn [idx e]
|
||||
(when (pred e)
|
||||
idx)))
|
||||
first))
|
||||
|
||||
(defn index-by
|
||||
"Given a collection and a unique key function, returns a map that indexes the collection.
|
||||
Similar to group-by except that the map values are single objects (depends on key uniqueness)."
|
||||
[key coll]
|
||||
(into {} (map #(vector (key %) %) coll)))
|
15
src/utils/number.cljs
Normal file
15
src/utils/number.cljs
Normal file
@ -0,0 +1,15 @@
|
||||
(ns utils.number)
|
||||
|
||||
(defn naive-round
|
||||
"Quickly and naively round number `n` up to `decimal-places`.
|
||||
|
||||
Example usage: use it to avoid re-renders caused by floating-point number
|
||||
changes in Reagent atoms. Such numbers can be rounded up to a certain number
|
||||
of `decimal-places` in order to avoid re-rendering due to tiny fractional
|
||||
changes.
|
||||
|
||||
Don't use this function for arbitrary-precision arithmetic."
|
||||
[n decimal-places]
|
||||
(let [scale (Math/pow 10 decimal-places)]
|
||||
(/ (Math/round (* n scale))
|
||||
scale)))
|
84
src/utils/re_frame.clj
Normal file
84
src/utils/re_frame.clj
Normal file
@ -0,0 +1,84 @@
|
||||
(ns utils.re-frame
|
||||
(:refer-clojure :exclude [defn]))
|
||||
|
||||
(defn- register-events
|
||||
[events interceptors name argsyms]
|
||||
(mapv (fn [event]
|
||||
`(utils.re-frame/register-handler-fx
|
||||
~event
|
||||
~interceptors
|
||||
(fn [cofx# [_# ~@argsyms]] (~name cofx# ~@argsyms))))
|
||||
events))
|
||||
|
||||
(defn- fully-qualified-name [sym]
|
||||
(str *ns* "/" (name sym)))
|
||||
|
||||
(defmacro defn
|
||||
"Defines an fx producing function
|
||||
Takes the same arguments as the defn macro
|
||||
Produces a 2 arity function:
|
||||
- first arity takes the declared parameters and returns a function that takes cofx as
|
||||
single argument, for use in composition of effects
|
||||
- second arity takes cofx as first arguments and declared parameters as next arguments,
|
||||
for use in repl or direct call
|
||||
Notes:
|
||||
- destructuring of cofx is possible
|
||||
- supports docstring
|
||||
- supports attr-map with optional :events key which needs to be a vector of
|
||||
event keywords under which the function will be registered
|
||||
- TODO: add suport for `prepost-map?` (don't forget to add it to arglist)
|
||||
- TODO: add validation of macro parameters"
|
||||
{:arglists '([name doc-string? attr-map? [params*] body])}
|
||||
[name & fdecl]
|
||||
(let [m (if (string? (first fdecl))
|
||||
{:doc (first fdecl)}
|
||||
{})
|
||||
fdecl (if (string? (first fdecl))
|
||||
(next fdecl)
|
||||
fdecl)
|
||||
m (if (map? (first fdecl))
|
||||
(conj m (first fdecl))
|
||||
m)
|
||||
events (get m :events [])
|
||||
interceptors (get m :interceptors [])
|
||||
fdecl (if (map? (first fdecl))
|
||||
(next fdecl)
|
||||
fdecl)
|
||||
[cofx & args] (first fdecl)
|
||||
fdecl (next fdecl)
|
||||
argsyms (take (count args) (repeatedly #(gensym "arg")))]
|
||||
(if (and (sequential? events)
|
||||
(every? keyword? events))
|
||||
`(do
|
||||
(clojure.core/defn ~(with-meta name m)
|
||||
([~@argsyms] (fn [cofx#] (~(with-meta name m) cofx# ~@argsyms)))
|
||||
([cofx# ~@args]
|
||||
(when js/goog.DEBUG
|
||||
(when (taoensso.timbre/level>=
|
||||
:trace
|
||||
(:level taoensso.timbre/*config*))
|
||||
(println
|
||||
(clojure.string/join
|
||||
(concat
|
||||
(repeat
|
||||
(deref utils.re-frame/handler-nesting-level)
|
||||
"│ ")
|
||||
["├─"]))
|
||||
~(str (clojure.core/name name) " " *ns*))))
|
||||
(if (and (map? cofx#)
|
||||
(not (nil? (:db cofx#))))
|
||||
(let [res# (let [~cofx cofx#] ~@fdecl)]
|
||||
(when-not (nil? res#)
|
||||
(aset res#
|
||||
"cljs$core$ILookup$_lookup$arity$2"
|
||||
(fn [foo# k#]
|
||||
(clojure.core/this-as
|
||||
m#
|
||||
(when (and (map? k#)
|
||||
(contains? k# :db))
|
||||
(throw (js/Error. (str "fx/defn's result is used as fx producing function in " ~(fully-qualified-name name)))))
|
||||
(get m# k# nil)))))
|
||||
res#)
|
||||
(throw (js/Error. (str "fx/defn expects a map of cofx as first argument got " cofx# " in function " ~(fully-qualified-name name)))))))
|
||||
~@(register-events events interceptors (with-meta name m) argsyms))
|
||||
(throw (Exception. (str "fx/defn expects a vector of keyword as value for :events key in attr-map in function " name))))))
|
83
src/utils/re_frame.cljs
Normal file
83
src/utils/re_frame.cljs
Normal file
@ -0,0 +1,83 @@
|
||||
(ns utils.re-frame
|
||||
(:require-macros utils.re-frame)
|
||||
(:require [taoensso.timbre :as log]
|
||||
[re-frame.core :as re-frame]
|
||||
[re-frame.interceptor :as interceptor])
|
||||
(:refer-clojure :exclude [merge reduce]))
|
||||
|
||||
(def handler-nesting-level (atom 0))
|
||||
|
||||
(def debug-handlers-names
|
||||
"Interceptor which logs debug information to js/console for each event."
|
||||
(interceptor/->interceptor
|
||||
:id :debug-handlers-names
|
||||
:before (fn debug-handlers-names-before
|
||||
[context]
|
||||
(when js/goog.DEBUG
|
||||
(reset! handler-nesting-level 0))
|
||||
(log/debug "Handling re-frame event: " (first (interceptor/get-coeffect context :event)))
|
||||
context)))
|
||||
|
||||
(defn register-handler-fx
|
||||
([name handler]
|
||||
(register-handler-fx name nil handler))
|
||||
([name interceptors handler]
|
||||
(re-frame/reg-event-fx
|
||||
name
|
||||
[debug-handlers-names (re-frame/inject-cofx :now) interceptors]
|
||||
handler)))
|
||||
|
||||
(defn- update-db [cofx fx]
|
||||
(if-let [db (:db fx)]
|
||||
(assoc cofx :db db)
|
||||
cofx))
|
||||
|
||||
(def ^:private mergeable-keys (atom nil))
|
||||
|
||||
(defn set-mergeable-keys [val]
|
||||
(reset! mergeable-keys val))
|
||||
|
||||
(defn- safe-merge [fx new-fx]
|
||||
(if (:merging-fx-with-common-keys fx)
|
||||
fx
|
||||
(clojure.core/reduce (fn [merged-fx [k v]]
|
||||
(if (= :db k)
|
||||
(assoc merged-fx :db v)
|
||||
(if (get merged-fx k)
|
||||
(if (get @mergeable-keys k)
|
||||
(update merged-fx k into v)
|
||||
(do (log/error "Merging fx with common-key: " k v (get merged-fx k))
|
||||
(reduced {:merging-fx-with-common-keys k})))
|
||||
(assoc merged-fx k v))))
|
||||
fx
|
||||
new-fx)))
|
||||
|
||||
(defn merge
|
||||
"Takes a map of co-effects and forms as argument.
|
||||
The first optional form can be map of effects
|
||||
The next forms are functions applying effects and returning a map of effects.
|
||||
The fn ensures that updates to db are passed from function to function within the cofx :db key and
|
||||
that only a :merging-fx-with-common-keys effect is returned if some functions are trying
|
||||
to produce the same effects (excepted :db, :data-source/tx effects).
|
||||
:data-source/tx and effects are handled specially and their results
|
||||
(list of transactions) are compacted to one transactions list (for each effect). "
|
||||
[{:keys [db] :as cofx} & args]
|
||||
(when js/goog.DEBUG
|
||||
(swap! handler-nesting-level inc))
|
||||
(let [[first-arg & rest-args] args
|
||||
initial-fxs? (map? first-arg)
|
||||
fx-fns (if initial-fxs? rest-args args)
|
||||
res
|
||||
(clojure.core/reduce (fn [fxs fx-fn]
|
||||
(let [updated-cofx (update-db cofx fxs)]
|
||||
(if fx-fn
|
||||
(safe-merge fxs (fx-fn updated-cofx))
|
||||
fxs)))
|
||||
(if initial-fxs? first-arg {:db db})
|
||||
fx-fns)]
|
||||
(swap! handler-nesting-level dec)
|
||||
res))
|
||||
|
||||
(def sub (comp deref re-frame/subscribe))
|
||||
|
||||
(def dispatch re-frame/dispatch)
|
20
src/utils/string.cljs
Normal file
20
src/utils/string.cljs
Normal file
@ -0,0 +1,20 @@
|
||||
(ns utils.string)
|
||||
|
||||
(defn truncate-str-memo
|
||||
"Given string and max threshold, trims the string to threshold length with `...`
|
||||
appended to end or in the middle if length of the string exceeds max threshold,
|
||||
returns the same string if threshold is not exceeded"
|
||||
[s threshold & [middle?]]
|
||||
(if (and s (< threshold (count s)))
|
||||
(if middle?
|
||||
(let [str-len (count s)
|
||||
max-len (- threshold 3)
|
||||
start-len (Math/ceil (/ max-len 2))
|
||||
end-len (Math/floor (/ max-len 2))
|
||||
start (subs s 0 start-len)
|
||||
end (subs s (- str-len end-len) str-len)]
|
||||
(str start "..." end))
|
||||
(str (subs s 0 (- threshold 3)) "..."))
|
||||
s))
|
||||
|
||||
(def truncate-str (memoize truncate-str-memo))
|
Loading…
x
Reference in New Issue
Block a user