Skip to content

Commit

Permalink
Merge pull request #5 from brianium/feature/tray
Browse files Browse the repository at this point in the history
Adds tray support
  • Loading branch information
brianium authored Nov 16, 2017
2 parents 027fa09 + 902e8ef commit fcf765f
Show file tree
Hide file tree
Showing 12 changed files with 137 additions and 36 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ are doing great things! Uses [reagent](http://reagent-project.github.io/) for th
* Update Slack profile with tomato while pom is in progress
* Send a Slack notification when pomodoro is complete
* Play a sound when time is up (useful if Slack is not configured)
* Timer visible in tray!

Slack usage is optional, but if configured - your profile will be updated like so:

Expand Down Expand Up @@ -56,5 +57,4 @@ $ make

## Todo
- [ ] webview for fetching slack token
- [ ] add timer to tray
- [ ] test and build for other operating systems
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tomaat",
"version": "1.1.0",
"version": "1.2.0",
"productName": "Tomaat",
"main": "resources/main.js",
"dependencies": {
Expand Down
6 changes: 4 additions & 2 deletions src/tomaat/main/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
(:require [cljs.nodejs :as nodejs]
[electron :refer [app Menu shell]]
[electron-default-menu]
[tomaat.util :as u]))
[tomaat.util :as u]
[tomaat.main.tray :as tray]))

(nodejs/enable-util-print!)

Expand Down Expand Up @@ -38,6 +39,7 @@
(defn -main []
(u/on-app "ready" create-window)
(u/on-app "window-all-closed" quit-app)
(u/on-app "activate" activate))
(u/on-app "activate" activate)
(tray/listen!))

(set! *main-cli-fn* -main)
24 changes: 24 additions & 0 deletions src/tomaat/main/tray.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
(ns tomaat.main.tray
(:require [electron :refer [Tray nativeImage]]
[tomaat.util :as u]))

(defonce *tray (atom nil))

(defn update-tray!
[event url]
(let [img (.createFromDataURL nativeImage url)]
(when (nil? @*tray)
(reset! *tray (Tray. img)))
(.setImage @*tray img)))

(defn remove-tray!
[event]
(when @*tray
(.destroy @*tray)
(reset! *tray nil)))

(defn listen! []
(u/on-ipc-main "update-tray" update-tray!)
(u/on-ipc-main "remove-tray" remove-tray!)
(u/on-app "window-all-closed" remove-tray!))

20 changes: 13 additions & 7 deletions src/tomaat/ui/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
[tomaat.ui.timer :refer [start-timer stop-timer]]
[tomaat.ui.settings :as settings]
[tomaat.ui.config :refer [config-screen]]
[tomaat.ui.main :refer [main-screen]]))
[tomaat.ui.main :refer [main-screen]]
[tomaat.ui.tray :as tray]))

(enable-console-print!)

Expand Down Expand Up @@ -40,6 +41,12 @@
(swap! *state assoc-in [:data k] v)
(settings/update-setting k v))

(defn time-changed
[event time]
(let [time-vec (js->clj time)]
(swap! *state assoc :time time-vec)
(tray/update! time-vec)))

(defn timer-complete []
(let [data (:data @*state)]
(swap! *state assoc :started? false)
Expand All @@ -48,10 +55,6 @@
js/Audio.
.play))))

;;; Updates state based on messages from the worker process
(on-ipc "time-changed" #(swap! *state assoc :time (js->clj %2)))
(on-ipc "timer-complete" timer-complete)

;;; Application Component
(defn tomaat []
(let [state @*state
Expand All @@ -66,19 +69,22 @@
:stop stop
:started? started?
:time (:time state)}]

[config-screen
{:toggle toggle-screen
:started? started?
:update update-setting
:data (:data state)}]]]))

(def app (with-meta tomaat
{:component-did-mount (swap! *state assoc :data (data/read))}))
{:component-did-mount #(swap! *state assoc :data (data/read))}))

;;; Render Tomaat as node application
(defn -main []
(reagent/render
[app]
(getElement "tomaat")))
(getElement "tomaat"))
(on-ipc "time-changed" time-changed)
(on-ipc "timer-complete" timer-complete))

(set! *main-cli-fn* -main)
8 changes: 2 additions & 6 deletions src/tomaat/ui/main.cljs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
(ns tomaat.ui.main
"Houses the main screen of Tomaat - that is the timer screen"
(:require [goog.string :as gstring]
goog.string.format))
(:require [tomaat.ui.timer :refer [time->string]]))

(defn header []
[:header.header
[:h1.header__text "Tomaat!"]])

(defn timer
[time]
(->> time
(mapv #(gstring/format "%02d" %))
(interpose ":")
(into [:div.timer])))
[:div.timer (time->string time)])

(defn button [{:keys [on-click]} & children]
[:button.button
Expand Down
13 changes: 12 additions & 1 deletion src/tomaat/ui/timer.cljs
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
(ns tomaat.ui.timer
(:require [tomaat.ui.worker :as worker]))
(:require [tomaat.ui.worker :as worker]
[goog.string :as gstring]
goog.string.format))

(defn time->string
"Takes a vector of form [minutes seconds] and converts
it into a human readble string"
[time]
(->> time
(mapv #(gstring/format "%02d" %))
(interpose ":")
(apply str)))

(defn start-timer
"Starts the timer in the worker process"
Expand Down
42 changes: 42 additions & 0 deletions src/tomaat/ui/tray.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
(ns tomaat.ui.tray
"Handles generating a data url for the tomaat tray"
(:require [tomaat.util :as u]
[tomaat.ui.timer :refer [time->string]]))

(defn- make-canvas [width height]
(let [canvas (.createElement js/document "canvas")]
(set! (.-width canvas) width)
(set! (.-height canvas) height)
canvas))

(defonce *canvas (atom (make-canvas 40 14)))

(defn- data-uri
[canvas]
(let [url (.toDataURL canvas)
context (.getContext canvas "2d")]
(.clearRect context 0 0 (.-width canvas) (.-height canvas))
url))

(defn- write-text
[canvas text]
(let [ctx (.getContext canvas "2d")]
(set! (.-font ctx) "14px Lato")
(set! (.-fillStyle ctx) "#444")
(set! (.-textAlign ctx) "start")
(set! (.-textBaseline ctx) "middle")
(.fillText ctx text 2 7)
(data-uri canvas)))

(defn time->url
"Given a time vector - generate a data url for it"
[time]
(->> (time->string time)
(write-text @*canvas)))

(defn update!
"Update the tray with a new time value"
[time]
(->> time
time->url
(u/send-ipc "update-tray")))
15 changes: 14 additions & 1 deletion src/tomaat/util.cljs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(ns tomaat.util
"A namespace to hide interop details and electron use. Might be
a library some day"
(:require [electron :refer [BrowserWindow remote app ipcRenderer]]
(:require [electron :refer [BrowserWindow remote app ipcRenderer ipcMain]]
[path]
[clojure.string :refer [includes?]]))

Expand Down Expand Up @@ -46,9 +46,22 @@
(on app event-name handler))

(defn on-ipc
"register ipc listener for renderer processes"
[event-name handler]
(on ipcRenderer event-name handler))

(defn send-ipc
([event-name data]
(.send ipcRenderer event-name data))
([event-name]
(.send ipcRenderer event-name)))

(defn on-ipc-main
"register ipc listener for main process - explicitly named as
it is the exception here"
[event-name handler]
(on ipcMain event-name handler))

(defn quit []
(.quit app))

Expand Down
31 changes: 19 additions & 12 deletions src/tomaat/worker/slack.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,28 @@
([event id]
(stop-pomodoro)))

(defn notify
(defn post-notification
"Notifies the user's slackbot channel that the pom is complete and it's time
to take a break from all their labors."
[token]
(go (let [response (<! (request "auth.test" {:token token}))
user-id (get-in response [:body :user_id])]
(request
"chat.postMessage"
{:token token
:channel user-id
:as_user false
:icon_emoji ":tomato:"
:text "Pom complete! Time to take a break :sweat_smile:"}))))

(defn notify
"Notifies user via slackbot if configured to do so"
[]
(with-token
(fn [token]
(go (let [response (<! (request "auth.test" {:token token}))
user-id (get-in response [:body :user_id])]
(request
"chat.postMessage"
{:token token
:channel user-id
:as_user false
:icon_emoji ":tomato:"
:text "Pom complete! Time to take a break :sweat_smile:"}))))))
(let [settings (data/read)
token (:token settings)
slack-me? (:slack-me settings)]
(when (and token slack-me?)
(post-notification token))))

;;; Completing a pomodoro involves stopping it and notifiying the user
(def complete-pomodoro
Expand Down
Binary file modified tomaat-example.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit fcf765f

Please sign in to comment.