diff --git a/src/airsonic_ui/events.cljs b/src/airsonic_ui/events.cljs index e2c50db..a4f54f9 100644 --- a/src/airsonic_ui/events.cljs +++ b/src/airsonic_ui/events.cljs @@ -7,15 +7,14 @@ [airsonic-ui.db :as db] [clojure.string :as string])) - -;; TODO: Remove impurities +;; TODO: ;; api related functions (defn ^:private uri-escape [s] (js/encodeURIComponent s)) -(defn api-url [endpoint params] +(defn ^:private api-url [endpoint params] (let [query (->> (assoc params :f "json" :c "airsonic-ui-cljs" @@ -25,13 +24,13 @@ (string/join "&"))] (str config/server "/rest/" endpoint "?" query))) -(defn api-error? +(defn ^:private api-error? "We need to look at the message body because the subsonic api always responds with status 200" [response] (= "failed" (-> response :subsonic-response :status))) -(defn error-message +(defn ^:private error-message [response] (let [{:keys [code message]} (-> response :subsonic-response :error)] (str "Code " code ": " message))) @@ -43,17 +42,38 @@ :http-xhrio {:method :get :uri (api-url "ping" {:u user :p pass}) :response-format (ajax/json-response-format {:keywords? true}) - :on-success [::auth-successful user pass] + :on-success [::auth-success user pass] :on-failure [::api-failure]}})) +;; TODO: Test that credentials are associated + (re-frame/reg-event-fx - ::auth-successful + ::auth-success (fn [{:keys [db]} [_ user pass response]] ;; TODO: Handle failures differently (let [login {:u user :p pass}] {:navigate [login ::routes/main] - :db (-> (update db :active-requests dec) - (assoc :login login))}))) + :db (-> (update db :active-requests #(max (dec %) 0)) + (assoc :login login)) + :dispatch [::api-request "getAlbumList2" :albumList2 {:type "recent"}]}))) + +;; TODO: Test that credentials are actually taken + +(re-frame/reg-event-fx + ::api-request + (fn [{:keys [db]} [_ endpoint k params]] + {:http-xhrio {:method :get + :uri (api-url endpoint (merge params (:login db))) + :response-format (ajax/json-response-format {:keywords? true}) + :on-success [::api-success k] + :on-failure [::api-failure]}})) + +(re-frame/reg-event-db + ::api-success + (fn [db [_ k response]] + (println "api response" response) + ;; we "unwrap" the responses + (assoc db :response (-> response :subsonic-response k)))) (re-frame/reg-event-db ::api-failure @@ -68,6 +88,7 @@ (fn [{:keys [db]} [_ route params query]] ;; all the naviagation logic is in routes.cljs; all we need to do here ;; is say what actually happens once we've navigated succesfully + ;; FIXME: This is really bad and wonky actually {:navigate [(:login db) route params query] :db (assoc db :current-route [route params query])})) @@ -75,8 +96,8 @@ ::routes/forbidden-route (fn [fx _] ;; log out on 403 - {:db db/default-db - :navigate [nil routes/default-route]})) + {:navigate [nil routes/default-route] + :db db/default-db})) ;; database reset / init diff --git a/src/airsonic_ui/routes.cljs b/src/airsonic_ui/routes.cljs index 12f914a..1e07d46 100644 --- a/src/airsonic_ui/routes.cljs +++ b/src/airsonic_ui/routes.cljs @@ -4,15 +4,20 @@ (def default-route ::login) -(def routes - [["/" ::login] - ["/hello" ::main]]) +(def router + (r/router [["/" ::login] + ["/hello" ::main] + ["/album/:id" ::album-view] + ["/artist/:id" ::artist-view]])) -(def protected-routes #{::main}) +(def protected-routes #{::main ::album-view}) (defn is-authorized? [login route] (or (not (protected-routes route)) login)) +(defn url-for [k params] + (str "#" (r/resolve router k params))) + ;; shouldn't need to change this ;; TODO: This is kind of ugly because at the moment r/navigate! is called twice. @@ -22,13 +27,12 @@ "Registers a :navigate effect that can be used for navigation; opts will be passed to bide.core/start!" [opts] - (let [router (r/router routes)] - (re-frame/reg-fx - :navigate - (fn [[login route-id params query]] - (if (is-authorized? login route-id) - (r/navigate! router route-id params query) - (do ;; 403 gets a special event - (println "Not authorized to navigate to " route-id) - (re-frame/dispatch [::forbidden-route]))))) - (r/start! router opts))) + (re-frame/reg-fx + :navigate + (fn [[login route-id params query]] + (if (is-authorized? login route-id) + (r/navigate! router route-id params query) + (do ;; 403 gets a special event + (println "Not authorized to navigate to " route-id) + (re-frame/dispatch [::forbidden-route]))))) + (r/start! router opts)) diff --git a/src/airsonic_ui/subs.cljs b/src/airsonic_ui/subs.cljs index bffb9ad..1cb680e 100644 --- a/src/airsonic_ui/subs.cljs +++ b/src/airsonic_ui/subs.cljs @@ -8,9 +8,17 @@ (fn [db] (:login db))) -;; --- +;; current hashbang (re-frame/reg-sub ::current-route (fn [db] (:current-route db))) + +;; --- + +;; TODO: Make this nice and clean +(re-frame/reg-sub + ::current-album-list + (fn [db] + (-> db :response :album))) diff --git a/src/airsonic_ui/views.cljs b/src/airsonic_ui/views.cljs index fbfb988..aee5176 100644 --- a/src/airsonic_ui/views.cljs +++ b/src/airsonic_ui/views.cljs @@ -5,6 +5,8 @@ [airsonic-ui.events :as events] [airsonic-ui.subs :as subs])) +;; login form + (defn login-form [] (let [user (r/atom "") pass (r/atom "")] @@ -21,10 +23,32 @@ [:div [:button {:on-click #(re-frame/dispatch [::events/authenticate @user @pass])} "Submit"]]]))) -(defn app [route] +;; album list + +(defn album-item [album] + (let [{:keys [artist artistId name coverArt year id]} album] + [:div + ;; link to artist page + [:a {:href (routes/url-for ::routes/artist-view {:id artistId})} artist] + " - " + ;; link to album + [:a {:href (routes/url-for ::routes/album-view {:id id})} name] (when year (str " (" year ")"))])) + +(defn album-list [] + (let [albums @(re-frame/subscribe [::subs/current-album-list])] + [:ul + (map-indexed (fn [idx album] + [:li {:key idx} [album-item album]]) + albums)])) + +;; putting everything together + +(defn app [route params query] (let [login @(re-frame/subscribe [::subs/login])] [:div [:h2 (str "Currently logged in as " (:u login))] + [:h3 (str "Recently played")] + [album-list] [:a {:on-click #(re-frame/dispatch [::events/initialize-db]) :href "#"} "Logout"]])) (defn main-panel [] @@ -33,4 +57,4 @@ [:h1 "Airsonic"] (case route ::routes/login [login-form] - [app route])])) + [app route params query])]))