-
Notifications
You must be signed in to change notification settings - Fork 33
/
todo.clj
110 lines (90 loc) · 3.73 KB
/
todo.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
(ns other-examples.todo
(:require [fn-fx.fx-dom :as dom]
[fn-fx.diff :refer [component defui render should-update?]]
[fn-fx.controls :as ui]))
(def main-font (ui/font :family "Helvetica" :size 20))
(defui TodoItem
(render [this {:keys [done? idx text]}]
(ui/border-pane
:padding (ui/insets
:top 10
:bottom 10
:left 0
:right 0)
:left (ui/check-box
:font main-font
:text text
:selected done?
:on-action {:event :swap-status :idx idx})
:right (ui/button :text "X"
:on-action {:event :delete-item :idx idx}))))
(defui MainWindow
(render [this {:keys [todos]}]
(ui/v-box
:style "-fx-base: rgb(30, 30, 35);"
:padding (ui/insets
:top-right-bottom-left 25)
:children [(ui/text-field
:id ::new-item
:prompt-text "What needs to be done?"
:font main-font
:on-action {:event :add-item
:fn-fx/include {::new-item #{:text}}})
(ui/v-box
:children (map-indexed
(fn [idx todo]
(todo-item (assoc todo :idx idx)))
todos))])))
(defui Stage
(render [this args]
(ui/stage
:title "ToDos"
:min-height 600
:listen/height {:event :height-change
:fn-fx/include {::new-item #{:text}}}
:shown true
:scene (ui/scene
:root (main-window args)))))
(defmulti handle-event (fn [state event]
(:event event)))
(defmethod handle-event :swap-status
[state {:keys [idx]}]
(update-in state [:todos idx :done?] (fn [x]
(not x))))
(defmethod handle-event :delete-item
[state {:keys [idx]}]
(update-in state [:todos] (fn [itms]
(println itms idx)
(vec (concat (take idx itms)
(drop (inc idx) itms))))))
(defmethod handle-event :add-item
[state {:keys [fn-fx/includes]}]
(update-in state [:todos] conj {:done? false
:text (get-in includes [::new-item :text])}))
(defmethod handle-event :default
[state event]
(println "No hander for event " (:type event) event)
state)
(defn -main []
(let [;; Data State holds the business logic of our app
data-state (atom {:todos [{:done? false
:text "Take out trash"}]})
;; handler-fn handles events from the ui and updates the data state
handler-fn (fn [event]
(try
(swap! data-state handle-event event)
(catch Throwable ex
(println ex))))
;; ui-state holds the most recent state of the ui
ui-state (agent (dom/app (stage @data-state) handler-fn))]
;; Every time the data-state changes, queue up an update of the UI
(add-watch data-state :ui (fn [_ _ _ _]
(send ui-state
(fn [old-ui]
(try
(dom/update-app old-ui (stage @data-state))
(catch Throwable ex
(println ex)))))))))
(comment
(-main)
)