diff --git a/app/dev/resources/notif01.mp3 b/app/dev/resources/notif01.mp3 new file mode 100644 index 0000000..39f95da Binary files /dev/null and b/app/dev/resources/notif01.mp3 differ diff --git a/app/dev/resources/notif02.mp3 b/app/dev/resources/notif02.mp3 new file mode 100644 index 0000000..393228d Binary files /dev/null and b/app/dev/resources/notif02.mp3 differ diff --git a/app/dev/resources/notif03.mp3 b/app/dev/resources/notif03.mp3 new file mode 100644 index 0000000..a189bed Binary files /dev/null and b/app/dev/resources/notif03.mp3 differ diff --git a/app/dev/resources/notif04.mp3 b/app/dev/resources/notif04.mp3 new file mode 100644 index 0000000..278255f Binary files /dev/null and b/app/dev/resources/notif04.mp3 differ diff --git a/app/dev/resources/notif05.mp3 b/app/dev/resources/notif05.mp3 new file mode 100644 index 0000000..adb998e Binary files /dev/null and b/app/dev/resources/notif05.mp3 differ diff --git a/app/dev/resources/notif06.mp3 b/app/dev/resources/notif06.mp3 new file mode 100644 index 0000000..dc724bf Binary files /dev/null and b/app/dev/resources/notif06.mp3 differ diff --git a/app/dev/resources/notif07.mp3 b/app/dev/resources/notif07.mp3 new file mode 100644 index 0000000..fb25b92 Binary files /dev/null and b/app/dev/resources/notif07.mp3 differ diff --git a/app/dev/resources/notif08.mp3 b/app/dev/resources/notif08.mp3 new file mode 100644 index 0000000..3cbc40e Binary files /dev/null and b/app/dev/resources/notif08.mp3 differ diff --git a/app/prod/package.json b/app/prod/package.json index df4ae03..915f62e 100644 --- a/app/prod/package.json +++ b/app/prod/package.json @@ -1,5 +1,5 @@ { - "name": "status-desktop", + "name": "Status", "version": "0.0.1", "main": "js/main.js" } diff --git a/app/prod/resources/notif01.mp3 b/app/prod/resources/notif01.mp3 new file mode 100644 index 0000000..39f95da Binary files /dev/null and b/app/prod/resources/notif01.mp3 differ diff --git a/app/prod/resources/notif02.mp3 b/app/prod/resources/notif02.mp3 new file mode 100644 index 0000000..393228d Binary files /dev/null and b/app/prod/resources/notif02.mp3 differ diff --git a/app/prod/resources/notif03.mp3 b/app/prod/resources/notif03.mp3 new file mode 100644 index 0000000..a189bed Binary files /dev/null and b/app/prod/resources/notif03.mp3 differ diff --git a/app/prod/resources/notif04.mp3 b/app/prod/resources/notif04.mp3 new file mode 100644 index 0000000..278255f Binary files /dev/null and b/app/prod/resources/notif04.mp3 differ diff --git a/app/prod/resources/notif05.mp3 b/app/prod/resources/notif05.mp3 new file mode 100644 index 0000000..adb998e Binary files /dev/null and b/app/prod/resources/notif05.mp3 differ diff --git a/app/prod/resources/notif06.mp3 b/app/prod/resources/notif06.mp3 new file mode 100644 index 0000000..dc724bf Binary files /dev/null and b/app/prod/resources/notif06.mp3 differ diff --git a/app/prod/resources/notif07.mp3 b/app/prod/resources/notif07.mp3 new file mode 100644 index 0000000..fb25b92 Binary files /dev/null and b/app/prod/resources/notif07.mp3 differ diff --git a/app/prod/resources/notif08.mp3 b/app/prod/resources/notif08.mp3 new file mode 100644 index 0000000..3cbc40e Binary files /dev/null and b/app/prod/resources/notif08.mp3 differ diff --git a/package-lock.json b/package-lock.json index d71ce74..695d077 100644 --- a/package-lock.json +++ b/package-lock.json @@ -102,6 +102,9 @@ "tweetnacl": "0.14.5" } }, + "bignumber.js": { + "version": "github:status-im/bignumber.js#cc066a0a3d6bfe0c436c9957f4ea8344bf963c89" + }, "block-stream": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", @@ -513,6 +516,14 @@ "verror": "1.10.0" } }, + "linkify-it": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz", + "integrity": "sha1-B3NSbDF8j9E71TTuHRgP+Iq/iBo=", + "requires": { + "uc.micro": "1.0.3" + } + }, "loose-envify": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", @@ -861,6 +872,13 @@ "prop-types": "15.6.0" } }, + "react-native-hyperlink": { + "version": "git+https://github.com/flexsurfer/react-native-hyperlink.git#3cd0b0f6bd2cc7dc4ccefe6fbc18699b72f68219", + "requires": { + "linkify-it": "1.2.4", + "react-native-web": "0.1.12" + } + }, "react-native-web": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.1.12.tgz", @@ -1046,6 +1064,11 @@ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz", "integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g==" }, + "uc.micro": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.3.tgz", + "integrity": "sha1-ftUNXg+an7ClczeSWfKndFjVAZI=" + }, "uid-number": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", @@ -1077,18 +1100,13 @@ } }, "web3": { - "version": "github:status-im/web3.js#17b13f26044e60ac824d1b97052bfad1be5af9cc", + "version": "github:status-im/web3.js#aca66029d7ffac8ed2803b2fc7f0fec01e335ca3", "requires": { "bignumber.js": "github:status-im/bignumber.js#cc066a0a3d6bfe0c436c9957f4ea8344bf963c89", "crypto-js": "3.1.8", "utf8": "2.1.2", "xhr2": "0.1.4", "xmlhttprequest": "1.8.0" - }, - "dependencies": { - "bignumber.js": { - "version": "github:status-im/bignumber.js#cc066a0a3d6bfe0c436c9957f4ea8344bf963c89" - } } }, "whatwg-fetch": { diff --git a/package.json b/package.json index 414586b..5d666df 100644 --- a/package.json +++ b/package.json @@ -3,17 +3,18 @@ "version": "0.0.1", "description": "Status Desktop (React Native Web and Electron)", "dependencies": { - "react": "16.0.0", - "react-dom": "16.0.0", - "react-native-web": "0.1.12", + "awesome-phonenumber": "^1.0.13", "chance": "1.0.4", "eccjs": "0.3.1", + "emojilib": "^2.2.1", "homoglyph-finder": "^1.1.1", "identicon.js": "github:status-im/identicon.js", - "awesome-phonenumber": "^1.0.13", - "emojilib": "^2.2.1", - "web3": "github:status-im/web3.js#status-develop", - "status-nodejs": "git+https://github.com/status-im/status-nodejs.git" + "react": "16.0.0", + "react-dom": "16.0.0", + "react-native-hyperlink": "git+https://github.com/flexsurfer/react-native-hyperlink.git", + "react-native-web": "0.1.12", + "status-nodejs": "git+https://github.com/status-im/status-nodejs.git", + "web3": "github:status-im/web3.js#status-develop" }, "license": "MPL-2.0", "repository": "https://github.com/status-im/status-electron" diff --git a/project.clj b/project.clj index ed8acb2..6069c08 100644 --- a/project.clj +++ b/project.clj @@ -30,12 +30,12 @@ ["cljsbuild" "once" "prod-front"]] ;; electron packager for production - "desktop-app-osx" ["shell" "electron-packager" "./app/prod" "status-desktop" "--platform=darwin" "--arch=x64" "--electron-version=1.8.2-beta.3" "--extraResource=./node_modules" "--icon=assets/icon1024.icns"] - "desktop-app-linux" ["shell" "electron-packager" "./app/prod" "status-desktop" "--platform=linux" "--arch=x64" "--electron-version=1.8.2-beta.3" "--extraResource=./node_modules" "--icon=assets/icon1024.png"] + "desktop-app-osx" ["shell" "electron-packager" "./app/prod" "Status" "--platform=darwin" "--arch=x64" "--electron-version=1.8.2-beta.3" "--extraResource=./node_modules" "--icon=assets/icon1024.icns"] + "desktop-app-linux" ["shell" "electron-packager" "./app/prod" "Status" "--platform=linux" "--arch=x64" "--electron-version=1.8.2-beta.3" "--extraResource=./node_modules" "--icon=assets/icon1024.png"] - "desktop-app-store" ["shell" "electron-packager" "./app/prod" "status-desktop" "--platform=mas" "--arch=x64" "--electron-version=1.8.2-beta.3" "--extraResource=./node_modules"] - "desktop-app-win64" ["shell" "cmd.exe" "/c" "electron-packager" "./app/prod" "status-desktop" "--platform=win32" "--arch=x64" "--electron-version=1.8.2-beta.3" "--extraResource=./node_modules"] - "desktop-app-win32" ["shell" "cmd.exe" "/c" "electron-packager" "./app/prod" "status-desktop" "--platform=win32" "--arch=ia32" "--electron-version=1.8.2-beta.3" "--extraResource=./node_modules"]} + "desktop-app-store" ["shell" "electron-packager" "./app/prod" "Status" "--platform=mas" "--arch=x64" "--electron-version=1.8.2-beta.3" "--extraResource=./node_modules"] + "desktop-app-win64" ["shell" "cmd.exe" "/c" "electron-packager" "./app/prod" "Status" "--platform=win32" "--arch=x64" "--electron-version=1.8.2-beta.3" "--extraResource=./node_modules"] + "desktop-app-win32" ["shell" "cmd.exe" "/c" "electron-packager" "./app/prod" "Status" "--platform=win32" "--arch=ia32" "--electron-version=1.8.2-beta.3" "--extraResource=./node_modules"]} :hooks [leiningen.cljsbuild] :cljsbuild {:builds {:dev-main {:source-paths ["src"] diff --git a/src/status_desktop/core.cljs b/src/status_desktop/core.cljs index b9619db..9bd127f 100644 --- a/src/status_desktop/core.cljs +++ b/src/status_desktop/core.cljs @@ -25,7 +25,7 @@ (.on app "ready" (fn [] - (reset! *win* (BrowserWindow. (clj->js {:width 1200 :height 800 :icon (.resolve path (js* "__dirname") "../status.icns")}))) + (reset! *win* (BrowserWindow. (clj->js {:width 1200 :height 800}))) ;; when no optimize comment out (.loadURL @*win* (str "file://" (.resolve path (js* "__dirname") "../index.html"))) @@ -50,14 +50,15 @@ (.on ipcMain "StartNode" (fn [event config] - (let [config (.GenerateConfig status-go (.resolve path (js* "__dirname") "../ethereum") 3 0) + (let [app-path (.getPath app "userData") + config (.GenerateConfig status-go (str app-path "/ethereum") 3 0) config' (.parse js/JSON config) _ (set! (.-LogLevel config') "INFO") - _ (set! (.-LogFile config') (.resolve path (js* "__dirname") "../node.log")) + _ (set! (.-LogFile config') (str app-path "/node.log")) _ (set! (.-Enabled (.-UpstreamConfig config')) true) config'' (.stringify js/JSON config') res (.StartNode status-go config'')] - (.log js/console (str "Node started at " (.resolve path (js* "__dirname") "../ethereum"))) + (.log js/console (str "Node started at " (str app-path "/ethereum"))) (set! (.-returnValue event) (str "Config " config'' " Node result: " res))))) (.on ipcMain "CreateAccount" diff --git a/src_front/status_desktop_front/core.cljs b/src_front/status_desktop_front/core.cljs index c64f3c4..f0b7cbb 100644 --- a/src_front/status_desktop_front/core.cljs +++ b/src_front/status_desktop_front/core.cljs @@ -30,7 +30,7 @@ { :role "quit"}]}))) (.append menu (MenuItem. - (clj->js {:label "Status" :submenu [{ :label "Logs" :click #(re-frame/dispatch [:logs]) :accelerator "CmdOrCtrl+L"}]}))) + (clj->js {:label "Dev" :submenu [{ :label "Logs" :click #(re-frame/dispatch [:logs]) :accelerator "CmdOrCtrl+L"}]}))) (.setApplicationMenu Menu menu)) (mount-root) (re-frame/dispatch-sync [:initialize-app])) diff --git a/src_front/status_desktop_front/override/chat.cljs b/src_front/status_desktop_front/override/chat.cljs index ff4176f..b2ecdfc 100644 --- a/src_front/status_desktop_front/override/chat.cljs +++ b/src_front/status_desktop_front/override/chat.cljs @@ -8,11 +8,21 @@ ;;;; DESKTOP +(def audio {:notif01 (js/Audio. (str js/__dirname "/resources/notif01.mp3")) + :notif02 (js/Audio. (str js/__dirname "/resources/notif02.mp3")) + :notif03 (js/Audio. (str js/__dirname "/resources/notif03.mp3")) + :notif04 (js/Audio. (str js/__dirname "/resources/notif04.mp3")) + :notif05 (js/Audio. (str js/__dirname "/resources/notif05.mp3")) + :notif06 (js/Audio. (str js/__dirname "/resources/notif06.mp3")) + :notif07 (js/Audio. (str js/__dirname "/resources/notif07.mp3")) + :notif08 (js/Audio. (str js/__dirname "/resources/notif08.mp3"))}) + (re-frame/reg-fx :send-desktop-notification - (fn [{:keys [content from]}] + (fn [{:keys [content from sound]}] (when-not (.hasFocus js/document) - (js/Notification. from (clj->js {:body content}))))) + (when sound (.play (get audio sound))) + (js/Notification. from (clj->js {:body content :silent true}))))) ;;;; old events @@ -100,8 +110,8 @@ (re-frame/reg-fx :update-message - (fn [message])) - ;(msg-store/update-message message))) + (fn [message] + (storage/update-message message))) (re-frame/reg-fx :save-message diff --git a/src_front/status_desktop_front/override/protocol.cljs b/src_front/status_desktop_front/override/protocol.cljs index 943a3e0..e572cf7 100644 --- a/src_front/status_desktop_front/override/protocol.cljs +++ b/src_front/status_desktop_front/override/protocol.cljs @@ -3,7 +3,8 @@ [status-desktop-front.web3-provider :as web3-provider] [status-im.protocol.handlers :as protocol.handlers] [status-im.constants :as constants] - [status-im.utils.handlers :as handlers])) + [status-im.utils.handlers :as handlers] + [status-desktop-front.storage :as storage])) ;;;; COFX @@ -15,7 +16,7 @@ (re-frame/reg-cofx ::protocol.handlers/get-chat-groups (fn [coeffects _] - (assoc coeffects :groups []))) + (assoc coeffects :groups (storage/get-active-group-chats)))) (re-frame/reg-cofx ::protocol.handlers/get-pending-messages diff --git a/src_front/status_desktop_front/storage.cljs b/src_front/status_desktop_front/storage.cljs index f781f87..5ec178b 100644 --- a/src_front/status_desktop_front/storage.cljs +++ b/src_front/status_desktop_front/storage.cljs @@ -1,7 +1,8 @@ (ns status-desktop-front.storage (:require [alandipert.storage-atom :refer [local-storage]] [status-im.data-store.messages :as data-store.messages] - [status-im.utils.random :as random])) + [status-im.utils.random :as random] + [status-im.constants :as constants])) ;;;; ACCOUNTS ;; I would love to have something similar in status-react instead realm @@ -24,7 +25,7 @@ ;;;; CONTACTS (defn save-contact [contact] - (swap! (:contacts @account) assoc (:whisper-identity contact) contact)) + (swap! (:contacts @account) update-in (:whisper-identity contact) merge contact)) (defn save-contacts [contacts] (mapv save-contact contacts)) @@ -59,6 +60,19 @@ (> timestamp removed-from-at) (> timestamp added-at)))) +(defn- groups [active?] + (filter #(and (:group-chat %) (= (:is-active %) active?)) (get-all-chats))) + +(defn get-active-group-chats [] + (map (fn [{:keys [chat-id public-key private-key public?]}] + (let [group {:group-id chat-id + :public? public?}] + (if (and public-key private-key) + (assoc group :keypair {:private private-key + :public public-key}) + group))) + (groups true))) + ;;;; MESSAGE (defn save-message [{:keys [message-id content] :as message}] @@ -69,11 +83,24 @@ :timestamp (random/timestamp)})] (swap! (:messages @account) assoc message-id message'))) +(defn update-message [{:keys [message-id content] :as message}] + (swap! (:messages @account) update-in [message-id] merge message)) + (defn get-message-by-id [message-id] (get @(:messages @account) message-id)) -(defn get-messages-by-chat-id [chat-id] - (filter #(= chat-id (:chat-id %)) (vals @(:messages @account)))) +(defn get-messages-by-chat-id + ([chat-id] + (get-messages-by-chat-id chat-id 0)) + ([chat-id from] + (let [chats (sort-by :timestamp > (filter #(= chat-id (:chat-id %)) (vals @(:messages @account)))) + to (+ from constants/default-number-of-messages)] + (if (< to (count chats)) + ;;TODO yeah i know i know + (subvec (into [] chats) + from + to) + chats)))) (defn get-last-message [chat-id] (->> (vals @(:messages @account)) diff --git a/src_front/status_desktop_front/ui/components/views.cljs b/src_front/status_desktop_front/ui/components/views.cljs index 407309d..74a89de 100644 --- a/src_front/status_desktop_front/ui/components/views.cljs +++ b/src_front/status_desktop_front/ui/components/views.cljs @@ -4,7 +4,14 @@ [status-desktop-front.ui.components.icons :as icons] [status-im.ui.components.common.styles :as styles] [status-im.ui.components.action-button.styles :as st] - [status-im.ui.components.styles :as common])) + [status-im.ui.components.styles :as common] + [status-im.ui.components.checkbox.styles :as checkbox.styles])) + +(defn checkbox [{:keys [on-value-change checked?]}] + [react/touchable-highlight {:style checkbox.styles/wrapper :on-press #(do (when on-value-change (on-value-change (not checked?))))} + [react/view {:style (checkbox.styles/icon-check-container checked?)} + (when checked? + [icons/icon :icons/ok {:style checkbox.styles/check-icon}])]]) ;; TODO copy-pate with minimum modifications of status-react components diff --git a/src_front/status_desktop_front/ui/screens/chat/profile/views.cljs b/src_front/status_desktop_front/ui/screens/chat/profile/views.cljs index 3b72d4c..d0f56b7 100644 --- a/src_front/status_desktop_front/ui/screens/chat/profile/views.cljs +++ b/src_front/status_desktop_front/ui/screens/chat/profile/views.cljs @@ -1,7 +1,9 @@ (ns status-desktop-front.ui.screens.chat.profile.views (:require [status-desktop-front.react-native-web :as react] [status-im.ui.screens.profile.styles :as styles] + [status-desktop-front.ui.components.views :as components] [re-frame.core :as re-frame] + [reagent.core :as reagent] [status-im.utils.utils :refer [hash-tag?]] [clojure.string :as string] [cljs.nodejs :as nodejs]) @@ -76,6 +78,36 @@ [profile-info-address-item contact] [profile-info-public-key-item public-key contact]]) +(views/defview sound-view [sound label sound-name] + [react/view {:style (merge styles/profile-setting-item {:height 30})} + [react/text {:style styles/profile-setting-text} label] + [react/view {:style {:flex 1}}] + [components/checkbox {:on-value-change + #(re-frame/dispatch [:set-in [:desktop :notifications :sound] sound-name]) + :checked? + (= sound sound-name)}]]) + +(views/defview notifications [] + (views/letsubs [notifications-enabled? [:get-in [:desktop :notifications :enabled?]] + sound [:get-in [:desktop :notifications :sound]]] + [react/view + [react/view {:style styles/profile-setting-item} + [react/text {:style styles/profile-setting-text} "Notifications"] + [react/view {:style {:flex 1}}] + [components/checkbox {:on-value-change + #(re-frame/dispatch [:set-in [:desktop :notifications :enabled?] %]) + :checked? + notifications-enabled?}]] + [sound-view sound "Sound 1" :notif01] + [sound-view sound "Sound 2" :notif02] + [sound-view sound "Sound 3" :notif03] + [sound-view sound "Sound 4" :notif04] + [sound-view sound "Sound 5" :notif05] + [sound-view sound "Sound 6" :notif06] + [sound-view sound "Sound 7" :notif07] + [sound-view sound "Sound 8" :notif08]])) + + (views/defview profile [] (views/letsubs [{:keys [status public-key] :as current-account} [:get-current-account]] [react/view {:style (merge styles/profile {:background-color :white})} @@ -84,4 +116,5 @@ [profile-badge current-account] [profile-status status true]] [react/view {:style styles/profile-info-container} - [my-profile-info current-account]]]])) \ No newline at end of file + [my-profile-info current-account]] + [notifications]]])) \ No newline at end of file diff --git a/src_front/status_desktop_front/ui/screens/chat/view.cljs b/src_front/status_desktop_front/ui/screens/chat/view.cljs index cfe9e4f..3f119d1 100644 --- a/src_front/status_desktop_front/ui/screens/chat/view.cljs +++ b/src_front/status_desktop_front/ui/screens/chat/view.cljs @@ -6,20 +6,23 @@ [status-desktop-front.ui.components.icons :as icons] [status-desktop-front.web3-provider :as protocol] [clojure.string :as string] + [status-im.chat.views.message.message :as message.views] [status-im.chat.styles.message.message :as message.style] [status-im.utils.gfycat.core :as gfycat.core] [status-im.utils.gfycat.core :as gfycat] [status-im.ui.screens.chats-list.styles :as chats-list.styles] - [status-im.constants :as constants]) + [status-im.constants :as constants] + [status-desktop-front.react-native-hyperlink :as rn-hl]) (:require-macros [status-im.utils.views :as views])) (views/defview message-author-name [{:keys [outgoing from] :as message}] (views/letsubs [current-account [:get-current-account] - incoming-name [:contact-name-by-identity from]] - (when-let [name (if outgoing - (:name current-account) - (or incoming-name "Unknown contact"))] - [react/text {:style message.style/author} name]))) + incoming-name [:contact-name-by-identity from]] + (if outgoing + [react/text {:style message.style/author} (:name current-account)] + (let [name (or incoming-name (gfycat/generate-gfy from))] + [react/touchable-highlight {:on-press #(re-frame/dispatch [:show-contact-dialog from name (boolean incoming-name)])} + [react/text {:style message.style/author} name]])))) (defn message [text me? {:keys [outgoing message-id chat-id message-status user-statuses from current-public-key content-type group-chat] :as message}] @@ -36,90 +39,115 @@ :message-id message-id}])) :reagent-render (fn [] - [react/view {:style (merge {:padding-bottom 8} - (if me? - {:align-items :flex-end - :padding-left 90 - :padding-right 60} - {:align-items :flex-start - :padding-left 60 - :padding-right 90}))} + [react/view {:style (merge + {:padding-bottom 8} + (if me? + {:align-items :flex-end + :padding-left 90 + :padding-right 60} + {:align-items :flex-start + :padding-left 60 + :padding-right 90}))} [react/view {:style {:padding 12 :background-color :white :border-radius 8}} (when group-chat [message-author-name message]) - [react/text - text]]])}))) + [rn-hl/hyperlink {:linkStyle {:color "#2980b9"} :on-press #(re-frame/dispatch [:show-link-dialog %1])} + [react/text + text]]]])}))) (views/defview messages-view [{:keys [chat-id group-chat]}] - (let [scroll-ref (atom nil) - messages (re-frame/subscribe [:get-chat-messages chat-id]) - current-public-key (re-frame/subscribe [:get-current-public-key])] - [react/view {:style {:flex 1 :background-color "#eef2f5"}} - [react/scroll-view {:onContentSizeChange #(.scrollToEnd @scroll-ref) :ref #(reset! scroll-ref %)} - [react/view {:style {:padding-vertical 60}} - (for [[index {:keys [from content message-id] :as message-obj}] (map-indexed vector (reverse @messages))] - ^{:key message-id} [message content (= from @current-public-key) (assoc message-obj :group-chat group-chat)])]]])) + (views/letsubs [chat-id* (atom nil) + scroll-ref (atom nil) + scroll-timer (atom nil) + scroll-height (atom nil)] + (let [_ (when (or (not @chat-id*) (not= @chat-id* chat-id)) + (reset! chat-id* chat-id) + (println "dirty hack") + (js/setTimeout #(when scroll-ref (.scrollToEnd @scroll-ref)) 400)) + messages (re-frame/subscribe [:get-chat-messages chat-id]) + current-public-key (re-frame/subscribe [:get-current-public-key])] + [react/view {:style {:flex 1 :background-color "#eef2f5"}} + [react/scroll-view {:scrollEventThrottle 16 + :on-scroll (fn [e] + (let [ne (.-nativeEvent e) + y (.-y (.-contentOffset ne))] + (when (zero? y) + (when @scroll-timer (js/clearTimeout @scroll-timer)) + (reset! scroll-timer (js/setTimeout #(re-frame/dispatch [:load-more-messages]) 300))) + (reset! scroll-height (+ y (.-height (.-layoutMeasurement ne)))))) + :on-content-size-change #(when (or (not @scroll-height) (< (- %2 @scroll-height) 500)) + (.scrollToEnd @scroll-ref)) + :ref #(reset! scroll-ref %)} + [react/view {:style {:padding-vertical 60}} + (for [[index {:keys [from content message-id] :as message-obj}] (map-indexed vector (reverse @messages))] + ^{:key message-id} [message content (= from @current-public-key) (assoc message-obj :group-chat group-chat)])]]]))) (views/defview status-view [] - [react/view {:style {:flex 1 :background-color "#eef2f5" :align-items :center :justify-content :center}} + [react/view {:style {:flex 1 :background-color "#eef2f5" :align-items :center :justify-content :center}} [react/text {:style {:font-size 18 :color "#939ba1"}} "Status.im"]]) (views/defview toolbar-chat-view [] - (views/letsubs [name [:chat :name] - chat-id [:get-current-chat-id] + (views/letsubs [name [:chat :name] + chat-id [:get-current-chat-id] pending-contact? [:current-contact :pending?] - public-key [:chat :public-key]] + public-key [:chat :public-key]] (let [chat-name (if (string/blank? name) (gfycat.core/generate-gfy public-key) - (or name;(get-contact-translated chat-id :name name) - "Chat name"))];(label :t/chat-name)))] + (or name ;(get-contact-translated chat-id :name name) + "Chat name"))] ;(label :t/chat-name)))] [react/view {:style {:height 64 :align-items :center :padding-horizontal 11 :justify-content :center}} [react/text {:style {:font-size 16 :color :black :font-weight "600"}} chat-name] (when pending-contact? [react/touchable-highlight {:on-press #(re-frame/dispatch [:add-pending-contact chat-id])} - [react/view ;style/add-contact + [react/view ;style/add-contact [react/text {:style {:font-size 14 :color "#939ba1" :margin-top 3}} "Add to contacts"]]])]))) - ;[react/text {:style {:font-size 14 :color "#939ba1" :margin-top 3}} - ;"Contact status not implemented"]]))) +;[react/text {:style {:font-size 14 :color "#939ba1" :margin-top 3}} +;"Contact status not implemented"]]))) -(views/defview chat-view [] - (views/letsubs [current-chat [:get-current-chat] - input-text [:chat :input-text] +(views/defview chat-text-input [] + (views/letsubs [input-text [:chat :input-text] inp-ref (atom nil)] + [react/view {:style {:height 90 :margin-horizontal 16 :margin-bottom 16 :background-color :white :border-radius 12 + :box-shadow "0 0.5px 4.5px 0 rgba(0, 0, 0, 0.04)"}} + [react/view {:style {:flex-direction :row :margin-horizontal 16 :margin-top 16 :flex 1 :margin-bottom 16}} + [react/view {:style {:flex 1}} + [react/text-input {:default-value (or input-text "") + :placeholder "Type a message..." + :auto-focus true + :multiline true + :blur-on-submit true + :style {:flex 1} + :ref #(reset! inp-ref %) + :on-key-press (fn [e] + (let [native-event (.-nativeEvent e) + key (.-key native-event)] + (when (= key "Enter") + (js/setTimeout #(do + (.clear @inp-ref) + (.focus @inp-ref)) 200) + (re-frame/dispatch [:send-current-message])))) + :on-change (fn [e] + (let [native-event (.-nativeEvent e) + text (.-text native-event)] + (re-frame/dispatch [:set-chat-input-text text])))}]] + [react/touchable-highlight {:on-press (fn [] + (js/setTimeout #(do (.clear @inp-ref)(.focus @inp-ref)) 200) + (re-frame/dispatch [:send-current-message]))} + [react/view {:style {:margin-left 16 :width 30 :height 30 :border-radius 15 :background-color "#eef2f5" :align-items :center + :justify-content :center}} + [icons/icon :icons/dropdown-up]]]]])) + +(views/defview chat-view [] + (views/letsubs [current-chat [:get-current-chat]] [react/view {:style {:flex 1 :background-color "#eef2f5"}} [toolbar-chat-view] [react/view {:style {:height 1 :background-color "#e8ebec" :margin-horizontal 16}}] [messages-view current-chat] - [react/view {:style {:height 90 :margin-horizontal 16 :margin-bottom 16 :background-color :white :border-radius 12 - :box-shadow "0 0.5px 4.5px 0 rgba(0, 0, 0, 0.04)"}} - [react/view {:style {:flex-direction :row :margin-horizontal 16 :margin-top 16 :flex 1 :margin-bottom 16}} - [react/view {:style {:flex 1}} - [react/text-input {:value (or input-text "") - :placeholder "Type a message..." - :auto-focus true - :multiline true - :blur-on-submit true - :style {:flex 1} - :ref #(reset! inp-ref %) - :on-key-press (fn [e] - (let [native-event (.-nativeEvent e) - key (.-key native-event)] - (when (= key "Enter") - (js/setTimeout #(.focus @inp-ref) 200) - (re-frame/dispatch [:send-current-message])))) - :on-change (fn [e] - (let [native-event (.-nativeEvent e) - text (.-text native-event)] - (re-frame/dispatch [:set-chat-input-text text])))}]] - [react/touchable-highlight {:on-press (fn [] - (js/setTimeout #(.focus @inp-ref) 200) - (re-frame/dispatch [:send-current-message]))} - [react/view {:style {:margin-left 16 :width 30 :height 30 :border-radius 15 :background-color "#eef2f5" :align-items :center - :justify-content :center}} - [icons/icon :icons/dropdown-up]]]]]])) + [chat-text-input]])) + (views/defview new-contact [] (views/letsubs [new-contact-identity [:get :contacts/new-identity] @@ -151,6 +179,7 @@ [react/view {:style {:height 90 :margin-horizontal 16 :margin-bottom 16 :background-color :white :border-radius 12 :box-shadow "0 0.5px 4.5px 0 rgba(0, 0, 0, 0.04)"}} [react/view {:style {:flex-direction :row :margin-horizontal 16 :margin-top 16}} + [react/text "#"] [react/view {:style {:flex 1}} [react/text-input {:placeholder "topic" :on-change (fn [e] diff --git a/src_front/status_desktop_front/ui/screens/events.cljs b/src_front/status_desktop_front/ui/screens/events.cljs index bc8e7b6..7a3a923 100644 --- a/src_front/status_desktop_front/ui/screens/events.cljs +++ b/src_front/status_desktop_front/ui/screens/events.cljs @@ -8,7 +8,8 @@ status-desktop-front.override.login status-desktop-front.override.account status-desktop-front.override.contacts - status-desktop-front.override.recieve-message)) + status-desktop-front.override.recieve-message + status-desktop-front.ui.screens.chat.events)) (handlers/register-handler-fx :create-desktop-account