Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e5db3758a | ||
|
|
47012b8c07 | ||
|
|
3b46d837ae | ||
|
|
94e89f65bc | ||
|
|
ca04e28df1 | ||
|
|
91039e89b0 | ||
|
|
661b6bc4bd | ||
|
|
2e4321483a | ||
|
|
b04cddd54c | ||
|
|
4b78f7dc8d | ||
|
|
808d06305e | ||
|
|
42acb2997a | ||
|
|
44df616c45 | ||
|
|
4c6b97093c | ||
|
|
9108585f12 | ||
|
|
0fed3a2469 | ||
|
|
00955fb9a3 | ||
|
|
380f24f46b | ||
|
|
875a37290d | ||
|
|
718bc363ad | ||
|
|
fa22e7fcba | ||
|
|
b49b43298b | ||
|
|
0ce2494246 | ||
|
|
b19788fba2 | ||
|
|
57d97b6667 | ||
|
|
723a911ec2 | ||
|
|
89139cf776 | ||
|
|
6632dae48e | ||
|
|
4f6a856052 | ||
|
|
9deb5dbf56 | ||
|
|
18252c1be6 | ||
|
|
24591328a0 | ||
|
|
05773c06ee | ||
|
|
66911f43d4 | ||
|
|
9c672323f3 | ||
|
|
cab969647d | ||
|
|
904d8cf96a | ||
|
|
6660224eb1 | ||
|
|
2e953baa67 | ||
|
|
4cee364958 | ||
|
|
a967239d69 | ||
|
|
7593a144c4 | ||
|
|
02d8209131 | ||
|
|
d3193fd958 | ||
|
|
043b254480 | ||
|
|
0997fb3ba4 | ||
|
|
c4328e6a30 | ||
|
|
66664692a6 | ||
|
|
03c16dd251 | ||
|
|
da923fe04e | ||
|
|
2fbf6518e7 | ||
|
|
a9c0427758 | ||
|
|
e9824a28bd | ||
|
|
7f6a5cb31f | ||
|
|
1a289d4ec7 | ||
|
|
156d27e8e1 | ||
|
|
392ecf7fdd | ||
|
|
a1469f8eb2 | ||
|
|
edcc107ec3 | ||
|
|
d54b5cc080 | ||
|
|
c188d840c5 | ||
|
|
dd253af0bb | ||
|
|
1c8c8fd7b1 | ||
|
|
34f8642fd8 | ||
|
|
f40fc9c6f1 | ||
|
|
c9b5496ec9 | ||
|
|
3256feee7c | ||
|
|
796bd4ac45 | ||
|
|
873db44f2e | ||
|
|
1ffd5a33a4 | ||
|
|
bb13230ba5 | ||
|
|
d19514fe09 | ||
|
|
b8d588a0ec | ||
|
|
ccc7b9b324 | ||
|
|
86b2cdc76a | ||
|
|
df58bed557 | ||
|
|
76c38f4092 | ||
|
|
c32bf4b827 | ||
|
|
ebd4b696f5 | ||
|
|
046b5ac9cf | ||
|
|
18aa57fb8e | ||
|
|
088f4c2de9 | ||
|
|
4ac9524398 | ||
|
|
5fb3d02921 | ||
|
|
a625a35e16 | ||
|
|
4ed84b1846 | ||
|
|
14ea177f9c | ||
|
|
bc7ef61855 | ||
|
|
43b598ee72 | ||
|
|
21a4016aa4 | ||
|
|
5baeffca8e | ||
|
|
d0ab22ab7e | ||
|
|
b200e90bcc | ||
|
|
bcaadc62f1 | ||
|
|
44931c642b | ||
|
|
5c262bcddb | ||
|
|
42739665fc | ||
|
|
097c16931e | ||
|
|
df87828d80 | ||
|
|
889027fffe | ||
|
|
8eee5fc318 | ||
|
|
317b54ad69 | ||
|
|
ada8f35cc3 | ||
|
|
7b12f2acae | ||
|
|
06750e92be | ||
|
|
d5ca9b6bbe | ||
|
|
6635ff42f2 | ||
|
|
3b22d0fb43 | ||
|
|
0702b9af79 | ||
|
|
b26ab3460e | ||
|
|
bcef86fee2 | ||
|
|
7a5871a03f | ||
|
|
5c0bd33697 | ||
|
|
220341e0be | ||
|
|
ceaa363f08 | ||
|
|
846d628a9d | ||
|
|
9ed89ac97d | ||
|
|
43da198c3f | ||
|
|
55d11d1a18 | ||
|
|
d2e8c5b52c | ||
|
|
115fb3f590 | ||
|
|
02a1c3597f | ||
|
|
6f10ff4d3e | ||
|
|
e289ad8968 | ||
|
|
043e218320 | ||
|
|
1cdcd298b0 |
@@ -1,4 +1,4 @@
|
||||
.PHONY: nix-add-gcroots clean nix-clean run-metro test release _list _fix-node-perms _tmpdir-mk _tmpdir-rm _install-hooks
|
||||
.PHONY: nix-add-gcroots clean nix-clean run-metro test release _list _fix-node-perms _tmpdir-rm
|
||||
|
||||
help: SHELL := /bin/sh
|
||||
help: ##@other Show this help
|
||||
@@ -118,10 +118,11 @@ _fix-node-perms: ##@prepare Fix permissions so that directory can be cleaned
|
||||
$(shell test -d node_modules && chmod -R 744 node_modules)
|
||||
$(shell test -d node_modules.tmp && chmod -R 744 node_modules.tmp)
|
||||
|
||||
_tmpdir-mk: SHELL := /bin/sh
|
||||
_tmpdir-mk: ##@prepare Create a TMPDIR for temporary files
|
||||
$(TMPDIR): SHELL := /bin/sh
|
||||
$(TMPDIR): ##@prepare Create a TMPDIR for temporary files
|
||||
@mkdir -p "$(TMPDIR)"
|
||||
# Make sure TMPDIR exists every time make is called
|
||||
_tmpdir-mk: $(TMPDIR)
|
||||
-include _tmpdir-mk
|
||||
|
||||
_tmpdir-rm: SHELL := /bin/sh
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
import "node-libs-react-native/globals";
|
||||
import "react-native-reanimated"
|
||||
import "./app/index.js";
|
||||
|
||||
@@ -206,58 +206,60 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
|
||||
|
||||
(def react-native-reanimated
|
||||
#js
|
||||
{:default #js
|
||||
{:createAnimatedComponent identity
|
||||
:eq nil
|
||||
:greaterOrEq nil
|
||||
:greaterThan nil
|
||||
:lessThan nil
|
||||
:lessOrEq nil
|
||||
:add nil
|
||||
:diff nil
|
||||
:divide nil
|
||||
:sub nil
|
||||
:multiply nil
|
||||
:abs nil
|
||||
:min nil
|
||||
:max nil
|
||||
:neq nil
|
||||
:and nil
|
||||
:or nil
|
||||
:not nil
|
||||
:set nil
|
||||
:startClock nil
|
||||
:stopClock nil
|
||||
:Value nil
|
||||
:Clock nil
|
||||
:debug nil
|
||||
:log nil
|
||||
:event nil
|
||||
:cond nil
|
||||
:block nil
|
||||
:interpolateNode nil
|
||||
:call nil
|
||||
:timing nil
|
||||
:onChange nil
|
||||
:View #js {}
|
||||
:Image #js {}
|
||||
:ScrollView #js {}
|
||||
:Text #js {}
|
||||
:Extrapolate #js {:CLAMP nil}
|
||||
:Code #js {}}
|
||||
:EasingNode #js
|
||||
{:bezier identity
|
||||
:linear identity}
|
||||
:clockRunning nil
|
||||
:useSharedValue (fn [])
|
||||
:useAnimatedStyle (fn [])
|
||||
:withTiming (fn [])
|
||||
:withDelay (fn [])
|
||||
:Easing #js {:bezier identity}
|
||||
:Keyframe (fn [])
|
||||
:SlideOutUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
|
||||
:SlideInUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
|
||||
:LinearTransition js/__STATUS_MOBILE_JS_IDENTITY_PROXY__})
|
||||
{:default #js
|
||||
{:createAnimatedComponent identity
|
||||
:eq nil
|
||||
:greaterOrEq nil
|
||||
:greaterThan nil
|
||||
:lessThan nil
|
||||
:lessOrEq nil
|
||||
:add nil
|
||||
:diff nil
|
||||
:divide nil
|
||||
:sub nil
|
||||
:multiply nil
|
||||
:abs nil
|
||||
:min nil
|
||||
:max nil
|
||||
:neq nil
|
||||
:and nil
|
||||
:or nil
|
||||
:not nil
|
||||
:set nil
|
||||
:startClock nil
|
||||
:stopClock nil
|
||||
:Value nil
|
||||
:Clock nil
|
||||
:debug nil
|
||||
:log nil
|
||||
:event nil
|
||||
:cond nil
|
||||
:block nil
|
||||
:interpolateNode nil
|
||||
:call nil
|
||||
:timing nil
|
||||
:onChange nil
|
||||
:View #js {}
|
||||
:Image #js {}
|
||||
:ScrollView #js {}
|
||||
:Text #js {}
|
||||
:Extrapolate #js {:CLAMP nil}
|
||||
:Code #js {}}
|
||||
:EasingNode #js
|
||||
{:bezier identity
|
||||
:linear identity}
|
||||
:clockRunning nil
|
||||
:useSharedValue (fn [])
|
||||
:useAnimatedStyle (fn [])
|
||||
:withTiming (fn [])
|
||||
:withDelay (fn [])
|
||||
:Easing #js {:bezier identity}
|
||||
:Keyframe (fn [])
|
||||
:enableLayoutAnimations (fn [])
|
||||
:SlideOutUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
|
||||
:SlideInUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
|
||||
:LinearTransition js/__STATUS_MOBILE_JS_IDENTITY_PROXY__})
|
||||
|
||||
(def react-native-gesture-handler
|
||||
#js
|
||||
{:default #js {}
|
||||
|
||||
+11
-1
@@ -1,4 +1,4 @@
|
||||
(ns quo2.components.banners.--tests--.banner-component-spec
|
||||
(ns quo2.components.banners.banner.component-spec
|
||||
(:require ["@testing-library/react-native" :as rtl]
|
||||
[quo2.components.banners.banner.view :as banner]
|
||||
[reagent.core :as reagent]))
|
||||
@@ -15,3 +15,13 @@
|
||||
(.toBeTruthy))
|
||||
(-> (js/expect (rtl/screen.getByText "5"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "banner component fires an event when pressed"
|
||||
(let [mock-fn (js/jest.fn)]
|
||||
(fn []
|
||||
(render-banner {:on-press mock-fn
|
||||
:pins-count "5"
|
||||
:latest-pin-text "this message"})
|
||||
(rtl/fireEvent.press (rtl/screen.getByText "this message"))
|
||||
(-> (js/expect mock-fn)
|
||||
(.toHaveBeenCalledTimes 1)))))
|
||||
@@ -3,17 +3,26 @@
|
||||
|
||||
|
||||
(def container
|
||||
{:width "100%"
|
||||
:height 50
|
||||
:background-color colors/primary-50-opa-20
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:padding-horizontal 20
|
||||
:padding-vertical 10})
|
||||
{:height 40
|
||||
:flex 1
|
||||
:background-color colors/primary-50-opa-20
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:padding-right 22
|
||||
:padding-left 20
|
||||
:padding-vertical 10})
|
||||
|
||||
(def counter
|
||||
{:padding-right 22
|
||||
:height 20
|
||||
:width 20
|
||||
{:flex 1
|
||||
:justify-content :center
|
||||
:align-items :center})
|
||||
:align-items :center})
|
||||
|
||||
(def icon
|
||||
{:flex 1
|
||||
:margin-right 10})
|
||||
|
||||
(defn text
|
||||
[hide-pin?]
|
||||
{:flex (if hide-pin? 16 15)
|
||||
:margin-right 10})
|
||||
|
||||
|
||||
@@ -3,22 +3,28 @@
|
||||
[quo2.components.counter.counter :as counter]
|
||||
[quo2.components.icon :as icons]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn banner
|
||||
[{:keys [show-pin? latest-pin-text pins-count on-press]}]
|
||||
[rn/touchable-opacity
|
||||
{:accessibility-label :pinned-banner
|
||||
:style style/container
|
||||
:active-opacity 1
|
||||
:on-press on-press}
|
||||
(when show-pin? [icons/icon :i/pin {:size 20}])
|
||||
[text/text
|
||||
{:number-of-lines 1
|
||||
:size :paragraph-2
|
||||
:style {:margin-left 10 :margin-right 50}}
|
||||
latest-pin-text]
|
||||
[rn/view
|
||||
{:accessibility-label :pins-count
|
||||
:style style/counter}
|
||||
(when (pos? pins-count) [counter/counter {:type :secondary} pins-count])]])
|
||||
[{:keys [hide-pin? latest-pin-text pins-count on-press]}]
|
||||
(when (pos? pins-count)
|
||||
[rn/touchable-opacity
|
||||
{:accessibility-label :pinned-banner
|
||||
:style style/container
|
||||
:active-opacity 1
|
||||
:on-press on-press}
|
||||
(when-not hide-pin?
|
||||
[rn/view {:style style/icon}
|
||||
[icons/icon :i/pin
|
||||
{:color (colors/theme-colors colors/neutral-100 colors/white)
|
||||
:size 20}]])
|
||||
[rn/view {:style (style/text hide-pin?)}
|
||||
[text/text
|
||||
{:number-of-lines 1
|
||||
:size :paragraph-2}
|
||||
latest-pin-text]]
|
||||
[rn/view
|
||||
{:accessibility-label :pins-count
|
||||
:style style/counter}
|
||||
(when (> pins-count 1) [counter/counter {:type :secondary} pins-count])]]))
|
||||
@@ -5,19 +5,8 @@
|
||||
[quo2.components.icon :as icons]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.fast-image :as fast-image]))
|
||||
|
||||
(defn community-icon-view
|
||||
[community-icon]
|
||||
[rn/view
|
||||
{:width 32
|
||||
:height 32}
|
||||
[fast-image/fast-image
|
||||
{:source {:uri community-icon}
|
||||
:style {:height 32
|
||||
:border-radius 16
|
||||
:width 32}}]])
|
||||
[quo2.components.community.icon :as community-icon]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn notification-view
|
||||
[{:keys [muted?
|
||||
@@ -54,27 +43,18 @@
|
||||
unread-messages?
|
||||
unread-mentions-count
|
||||
community-icon
|
||||
tokens
|
||||
background-color]}]
|
||||
tokens]}]
|
||||
[rn/view
|
||||
{:style (merge (style/community-card 16)
|
||||
{:margin-bottom 12
|
||||
:margin-horizontal 20})}
|
||||
{:margin-bottom 12})}
|
||||
[rn/touchable-highlight
|
||||
(merge {:style {:height 56
|
||||
:border-radius 16}}
|
||||
props)
|
||||
[rn/view {:flex 1}
|
||||
[rn/view
|
||||
{:flex-direction :row
|
||||
:border-radius 16
|
||||
:padding-horizontal 12
|
||||
:align-items :center
|
||||
:padding-vertical 8
|
||||
:background-color background-color}
|
||||
[rn/view]
|
||||
(when community-icon
|
||||
[community-icon-view community-icon])
|
||||
[rn/view (style/list-info-container)
|
||||
[community-icon/community-icon
|
||||
{:images community-icon} 32]
|
||||
[rn/view
|
||||
{:flex 1
|
||||
:margin-horizontal 12}
|
||||
@@ -109,39 +89,36 @@
|
||||
community-icon
|
||||
tokens
|
||||
locked?]}]
|
||||
[rn/view {:margin-bottom 20}
|
||||
[rn/touchable-highlight
|
||||
(merge {:underlay-color colors/primary-50-opa-5
|
||||
:style {:border-radius 12}}
|
||||
props)
|
||||
[rn/view {:flex 1}
|
||||
[rn/touchable-highlight
|
||||
(merge {:underlay-color (colors/theme-colors
|
||||
colors/neutral-5
|
||||
colors/neutral-95)
|
||||
:style {:border-radius 12}}
|
||||
props)
|
||||
[rn/view {:flex 1}
|
||||
[rn/view (style/membership-info-container)
|
||||
[community-icon/community-icon
|
||||
{:images community-icon} 32]
|
||||
[rn/view
|
||||
{:flex-direction :row
|
||||
:border-radius 16
|
||||
:align-items :center}
|
||||
{:flex 1
|
||||
:margin-left 12
|
||||
:justify-content :center}
|
||||
[text/text
|
||||
{:accessibility-label :chat-name-text
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail
|
||||
:weight :semi-bold
|
||||
:size :paragraph-1}
|
||||
name]]
|
||||
|
||||
(when community-icon
|
||||
[community-icon-view community-icon])
|
||||
[rn/view
|
||||
{:flex 1
|
||||
:margin-left 12
|
||||
:justify-content :center}
|
||||
[text/text
|
||||
{:accessibility-label :chat-name-text
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail
|
||||
:weight :semi-bold
|
||||
:size :paragraph-1}
|
||||
name]]
|
||||
|
||||
[rn/view
|
||||
{:justify-content :center
|
||||
:margin-right 16}
|
||||
(if (= status :gated)
|
||||
[community-view/permission-tag-container
|
||||
{:locked? locked?
|
||||
:tokens tokens}]
|
||||
[notification-view
|
||||
{:muted? muted?
|
||||
:unread-mentions-count unread-mentions-count
|
||||
:unread-messages? unread-messages?}])]]]]])
|
||||
[rn/view
|
||||
{:justify-content :center
|
||||
:margin-right 16}
|
||||
(if (= status :gated)
|
||||
[community-view/permission-tag-container
|
||||
{:locked? locked?
|
||||
:tokens tokens}]
|
||||
[notification-view
|
||||
{:muted? muted?
|
||||
:unread-mentions-count unread-mentions-count
|
||||
:unread-messages? unread-messages?}])]]]])
|
||||
|
||||
@@ -46,12 +46,12 @@
|
||||
^{:key id}
|
||||
[rn/view {:margin-right 8}
|
||||
[tag/tag
|
||||
{:id id
|
||||
:size 24
|
||||
:label tag-label
|
||||
:type :emoji
|
||||
:labelled true
|
||||
:resource resource}]])])
|
||||
{:id id
|
||||
:size 24
|
||||
:label tag-label
|
||||
:type :emoji
|
||||
:labelled? true
|
||||
:resource resource}]])])
|
||||
|
||||
(defn community-title
|
||||
[{:keys [title description size] :or {size :small}}]
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
:border-width 0
|
||||
:border-color :transparent
|
||||
:width size
|
||||
:height size}}]))
|
||||
:height size}}]))
|
||||
|
||||
@@ -77,19 +77,20 @@
|
||||
colors/white
|
||||
colors/neutral-90)})
|
||||
|
||||
(defn list-view-content-container
|
||||
(defn list-info-container
|
||||
[]
|
||||
{:flex-direction :row
|
||||
:border-radius 16
|
||||
:align-items :center
|
||||
:background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-90)})
|
||||
{:flex-direction :row
|
||||
:border-radius 16
|
||||
:padding-horizontal 12
|
||||
:align-items :center
|
||||
:padding-vertical 8})
|
||||
|
||||
(defn list-view-chat-icon
|
||||
(defn membership-info-container
|
||||
[]
|
||||
{:border-radius 32
|
||||
:padding 12})
|
||||
{:flex-direction :row
|
||||
:border-radius 16
|
||||
:align-items :center
|
||||
:height 48})
|
||||
|
||||
(defn community-title-description-container
|
||||
[margin-top]
|
||||
@@ -107,4 +108,4 @@
|
||||
[]
|
||||
{:position :absolute
|
||||
:top 8
|
||||
:right 8})
|
||||
:right 8})
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
(ns quo2.components.drawers.permission-context.--tests--.permission-context-component-spec
|
||||
(:require [quo2.components.drawers.permission-context.view :as permission-context]
|
||||
[react-native.core :as rn]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "permission context"
|
||||
(h/test
|
||||
(h/render [permission-context/view
|
||||
[rn/text
|
||||
{:accessibility-label :accessibility-id}
|
||||
"a sample label"]])
|
||||
(-> (js/expect (h/get-by-label-text :accessibility-id))
|
||||
(.toBeTruthy))))
|
||||
@@ -0,0 +1,16 @@
|
||||
(ns quo2.components.drawers.permission-context.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def radius 20)
|
||||
(def container
|
||||
{:padding-top 16
|
||||
:padding-bottom 48
|
||||
:padding-horizontal 20
|
||||
:shadow-offset {:width 0
|
||||
:height 2}
|
||||
:shadow-radius radius
|
||||
:border-top-left-radius radius
|
||||
:border-top-right-radius radius
|
||||
:elevation 2
|
||||
:shadow-opacity 1
|
||||
:shadow-color colors/shadow})
|
||||
@@ -0,0 +1,8 @@
|
||||
(ns quo2.components.drawers.permission-context.view
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.components.drawers.permission-context.style :as style]))
|
||||
|
||||
(defn view
|
||||
[children]
|
||||
[rn/view {:style style/container}
|
||||
children])
|
||||
@@ -7,12 +7,14 @@
|
||||
(defn themes
|
||||
[type]
|
||||
(case type
|
||||
:main {:icon-color (theme-colors colors/neutral-50 colors/neutral-10)
|
||||
:background (theme-colors colors/white colors/neutral-90)
|
||||
:text-color (theme-colors colors/neutral-100 colors/white)}
|
||||
:danger {:icon-color (theme-colors colors/danger-50 colors/danger-60)
|
||||
:background (theme-colors colors/white colors/neutral-90)
|
||||
:text-color (theme-colors colors/danger-50 colors/danger-60)}))
|
||||
:main {:icon-color (theme-colors colors/neutral-50 colors/neutral-10)
|
||||
:background (theme-colors colors/white colors/neutral-90)
|
||||
:text-color (theme-colors colors/neutral-100 colors/white)}
|
||||
:danger {:icon-color (theme-colors colors/danger-50 colors/danger-60)
|
||||
:background (theme-colors colors/white colors/neutral-90)
|
||||
:text-color (theme-colors colors/danger-50 colors/danger-60)}
|
||||
:transparent {:icon-color (theme-colors colors/neutral-50 colors/neutral-10)
|
||||
:text-color (theme-colors colors/neutral-100 colors/white)}))
|
||||
|
||||
(defn menu-item
|
||||
[{:keys [type title accessibility-label icon on-press style-props subtitle subtitle-color]
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(def ^:private themes
|
||||
{:container {:light {:background-color colors/white-opa-70}
|
||||
:dark {:background-color colors/neutral-80-opa-70}}
|
||||
:text {:light {:color colors/neutral-100}
|
||||
:dark {:color colors/white}}
|
||||
:icon {:light {:color colors/neutral-100}
|
||||
:dark {:color colors/white}}
|
||||
:action-container {:light {:background-color :colors/neutral-80-opa-5}
|
||||
:dark {:background-color :colors/white-opa-5}}})
|
||||
{:container {:dark {:background-color colors/white-opa-70}
|
||||
:light {:background-color colors/neutral-80-opa-70}}
|
||||
:text {:dark {:color colors/neutral-100}
|
||||
:light {:color colors/white}}
|
||||
:icon {:dark {:color colors/neutral-100}
|
||||
:light {:color colors/white}}
|
||||
:action-container {:dark {:background-color :colors/neutral-80-opa-5}
|
||||
:light {:background-color :colors/white-opa-5}}})
|
||||
|
||||
(defn- merge-theme-style
|
||||
[component-key styles]
|
||||
@@ -23,7 +23,9 @@
|
||||
|
||||
(defn toast-action-container
|
||||
[{:keys [on-press style]} & children]
|
||||
[rn/touchable-highlight {:on-press on-press}
|
||||
[rn/touchable-highlight
|
||||
{:on-press on-press
|
||||
:underlay-color :transparent}
|
||||
[into
|
||||
[rn/view
|
||||
{:style (merge
|
||||
@@ -40,7 +42,8 @@
|
||||
|
||||
(defn toast-undo-action
|
||||
[duration on-press]
|
||||
[toast-action-container {:on-press on-press}
|
||||
[toast-action-container
|
||||
{:on-press on-press :accessibility-label :toast-undo-action}
|
||||
[rn/view {:style {:margin-right 5}}
|
||||
[count-down-circle/circle-timer {:duration duration}]]
|
||||
[text/text
|
||||
@@ -63,7 +66,10 @@
|
||||
[rn/view {:style {:padding 2}} left]
|
||||
[rn/view {:style {:padding 4 :flex 1}}
|
||||
[text/text
|
||||
{:size :paragraph-2 :weight :medium :style (merge-theme-style :text {})}
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (merge-theme-style :text {})
|
||||
:accessibility-label :toast-content}
|
||||
middle]]
|
||||
(when right right)]])
|
||||
|
||||
|
||||
+137
-130
@@ -28,28 +28,6 @@
|
||||
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)}}
|
||||
[notification-dot]])
|
||||
|
||||
(defn tabs
|
||||
[{:keys [default-active on-change style]}]
|
||||
(let [active-tab-id (reagent/atom default-active)]
|
||||
(fn [{:keys [data size] :or {size default-tab-size}}]
|
||||
[rn/view (merge {:flex-direction :row} style)
|
||||
(doall
|
||||
(for [{:keys [label id notification-dot? accessibility-label]} data]
|
||||
^{:key id}
|
||||
[rn/view {:style {:margin-right (if (= size default-tab-size) 12 8)}}
|
||||
(when notification-dot?
|
||||
[indicator])
|
||||
[tab/tab
|
||||
{:id id
|
||||
:size size
|
||||
:accessibility-label accessibility-label
|
||||
:active (= id @active-tab-id)
|
||||
:on-press (fn []
|
||||
(reset! active-tab-id id)
|
||||
(when on-change
|
||||
(on-change id)))}
|
||||
label]]))])))
|
||||
|
||||
(defn- calculate-fade-end-percentage
|
||||
[{:keys [offset-x content-width layout-width max-fade-percentage]}]
|
||||
(let [fade-percentage (max max-fade-percentage
|
||||
@@ -60,30 +38,35 @@
|
||||
0.99
|
||||
(utils.number/naive-round fade-percentage 2))))
|
||||
|
||||
(defn scrollable-tabs
|
||||
"Just like the component `tabs`, displays horizontally scrollable tabs with
|
||||
extra options to control if/how the end of the scroll view fades.
|
||||
|
||||
Tabs are rendered using ReactNative's FlatList, which offers the convenient
|
||||
`scrollToIndex` method. FlatList accepts VirtualizedList and ScrollView props,
|
||||
and so does this component.
|
||||
|
||||
Usage:
|
||||
[tabs/scrollable-tabs
|
||||
{:scroll-on-press? true
|
||||
:fade-end? true
|
||||
:on-change #(...)
|
||||
:default-active :tab-a
|
||||
:data [{:id :tab-a :label \"Tab A\"}
|
||||
{:id :tab-b :label \"Tab B\"}]}]]
|
||||
|
||||
(defn tabs
|
||||
"Usage:
|
||||
{:type :icon/:emoji/:label
|
||||
:component tag/tab
|
||||
:size 32/24
|
||||
:on-press fn
|
||||
:blurred? true/false
|
||||
:labelled? true/false
|
||||
:disabled? true/false
|
||||
:scrollable? false
|
||||
:scroll-on-press? true
|
||||
:fade-end? true
|
||||
:on-change fn
|
||||
:default-active tag-id
|
||||
:data [{:id :label \"\" :resource \"url\"}
|
||||
{:id :label \"\" :resource \"url\"}]}
|
||||
Opts:
|
||||
- `size` number
|
||||
- `scroll-on-press?` When non-nil, clicking on a tab centers it the middle
|
||||
- `component` this is to determine which component is to be rendered since the
|
||||
logic in this view is shared between tab and tag component
|
||||
- `blurred` boolean: use to determine border color if the background is blurred
|
||||
- `type` can be icon or emoji with or without a tag label
|
||||
- `labelled` boolean: is true if tag has label else false
|
||||
- `size` number
|
||||
- `scroll-on-press?` When non-nil, clicking on a tag centers it the middle
|
||||
(with animation enabled).
|
||||
- `fade-end?` When non-nil, causes the end of the scrollable view to fade out.
|
||||
- `fade-end-percentage` Percentage where fading starts relative to the total
|
||||
- `fade-end?` When non-nil, causes the end of the scrollable view to fade out.
|
||||
- `fade-end-percentage` Percentage where fading starts relative to the total
|
||||
layout width of the `flat-list` data."
|
||||
|
||||
[{:keys [default-active fade-end-percentage]
|
||||
:or {fade-end-percentage 0.8}}]
|
||||
(let [active-tab-id (reagent/atom default-active)
|
||||
@@ -97,99 +80,123 @@
|
||||
on-scroll
|
||||
scroll-event-throttle
|
||||
scroll-on-press?
|
||||
scrollable?
|
||||
style
|
||||
size
|
||||
blur?
|
||||
override-theme]
|
||||
:or {fade-end-percentage fade-end-percentage
|
||||
fade-end? false
|
||||
scroll-event-throttle 64
|
||||
scrollable? false
|
||||
scroll-on-press? false
|
||||
size default-tab-size}
|
||||
:as props}]
|
||||
(let [maybe-mask-wrapper (if fade-end?
|
||||
[masked-view/masked-view
|
||||
{:mask-element
|
||||
(reagent/as-element
|
||||
[linear-gradient/linear-gradient
|
||||
{:colors [:black :transparent]
|
||||
:locations [(get @fading :fade-end-percentage) 1]
|
||||
:start {:x 0 :y 0}
|
||||
:end {:x 1 :y 0}
|
||||
:pointer-events :none
|
||||
:style {:width "100%"
|
||||
:height "100%"}}])}]
|
||||
[:<>])]
|
||||
(conj
|
||||
maybe-mask-wrapper
|
||||
[rn/flat-list
|
||||
(merge
|
||||
(dissoc props
|
||||
:default-active
|
||||
:fade-end-percentage
|
||||
:fade-end?
|
||||
:on-change
|
||||
:scroll-on-press?
|
||||
:size)
|
||||
(when scroll-on-press?
|
||||
{: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
|
||||
:scroll-event-throttle scroll-event-throttle
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:data data
|
||||
:key-fn (comp str :id)
|
||||
:on-scroll-to-index-failed identity
|
||||
:on-scroll (fn [^js e]
|
||||
(when fade-end?
|
||||
(let [offset-x (oget
|
||||
e
|
||||
"nativeEvent.contentOffset.x")
|
||||
content-width (oget
|
||||
e
|
||||
"nativeEvent.contentSize.width")
|
||||
layout-width
|
||||
(oget e "nativeEvent.layoutMeasurement.width")
|
||||
new-percentage
|
||||
(calculate-fade-end-percentage
|
||||
{:offset-x offset-x
|
||||
:content-width content-width
|
||||
:layout-width layout-width
|
||||
:max-fade-percentage fade-end-percentage})]
|
||||
;; Avoid unnecessary re-rendering.
|
||||
(when (not= new-percentage
|
||||
(get @fading :fade-end-percentage))
|
||||
(swap! fading assoc
|
||||
:fade-end-percentage
|
||||
new-percentage))))
|
||||
(when on-scroll
|
||||
(on-scroll e)))
|
||||
:render-fn (fn [{:keys [id label]} index]
|
||||
[rn/view
|
||||
{:style {:margin-right (if (= size default-tab-size)
|
||||
12
|
||||
8)
|
||||
:padding-right (when (= index
|
||||
(dec (count data)))
|
||||
(get-in props
|
||||
[:style
|
||||
:padding-left]))}}
|
||||
[tab/tab
|
||||
{:id id
|
||||
:size size
|
||||
:override-theme override-theme
|
||||
:blur? blur?
|
||||
:active (= id @active-tab-id)
|
||||
:on-press (fn [id]
|
||||
(reset! active-tab-id id)
|
||||
(when scroll-on-press?
|
||||
(.scrollToIndex ^js
|
||||
@flat-list-ref
|
||||
#js
|
||||
{:animated true
|
||||
:index index
|
||||
:viewPosition
|
||||
0.5}))
|
||||
(when on-change
|
||||
(on-change id)))}
|
||||
label]])})])))))
|
||||
(if scrollable?
|
||||
(let [maybe-mask-wrapper (if fade-end?
|
||||
[masked-view/masked-view
|
||||
{:mask-element
|
||||
(reagent/as-element
|
||||
[linear-gradient/linear-gradient
|
||||
{:colors [:black :transparent]
|
||||
:locations [(get @fading :fade-end-percentage) 1]
|
||||
:start {:x 0 :y 0}
|
||||
:end {:x 1 :y 0}
|
||||
:pointer-events :none
|
||||
:style {:width "100%"
|
||||
:height "100%"}}])}]
|
||||
[:<>])]
|
||||
(conj
|
||||
maybe-mask-wrapper
|
||||
[rn/flat-list
|
||||
(merge
|
||||
(dissoc props
|
||||
:default-active
|
||||
:fade-end-percentage
|
||||
:fade-end?
|
||||
:on-change
|
||||
:scroll-on-press?
|
||||
:size)
|
||||
(when scroll-on-press?
|
||||
{: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
|
||||
:scroll-event-throttle scroll-event-throttle
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:data data
|
||||
:key-fn (comp str :id)
|
||||
:on-scroll-to-index-failed identity
|
||||
:on-scroll (fn [^js e]
|
||||
(when fade-end?
|
||||
(let [offset-x (oget
|
||||
e
|
||||
"nativeEvent.contentOffset.x")
|
||||
content-width
|
||||
(oget
|
||||
e
|
||||
"nativeEvent.contentSize.width")
|
||||
layout-width
|
||||
(oget e
|
||||
"nativeEvent.layoutMeasurement.width")
|
||||
new-percentage
|
||||
(calculate-fade-end-percentage
|
||||
{:offset-x offset-x
|
||||
:content-width content-width
|
||||
:layout-width layout-width
|
||||
:max-fade-percentage fade-end-percentage})]
|
||||
;; Avoid unnecessary re-rendering.
|
||||
(when (not= new-percentage
|
||||
(get @fading :fade-end-percentage))
|
||||
(swap! fading assoc
|
||||
:fade-end-percentage
|
||||
new-percentage))))
|
||||
(when on-scroll
|
||||
(on-scroll e)))
|
||||
:render-fn (fn [{:keys [id label]} index]
|
||||
[rn/view
|
||||
{:style {:margin-right (if (= size default-tab-size)
|
||||
12
|
||||
8)
|
||||
:padding-right (when (= index
|
||||
(dec (count data)))
|
||||
(get-in props
|
||||
[:style
|
||||
:padding-left]))}}
|
||||
[tab/tab
|
||||
{:id id
|
||||
:size size
|
||||
:override-theme override-theme
|
||||
:blur? blur?
|
||||
:active (= id @active-tab-id)
|
||||
:on-press (fn [id]
|
||||
(reset! active-tab-id id)
|
||||
(when scroll-on-press?
|
||||
(.scrollToIndex
|
||||
^js
|
||||
@flat-list-ref
|
||||
#js
|
||||
{:animated true
|
||||
:index index
|
||||
:viewPosition
|
||||
0.5}))
|
||||
(when on-change
|
||||
(on-change id)))}
|
||||
label]])})]))
|
||||
[rn/view (merge {:flex-direction :row} style)
|
||||
(doall
|
||||
(for [{:keys [label id notification-dot? accessibility-label]} data]
|
||||
^{:key id}
|
||||
[rn/view {:style {:margin-right (if (= size default-tab-size) 12 8)}}
|
||||
(when notification-dot?
|
||||
[indicator])
|
||||
[tab/tab
|
||||
{:id id
|
||||
:size size
|
||||
:accessibility-label accessibility-label
|
||||
:active (= id @active-tab-id)
|
||||
:on-press (fn []
|
||||
(reset! active-tab-id id)
|
||||
(when on-change
|
||||
(on-change id)))}
|
||||
label]]))]))))
|
||||
|
||||
@@ -16,25 +16,21 @@
|
||||
{:width size})))
|
||||
|
||||
(defn base-tag
|
||||
"opts
|
||||
{:type :icon/:emoji/:label/:permission
|
||||
:size 32/24}
|
||||
:labelled true"
|
||||
[_]
|
||||
(fn [{:keys [id size disabled border-color border-width background-color on-press
|
||||
accessibility-label label type]
|
||||
(fn [{:keys [id size disabled? border-color border-width background-color on-press
|
||||
accessibility-label labelled? type]
|
||||
:or {size 32}} children]
|
||||
[rn/touchable-without-feedback
|
||||
(merge {:disabled disabled
|
||||
(merge {:disabled disabled?
|
||||
:accessibility-label accessibility-label}
|
||||
(when on-press
|
||||
{:on-press #(on-press id)}))
|
||||
[rn/view
|
||||
{:style (merge (style-container size
|
||||
disabled
|
||||
disabled?
|
||||
border-color
|
||||
border-width
|
||||
background-color
|
||||
label
|
||||
labelled?
|
||||
type))}
|
||||
children]]))
|
||||
|
||||
@@ -68,26 +68,40 @@
|
||||
label])])
|
||||
|
||||
(defn tag
|
||||
"opts
|
||||
{:type :icon/:emoji/:label
|
||||
:size 32/24
|
||||
:on-press fn
|
||||
:blurred? true/false
|
||||
:resource icon/image
|
||||
:labelled? true/false
|
||||
:disabled? true/false}
|
||||
|
||||
opts
|
||||
- `blurred` boolean: use to determine border color if the background is blurred
|
||||
- `type` can be icon or emoji with or without a tag label
|
||||
- `labelled` boolean: is true if tag has label else false"
|
||||
[_ _]
|
||||
(fn [{:keys [id on-press disabled size resource active accessibility-label
|
||||
label type labelled blurred icon-color]
|
||||
(fn [{:keys [id on-press disabled? size resource active accessibility-label
|
||||
label type labelled? blurred? icon-color]
|
||||
:or {size 32}}]
|
||||
(let [state (cond disabled :disabled
|
||||
active :active
|
||||
:else :default)
|
||||
(let [state (cond disabled? :disabled
|
||||
active :active
|
||||
:else :default)
|
||||
{:keys [border-color blurred-border-color text-color]}
|
||||
(get-in themes [(theme/get-theme) state])]
|
||||
[base-tag/base-tag
|
||||
{:id id
|
||||
:size size
|
||||
:border-width 1
|
||||
:border-color (if blurred
|
||||
blurred-border-color
|
||||
border-color)
|
||||
:on-press on-press
|
||||
:accessibility-label accessibility-label
|
||||
:disabled disabled
|
||||
:type type
|
||||
:label label}
|
||||
[tag-resources size type resource icon-color label text-color labelled]])))
|
||||
[rn/view {:style {:align-items :center}}
|
||||
[base-tag/base-tag
|
||||
{:id id
|
||||
:size size
|
||||
:border-width 1
|
||||
:border-color (if blurred?
|
||||
blurred-border-color
|
||||
border-color)
|
||||
:on-press on-press
|
||||
:accessibility-label accessibility-label
|
||||
:disabled? disabled?
|
||||
:type type
|
||||
:labelled? (if (= type :label) true labelled?)}
|
||||
[tag-resources size type resource icon-color label text-color labelled?]]])))
|
||||
|
||||
|
||||
@@ -1,29 +1,171 @@
|
||||
(ns quo2.components.tags.tags
|
||||
(:require [quo2.components.tags.tag :as tag]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
(:require [reagent.core :as reagent]
|
||||
[quo.react-native :as rn]
|
||||
[oops.core :refer [oget]]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.utils.core :as utils]
|
||||
[quo2.components.tags.tag :as tag]
|
||||
[utils.number :as number-utils]))
|
||||
|
||||
(def default-tab-size 32)
|
||||
|
||||
(defn calculate-fade-end-percentage
|
||||
[{:keys [offset-x content-width layout-width max-fade-percentage]}]
|
||||
(let [fade-percentage (max max-fade-percentage
|
||||
(/ (+ layout-width offset-x)
|
||||
content-width))]
|
||||
;; Truncate to avoid unnecessary rendering.
|
||||
(if (> fade-percentage 0.99)
|
||||
0.99
|
||||
(number-utils/naive-round fade-percentage 2))))
|
||||
|
||||
(defn tags
|
||||
[{:keys [default-active on-change]}]
|
||||
(let [active-tab-id (reagent/atom default-active)]
|
||||
(fn [{:keys [data size type labelled disabled blurred icon-color] :or {size 32}}]
|
||||
(let [active-id @active-tab-id]
|
||||
[rn/view {:flex-direction :row}
|
||||
(for [{:keys [tag-label id resource]} data]
|
||||
^{:key id}
|
||||
[rn/view {:margin-right 8}
|
||||
[tag/tag
|
||||
(merge {:id id
|
||||
:size size
|
||||
:type type
|
||||
:label (if labelled tag-label (when (= type :label) tag-label))
|
||||
:active (= id active-id)
|
||||
:disabled disabled
|
||||
:blurred blurred
|
||||
:icon-color icon-color
|
||||
:labelled (if (= type :label) true labelled)
|
||||
:resource (if (= type :icon)
|
||||
:i/placeholder
|
||||
resource)
|
||||
:on-press #(do (reset! active-tab-id %)
|
||||
(when on-change (on-change %)))})]])]))))
|
||||
"Usage:
|
||||
{:type :icon/:emoji/:label
|
||||
:component tag/tab
|
||||
:size 32/24
|
||||
:on-press fn
|
||||
:blurred? true/false
|
||||
:labelled? true/false
|
||||
:disabled? true/false
|
||||
:scroll-on-press? true
|
||||
:scrollable? false
|
||||
:fade-end? true
|
||||
:on-change fn
|
||||
:default-active tag-id
|
||||
:data [{:id :label \"\" :resource \"url\"}
|
||||
{:id :label \"\" :resource \"url\"}]}
|
||||
Opts:
|
||||
- `component` this is to determine which component is to be rendered since the
|
||||
logic in this view is shared between tab and tag component
|
||||
- `blurred` boolean: use to determine border color if the background is blurred
|
||||
- `type` can be icon or emoji with or without a tag label
|
||||
- `labelled` boolean: is true if tag has label else false
|
||||
- `size` number
|
||||
- `scroll-on-press?` When non-nil, clicking on a tag centers it the middle
|
||||
(with animation enabled).
|
||||
- `fade-end?` When non-nil, causes the end of the scrollable view to fade out.
|
||||
- `fade-end-percentage` Percentage where fading starts relative to the total
|
||||
layout width of the `flat-list` data."
|
||||
|
||||
[{:keys [default-active fade-end-percentage]
|
||||
:or {fade-end-percentage 0.8}}]
|
||||
(let [active-tab-id (reagent/atom default-active)
|
||||
fading (reagent/atom {:fade-end-percentage fade-end-percentage})
|
||||
flat-list-ref (atom nil)]
|
||||
(fn
|
||||
[{:keys [data
|
||||
fade-end-percentage
|
||||
fade-end?
|
||||
on-change
|
||||
on-scroll
|
||||
scroll-event-throttle
|
||||
scrollable?
|
||||
scroll-on-press?
|
||||
size
|
||||
type
|
||||
labelled?
|
||||
disabled?
|
||||
blurred?
|
||||
icon-color]
|
||||
:or {fade-end-percentage fade-end-percentage
|
||||
fade-end? false
|
||||
scroll-event-throttle 64
|
||||
scrollable? false
|
||||
scroll-on-press? false
|
||||
size default-tab-size}
|
||||
:as props}]
|
||||
(let [maybe-mask-wrapper (if fade-end?
|
||||
[react/masked-view
|
||||
{:mask-element (reagent/as-element
|
||||
[react/linear-gradient
|
||||
{:colors [:black :transparent]
|
||||
:locations [(get @fading :fade-end-percentage)
|
||||
1]
|
||||
:start {:x 0 :y 0}
|
||||
:end {:x 1 :y 0}
|
||||
:pointer-events :none
|
||||
:style {:width "100%"
|
||||
:height "100%"}}])}]
|
||||
[:<>])]
|
||||
(if scrollable?
|
||||
(conj
|
||||
maybe-mask-wrapper
|
||||
[rn/flat-list
|
||||
(merge (dissoc props
|
||||
:default-active
|
||||
:fade-end-percentage
|
||||
:fade-end?
|
||||
:on-change
|
||||
:scroll-on-press?
|
||||
:size)
|
||||
(when scroll-on-press?
|
||||
{:initial-scroll-index (utils/first-index #(= @active-tab-id (:id %)) data)})
|
||||
{:ref #(reset! flat-list-ref %)
|
||||
:extra-data (str @active-tab-id)
|
||||
:horizontal true
|
||||
:scroll-event-throttle scroll-event-throttle
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:data data
|
||||
:key-fn (comp str :id)
|
||||
:on-scroll (fn [^js e]
|
||||
(when fade-end?
|
||||
(let [offset-x (oget e "nativeEvent.contentOffset.x")
|
||||
content-width (oget e "nativeEvent.contentSize.width")
|
||||
layout-width (oget e "nativeEvent.layoutMeasurement.width")
|
||||
new-percentage (calculate-fade-end-percentage
|
||||
{:offset-x offset-x
|
||||
:content-width content-width
|
||||
:layout-width layout-width
|
||||
:max-fade-percentage fade-end-percentage})]
|
||||
;; Avoid unnecessary re-rendering.
|
||||
(when (not= new-percentage (get @fading :fade-end-percentage))
|
||||
(swap! fading assoc :fade-end-percentage new-percentage))))
|
||||
(when on-scroll
|
||||
(on-scroll e)))
|
||||
:render-fn (fn [{:keys [id label resource]} index]
|
||||
[rn/view
|
||||
{:style {:margin-right (if (= size default-tab-size) 12 8)
|
||||
:padding-right (when (= index (dec (count data)))
|
||||
(get-in props [:style :padding-left]))}}
|
||||
[tag/tag
|
||||
{:id id
|
||||
:size size
|
||||
:active (= id @active-tab-id)
|
||||
:resource resource
|
||||
:blurred? blurred?
|
||||
:icon-color icon-color
|
||||
:disabled? disabled?
|
||||
:label label
|
||||
:type type
|
||||
:labelled? labelled?
|
||||
:on-press (fn [id]
|
||||
(reset! active-tab-id id)
|
||||
(when scroll-on-press?
|
||||
(.scrollToIndex @flat-list-ref
|
||||
#js
|
||||
{:animated true
|
||||
:index index
|
||||
:viewPosition 0.5}))
|
||||
(when on-change
|
||||
(on-change id)))}
|
||||
label]])})])
|
||||
[rn/view {:style {:flex-direction :row}}
|
||||
(for [{:keys [label id resource]} data]
|
||||
^{:key id}
|
||||
[rn/view {:style {:margin-right 8}}
|
||||
[tag/tag
|
||||
(merge {:id id
|
||||
:size size
|
||||
:type type
|
||||
:label (if labelled? label (when (= type :label) label))
|
||||
:active (= id active-tab-id)
|
||||
:disabled? disabled?
|
||||
:blurred? blurred?
|
||||
:icon-color icon-color
|
||||
:labelled? (if (= type :label) true labelled?)
|
||||
:resource (if (= type :icon)
|
||||
:i/placeholder
|
||||
resource)
|
||||
:on-press #(do (reset! active-tab-id %)
|
||||
(when on-change (on-change %)))})]])])))))
|
||||
|
||||
@@ -78,7 +78,6 @@
|
||||
(def audio-tag quo2.components.tags.context-tags/audio-tag)
|
||||
(def community-tag quo2.components.tags.context-tags/community-tag)
|
||||
(def tabs quo2.components.tabs.tabs/tabs)
|
||||
(def scrollable-tabs quo2.components.tabs.tabs/scrollable-tabs)
|
||||
(def account-selector quo2.components.tabs.account-selector/account-selector)
|
||||
(def floating-shell-button quo2.components.navigation.floating-shell-button/floating-shell-button)
|
||||
(def status-tag quo2.components.tags.status-tags/status-tag)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
(ns quo2.core-spec
|
||||
(:require [quo2.components.banners.--tests--.banner-component-spec]
|
||||
(:require [quo2.components.banners.banner.component-spec]
|
||||
[quo2.components.buttons.--tests--.buttons-component-spec]
|
||||
[quo2.components.counter.--tests--.counter-component-spec]
|
||||
[quo2.components.dividers.--tests--.divider-label-component-spec]
|
||||
[quo2.components.drawers.--tests--.action-drawers-component-spec]
|
||||
[quo2.components.drawers.permission-context.--tests--.permission-context-component-spec]
|
||||
[quo2.components.markdown.--tests--.text-component-spec]
|
||||
[quo2.components.selectors.--tests--.selectors-component-spec]
|
||||
[quo2.components.selectors.filter.component-spec]))
|
||||
|
||||
@@ -101,4 +101,4 @@
|
||||
[f]
|
||||
(let [fn-ref (use-ref f)]
|
||||
(oops/oset! fn-ref "current" f)
|
||||
(use-effect-once (fn [] #((oops/oget fn-ref "current"))))))
|
||||
(use-effect-once (fn [] (fn [] (oops/ocall! fn-ref "current"))))))
|
||||
|
||||
@@ -54,11 +54,13 @@
|
||||
;; Helper functions
|
||||
(defn get-shared-value
|
||||
[anim]
|
||||
(.-value anim))
|
||||
(when anim
|
||||
(.-value anim)))
|
||||
|
||||
(defn set-shared-value
|
||||
[anim val]
|
||||
(set! (.-value anim) val))
|
||||
(when anim
|
||||
(set! (.-value anim) val)))
|
||||
|
||||
(defn kebab-case->camelCase
|
||||
[k]
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
[status-im2.contexts.chat.messages.delete-message-for-me.events :as delete-for-me]
|
||||
[status-im2.contexts.chat.messages.delete-message.events :as delete-message]
|
||||
[status-im2.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]))
|
||||
[taoensso.timbre :as log]
|
||||
status-im2.common.bottom-sheet.view))
|
||||
|
||||
(defn chats
|
||||
[]
|
||||
@@ -220,11 +221,17 @@
|
||||
|
||||
(rf/defn close-chat
|
||||
{:events [:close-chat]}
|
||||
[{:keys [db] :as cofx}]
|
||||
[{:keys [db] :as cofx} navigate-to-shell?]
|
||||
(when-let [chat-id (:current-chat-id db)]
|
||||
(chat.state/reset-visible-item)
|
||||
(rf/merge cofx
|
||||
{:db (dissoc db :current-chat-id)}
|
||||
(merge
|
||||
{:db (dissoc db :current-chat-id)}
|
||||
(let [community-id (get-in db [:chats chat-id :community-id])]
|
||||
;; When navigating back from community chat to community, update switcher card
|
||||
(when (and community-id (not navigate-to-shell?))
|
||||
{:dispatch [:shell/add-switcher-card
|
||||
:community {:community-id community-id}]})))
|
||||
(delete-for-me/sync-all)
|
||||
(delete-message/send-all)
|
||||
(offload-messages chat-id))))
|
||||
@@ -243,7 +250,8 @@
|
||||
[{:keys [db now] :as cofx} chat-id]
|
||||
(rf/merge cofx
|
||||
{:clear-message-notifications
|
||||
[[chat-id] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
|
||||
[[chat-id] (get-in db [:multiaccount :remote-push-notifications-enabled?])]
|
||||
:dispatch [:shell/close-switcher-card chat-id]}
|
||||
(deactivate-chat chat-id)
|
||||
(offload-messages chat-id)))
|
||||
|
||||
@@ -268,7 +276,7 @@
|
||||
(navigation/change-tab :chat)
|
||||
(when-not (= (:view-id db) :community)
|
||||
(navigation/pop-to-root-tab :chat-stack))
|
||||
(close-chat)
|
||||
(close-chat false)
|
||||
(force-close-chat chat-id)
|
||||
(fn [{:keys [db]}]
|
||||
{:db (assoc db :current-chat-id chat-id)})
|
||||
@@ -284,7 +292,7 @@
|
||||
{:dispatch [:navigate-to-nav2 :chat chat-id from-shell?]}
|
||||
(when-not (= (:view-id db) :community)
|
||||
(navigation/pop-to-root-tab :shell-stack))
|
||||
(close-chat)
|
||||
(close-chat false)
|
||||
(force-close-chat chat-id)
|
||||
(fn [{:keys [db]}]
|
||||
{:db (assoc db :current-chat-id chat-id)})
|
||||
@@ -311,7 +319,7 @@
|
||||
(assoc-in [:chats chat-id] chat)
|
||||
:always
|
||||
(update :chats-home-list conj chat-id))
|
||||
:dispatch [:chat.ui/navigate-to-chat chat-id]}))
|
||||
:dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]}))
|
||||
|
||||
(rf/defn navigate-to-user-pinned-messages
|
||||
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
|
||||
@@ -446,7 +454,7 @@
|
||||
:content (i18n/label :t/clear-history-confirmation-content)
|
||||
:confirm-button-text (i18n/label :t/clear-history-action)
|
||||
:on-accept #(do
|
||||
(re-frame/dispatch [:bottom-sheet/hide])
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
(re-frame/dispatch [:chat.ui/clear-history chat-id false]))}})
|
||||
|
||||
(rf/defn gaps-failed
|
||||
@@ -515,7 +523,7 @@
|
||||
:content (i18n/label :t/delete-chat-confirmation)
|
||||
:confirm-button-text (i18n/label :t/delete)
|
||||
:on-accept #(do
|
||||
(re-frame/dispatch [:bottom-sheet/hide])
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
(re-frame/dispatch [:chat.ui/remove-chat chat-id]))}})
|
||||
|
||||
(rf/defn decrease-unviewed-count
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
(ns status-im.chat.models.message-list
|
||||
(:require ["functional-red-black-tree" :as rb-tree]
|
||||
[status-im.constants :as constants]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.datetime :as datetime]))
|
||||
[utils.datetime :as datetime]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- add-datemark
|
||||
[{:keys [whisper-timestamp] :as msg}]
|
||||
@@ -20,6 +20,7 @@
|
||||
from
|
||||
outgoing
|
||||
whisper-timestamp
|
||||
deleted?
|
||||
deleted-for-me?
|
||||
albumize?]}]
|
||||
(-> {:whisper-timestamp whisper-timestamp
|
||||
@@ -29,6 +30,7 @@
|
||||
(or
|
||||
(= constants/message-type-private-group-system-message
|
||||
message-type)
|
||||
deleted?
|
||||
deleted-for-me?))
|
||||
:clock-value clock-value
|
||||
:type :message
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
[clojure.walk :as walk]
|
||||
[quo.design-system.colors :as colors]
|
||||
[re-frame.core :as re-frame]
|
||||
[i18n.i18n :as i18n]
|
||||
[status-im.async-storage.core :as async-storage]
|
||||
[status-im.bottom-sheet.core :as bottom-sheet]
|
||||
[status-im.constants :as constants]
|
||||
@@ -11,6 +12,7 @@
|
||||
[utils.re-frame :as rf]
|
||||
[status-im.utils.universal-links.core :as universal-links]
|
||||
[status-im2.contexts.activity-center.events :as activity-center]
|
||||
[status-im2.common.toasts.events :as toasts]
|
||||
[status-im2.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
@@ -110,15 +112,28 @@
|
||||
(rf/defn left
|
||||
{:events [::left]}
|
||||
[cofx response-js]
|
||||
(rf/merge cofx
|
||||
(handle-response cofx response-js)
|
||||
(navigation/pop-to-root-tab :chat-stack)
|
||||
(activity-center/notifications-fetch-unread-count)))
|
||||
(let [community-name (aget response-js "communities" 0 "name")]
|
||||
(rf/merge cofx
|
||||
(handle-response cofx response-js)
|
||||
(toasts/upsert {:icon :placeholder
|
||||
:icon-color (:positive-01 @colors/theme)
|
||||
:text (i18n/label :t/left-community {:community community-name})})
|
||||
(navigation/navigate-back)
|
||||
(activity-center/notifications-fetch-unread-count))))
|
||||
|
||||
(rf/defn joined
|
||||
{:events [::joined ::requested-to-join]}
|
||||
[cofx response-js]
|
||||
(handle-response cofx response-js))
|
||||
(let [[event-name _] (:event cofx)
|
||||
community-name (aget response-js "communities" 0 "name")]
|
||||
(rf/merge cofx
|
||||
(handle-response cofx response-js)
|
||||
(toasts/upsert {:icon :placeholder
|
||||
:icon-color (:positive-01 @colors/theme)
|
||||
:text (i18n/label (if (= event-name ::joined)
|
||||
:t/joined-community
|
||||
:t/requested-to-join-community)
|
||||
{:community community-name})}))))
|
||||
|
||||
(rf/defn export
|
||||
{:events [::export-pressed]}
|
||||
@@ -172,6 +187,7 @@
|
||||
(keys (get-in db [:communities community-id :chats])))]
|
||||
{:clear-message-notifications [community-chat-ids
|
||||
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
|
||||
:dispatch [:shell/close-switcher-card community-id]
|
||||
:json-rpc/call [{:method "wakuext_leaveCommunity"
|
||||
:params [community-id]
|
||||
:js-response true
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
(update :chats dissoc public-key)
|
||||
(update :chats-home-list disj public-key)
|
||||
(assoc-in [:contacts/contacts public-key :added] false))
|
||||
:dispatch [:shell/close-switcher-card public-key]
|
||||
:clear-message-notifications
|
||||
[[public-key] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
|
||||
(activity-center/notifications-fetch-unread-count)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[status-im.contact.block :as contact.block]
|
||||
[status-im.contact.db :as contact.db]
|
||||
[status-im.data-store.contacts :as contacts-store]
|
||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]))
|
||||
@@ -151,15 +150,6 @@
|
||||
#(re-frame/dispatch [:sanitize-messages-and-process-response %]))
|
||||
(navigation/navigate-back)))
|
||||
|
||||
(rf/defn switch-mutual-contact-requests-enabled
|
||||
{:events [:multiaccounts.ui/switch-mutual-contact-requests-enabled]}
|
||||
[cofx enabled?]
|
||||
(multiaccounts.update/multiaccount-update
|
||||
cofx
|
||||
:mutual-contact-enabled?
|
||||
enabled?
|
||||
nil))
|
||||
|
||||
(rf/defn set-search-query
|
||||
{:events [:contacts/set-search-query]}
|
||||
[{:keys [db] :as cofx} value]
|
||||
|
||||
@@ -86,8 +86,9 @@
|
||||
(get-in db [:contacts/contacts public-key]))
|
||||
|
||||
(defn added?
|
||||
([contact]
|
||||
(:added contact))
|
||||
([{:keys [contact-request-state]}]
|
||||
(or (= constants/contact-request-state-mutual contact-request-state)
|
||||
(= constants/contact-request-state-sent contact-request-state)))
|
||||
([db public-key]
|
||||
(added? (get-in db [:contacts/contacts public-key]))))
|
||||
|
||||
@@ -98,27 +99,28 @@
|
||||
(blocked? (get-in db [:contacts/contacts public-key]))))
|
||||
|
||||
(defn active?
|
||||
"Checks that the user is added to the contact and not blocked"
|
||||
"Checks that we are mutual contacts"
|
||||
([contact]
|
||||
(and (:added contact)
|
||||
(and (= constants/contact-request-state-mutual
|
||||
(:contact-request-state contact))
|
||||
(not (:blocked contact))))
|
||||
([db public-key]
|
||||
(active? (get-in db [:contacts/contacts public-key]))))
|
||||
|
||||
(defn enrich-contact
|
||||
([contact] (enrich-contact contact nil nil))
|
||||
([{:keys [added public-key] :as contact} setting own-public-key]
|
||||
([{:keys [public-key] :as contact} setting own-public-key]
|
||||
(cond-> (-> contact
|
||||
(dissoc :ens-verified-at :ens-verification-retries)
|
||||
(assoc :blocked? (:blocked contact)
|
||||
:active? (active? contact)
|
||||
:added? added)
|
||||
:added? (added? contact))
|
||||
(multiaccounts/contact-with-names))
|
||||
(and setting
|
||||
(not= public-key own-public-key)
|
||||
(or (= setting constants/profile-pictures-visibility-none)
|
||||
(and (= setting constants/profile-pictures-visibility-contacts-only)
|
||||
(not added))))
|
||||
(not (added? contact)))))
|
||||
(dissoc :images))))
|
||||
|
||||
(defn enrich-contacts
|
||||
|
||||
@@ -58,7 +58,8 @@
|
||||
status-im.wallet.custom-tokens.core
|
||||
status-im2.contexts.activity-center.events
|
||||
status-im2.contexts.shell.events
|
||||
[status-im2.navigation.events :as navigation]))
|
||||
[status-im2.navigation.events :as navigation]
|
||||
[react-native.background-timer :as timer]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:dismiss-keyboard
|
||||
@@ -324,3 +325,57 @@
|
||||
{::async-storage/get {:keys keys
|
||||
:cb #(re-frame/dispatch
|
||||
[:information-box-states-loaded hashes %])}}))
|
||||
|
||||
(rf/defn reset-bottom-sheet
|
||||
{:events [:bottom-sheet/reset]}
|
||||
[{:keys [db]}]
|
||||
{:db (assoc db
|
||||
:bottom-sheet/config
|
||||
{:content-height nil
|
||||
:show-bottom-sheet? nil
|
||||
:keyboard-was-shown? false
|
||||
:expanded? false
|
||||
:gesture-running? false
|
||||
:animation-delay 450})})
|
||||
|
||||
(re-frame/reg-fx
|
||||
:dismiss-bottom-sheet-fx
|
||||
(fn [[on-cancel animation-delay]]
|
||||
(re-frame/dispatch [:bottom-sheet/show-quo2-bottom-sheet false])
|
||||
(when (fn? on-cancel) (on-cancel))
|
||||
(timer/set-timeout
|
||||
(fn []
|
||||
(re-frame/dispatch [:bottom-sheet/hide-navigation-overlay])
|
||||
(re-frame/dispatch [:bottom-sheet/reset]))
|
||||
(or animation-delay 450))))
|
||||
|
||||
(rf/defn dismiss-bottom-sheet
|
||||
{:events [:dismiss-bottom-sheet]}
|
||||
[{:keys [db]} on-cancel]
|
||||
(let [animation-delay (get-in db [:bottom-sheet/config :animation-delay])]
|
||||
{:dismiss-bottom-sheet-fx [on-cancel animation-delay]}))
|
||||
|
||||
(rf/defn update-bottom-sheet-height
|
||||
{:events [:bottom-sheet/update-height]}
|
||||
[{:keys [db]} height]
|
||||
{:db (assoc-in db [:bottom-sheet/config :content-height] height)})
|
||||
|
||||
(rf/defn show-bottom-sheet
|
||||
{:events [:bottom-sheet/show-quo2-bottom-sheet]}
|
||||
[{:keys [db]} value]
|
||||
{:db (assoc-in db [:bottom-sheet/config :show-bottom-sheet?] value)})
|
||||
|
||||
(rf/defn keyboard-was-shown?
|
||||
{:events [:bottom-sheet/keyboard-was-shown?]}
|
||||
[{:keys [db]} value]
|
||||
{:db (assoc-in db [:bottom-sheet/config :keyboard-was-shown?] value)})
|
||||
|
||||
(rf/defn bottom-sheet-did-expand
|
||||
{:events [:bottom-sheet/did-expand]}
|
||||
[{:keys [db]} value]
|
||||
{:db (assoc-in db [:bottom-sheet/config :expanded?] value)})
|
||||
|
||||
(rf/defn bottom-sheet-gesture-running?
|
||||
{:events [:bottom-sheet/gesture-running?]}
|
||||
[{:keys [db]} value]
|
||||
{:db (assoc-in db [:bottom-sheet/config :gesture-running?] value)})
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
{:events [:navigate-chat-updated]}
|
||||
[cofx chat-id]
|
||||
(when (get-in cofx [:db :chats chat-id])
|
||||
(models.chat/navigate-to-chat cofx chat-id)))
|
||||
(models.chat/navigate-to-chat-nav2 cofx chat-id nil)))
|
||||
|
||||
(rf/defn handle-chat-removed
|
||||
{:events [:chat-removed]}
|
||||
@@ -71,7 +71,7 @@
|
||||
(rf/defn create-from-link
|
||||
[cofx {:keys [chat-id invitation-admin chat-name]}]
|
||||
(if (get-in cofx [:db :chats chat-id])
|
||||
{:dispatch [:chat.ui/navigate-to-chat chat-id]}
|
||||
{:dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]}
|
||||
{:json-rpc/call [{:method "wakuext_createGroupChatFromInvitation"
|
||||
:params [chat-name chat-id invitation-admin]
|
||||
:js-response true
|
||||
@@ -208,6 +208,11 @@
|
||||
[{:keys [db]} id]
|
||||
{:db (update db :group/selected-contacts conj id)})
|
||||
|
||||
(rf/defn clear-contacts
|
||||
{:events [:clear-contacts]}
|
||||
[{:keys [db]} id]
|
||||
{:db (assoc db :group/selected-contacts #{})})
|
||||
|
||||
(rf/defn deselect-participant
|
||||
{:events [:deselect-participant]}
|
||||
[{:keys [db]} id]
|
||||
|
||||
@@ -251,7 +251,7 @@
|
||||
(rf/dispatch-sync [:chat.ui/start-chat chat-id]) ;; start a new chat
|
||||
(rf-test/wait-for
|
||||
[:status-im.chat.models/one-to-one-chat-created]
|
||||
(rf/dispatch-sync [:chat.ui/navigate-to-chat chat-id])
|
||||
(rf/dispatch-sync [:chat.ui/navigate-to-chat-nav2 chat-id])
|
||||
(is (= chat-id @(rf/subscribe [:chats/current-chat-id])))
|
||||
(logout!)
|
||||
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not in
|
||||
@@ -276,7 +276,7 @@
|
||||
(rf/dispatch-sync [:chat.ui/start-chat chat-id]) ;; start a new chat
|
||||
(rf-test/wait-for
|
||||
[:status-im.chat.models/one-to-one-chat-created]
|
||||
(rf/dispatch-sync [:chat.ui/navigate-to-chat chat-id])
|
||||
(rf/dispatch-sync [:chat.ui/navigate-to-chat-nav2 chat-id])
|
||||
(is (= chat-id @(rf/subscribe [:chats/current-chat-id])))
|
||||
(is @(rf/subscribe [:chats/chat chat-id]))
|
||||
(rf/dispatch-sync [:chat.ui/remove-chat-pressed chat-id])
|
||||
@@ -307,7 +307,7 @@
|
||||
(rf/dispatch-sync [:chat.ui/start-chat chat-id]) ;; start a new chat
|
||||
(rf-test/wait-for
|
||||
[:status-im.chat.models/one-to-one-chat-created]
|
||||
(rf/dispatch-sync [:chat.ui/navigate-to-chat chat-id])
|
||||
(rf/dispatch-sync [:chat.ui/navigate-to-chat-nav2 chat-id])
|
||||
(is (= chat-id @(rf/subscribe [:chats/current-chat-id])))
|
||||
(is @(rf/subscribe [:chats/chat chat-id]))
|
||||
(rf/dispatch-sync [::chat.models/mute-chat-toggled chat-id true])
|
||||
|
||||
@@ -424,7 +424,7 @@
|
||||
:key-uid
|
||||
(fn [stored-key-uid]
|
||||
(when (= stored-key-uid key-uid)
|
||||
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id])))))))))
|
||||
(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])))))))))
|
||||
|
||||
(rf/defn check-last-chat
|
||||
{:events [::check-last-chat]}
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
transactions-management-enabled?
|
||||
wakuv2-flag
|
||||
current-fleet
|
||||
webview-debug
|
||||
mutual-contact-requests-enabled?]}]
|
||||
webview-debug]}]
|
||||
(keep
|
||||
identity
|
||||
[{:size :small
|
||||
@@ -115,17 +114,7 @@
|
||||
#(re-frame/dispatch
|
||||
[:multiaccounts.ui/waku-bloom-filter-mode-switched (not waku-bloom-filter-mode)])
|
||||
:accessory :switch
|
||||
:active waku-bloom-filter-mode}
|
||||
{:size :small
|
||||
:title (i18n/label :t/mutual-contact-requests)
|
||||
:accessibility-label :mutual-contact-requests-switch
|
||||
:container-margin-bottom 8
|
||||
:on-press
|
||||
#(re-frame/dispatch
|
||||
[:multiaccounts.ui/switch-mutual-contact-requests-enabled
|
||||
(not mutual-contact-requests-enabled?)])
|
||||
:accessory :switch
|
||||
:active mutual-contact-requests-enabled?}]))
|
||||
:active waku-bloom-filter-mode}]))
|
||||
|
||||
(defn- flat-list-data
|
||||
[options]
|
||||
@@ -146,8 +135,7 @@
|
||||
communities-enabled? [:communities/enabled?]
|
||||
transactions-management-enabled? [:wallet/transactions-management-enabled?]
|
||||
current-log-level [:log-level/current-log-level]
|
||||
current-fleet [:fleets/current-fleet]
|
||||
mutual-contact-requests-enabled? [:mutual-contact-requests/enabled?]]
|
||||
current-fleet [:fleets/current-fleet]]
|
||||
[list/flat-list
|
||||
{:data (flat-list-data
|
||||
{:network-name network-name
|
||||
@@ -158,7 +146,6 @@
|
||||
:dev-mode? false
|
||||
:wakuv2-flag wakuv2-flag
|
||||
:waku-bloom-filter-mode waku-bloom-filter-mode
|
||||
:webview-debug webview-debug
|
||||
:mutual-contact-requests-enabled? mutual-contact-requests-enabled?})
|
||||
:webview-debug webview-debug})
|
||||
:key-fn (fn [_ i] (str i))
|
||||
:render-fn render-item}]))
|
||||
|
||||
@@ -7,11 +7,17 @@
|
||||
[status-im.ui.screens.multiaccounts.key-storage.views :as key-storage]
|
||||
[status-im.ui.screens.multiaccounts.recover.views :as recover.views]
|
||||
[status-im2.common.bottom-sheet.view :as bottom-sheet]
|
||||
[status-im2.contexts.chat.messages.pin.list.view :as pin.list]))
|
||||
[status-im2.contexts.chat.messages.pin.list.view :as pin.list]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.chat.messages.drawers.view :as drawers]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.multiaccounts.sheets :as multiaccounts-sheet]))
|
||||
|
||||
(defn bottom-sheet
|
||||
[]
|
||||
(let [{:keys [show? view options]} @(re-frame/subscribe [:bottom-sheet])
|
||||
(let [dismiss-bottom-sheet-callback #(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
{:keys [show-bottom-sheet?]} @(re-frame/subscribe [:bottom-sheet/config])
|
||||
{:keys [show? view options]} @(re-frame/subscribe [:bottom-sheet])
|
||||
{:keys [content]
|
||||
:as opts}
|
||||
(cond-> {:visible? show?}
|
||||
@@ -46,7 +52,22 @@
|
||||
(merge key-storage/migrate-account-password)
|
||||
|
||||
(= view :pinned-messages-list)
|
||||
(merge {:content pin.list/pinned-messages-list}))]
|
||||
[bottom-sheet/bottom-sheet opts
|
||||
(when content
|
||||
[content (when options options)])]))
|
||||
(merge {:content pin.list/pinned-messages-list})
|
||||
|
||||
(= view :drawer/reactions)
|
||||
(merge {:content drawers/reactions})
|
||||
|
||||
(= view :generate-a-new-key)
|
||||
(merge {:content multiaccounts-sheet/actions-sheet}))]
|
||||
(reagent/create-class
|
||||
{:reagent-render (fn []
|
||||
[bottom-sheet/bottom-sheet
|
||||
opts
|
||||
(when content
|
||||
[content (when options options)])])
|
||||
:component-did-mount (fn []
|
||||
(react/hw-back-add-listener dismiss-bottom-sheet-callback))
|
||||
:component-will-unmount (fn []
|
||||
(react/hw-back-remove-listener dismiss-bottom-sheet-callback)
|
||||
(when show-bottom-sheet?
|
||||
(re-frame/dispatch [:bottom-sheet/reset])))})))
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[quo.design-system.colors :as colors]
|
||||
[quo.react :as quo.react]
|
||||
[quo.react-native :as rn]
|
||||
[re-frame.core :as re-frame]
|
||||
[re-frame.core :as rf]
|
||||
re-frame.db
|
||||
[reagent.core :as reagent]
|
||||
[status-im.constants :as constants]
|
||||
@@ -42,13 +42,13 @@
|
||||
|
||||
(defn invitation-requests
|
||||
[chat-id admins]
|
||||
(let [current-pk @(re-frame/subscribe [:multiaccount/public-key])
|
||||
(let [current-pk @(rf/subscribe [:multiaccount/public-key])
|
||||
admin? (get admins current-pk)]
|
||||
(when admin?
|
||||
(let [invitations @(re-frame/subscribe [:group-chat/pending-invitations-by-chat-id chat-id])]
|
||||
(let [invitations @(rf/subscribe [:group-chat/pending-invitations-by-chat-id chat-id])]
|
||||
(when (seq invitations)
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch [:navigate-to :group-chat-invite])
|
||||
{:on-press #(rf/dispatch [:navigate-to :group-chat-invite])
|
||||
:accessibility-label :invitation-requests-button}
|
||||
[react/view {:style (style/add-contact)}
|
||||
[react/text {:style style/add-contact-text}
|
||||
@@ -56,11 +56,11 @@
|
||||
|
||||
(defn add-contact-bar
|
||||
[public-key]
|
||||
(when-not (or @(re-frame/subscribe [:contacts/contact-added? public-key])
|
||||
@(re-frame/subscribe [:contacts/contact-blocked? public-key]))
|
||||
(when-not (or @(rf/subscribe [:contacts/contact-added? public-key])
|
||||
@(rf/subscribe [:contacts/contact-blocked? public-key]))
|
||||
[react/touchable-highlight
|
||||
{:on-press
|
||||
#(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key])
|
||||
#(rf/dispatch [:contact.ui/add-to-contact-pressed public-key])
|
||||
:accessibility-label :add-to-contacts-button}
|
||||
[react/view {:style (style/add-contact)}
|
||||
[icons/icon :main-icons/add
|
||||
@@ -69,7 +69,7 @@
|
||||
|
||||
(defn contact-request
|
||||
[]
|
||||
(let [contact-request @(re-frame/subscribe [:chats/sending-contact-request])]
|
||||
(let [contact-request @(rf/subscribe [:chats/sending-contact-request])]
|
||||
[react/view {:style style/contact-request}
|
||||
[react/image
|
||||
{:source (resources/get-image :hand-wave)
|
||||
@@ -92,7 +92,7 @@
|
||||
[quo/button
|
||||
{:style {:width "100%"}
|
||||
:accessibility-label :contact-request--button
|
||||
:on-press #(re-frame/dispatch [:chat.ui/send-contact-request])}
|
||||
:on-press #(rf/dispatch [:chat.ui/send-contact-request])}
|
||||
(i18n/label :t/contact-request)]])]))
|
||||
|
||||
(defn chat-intro
|
||||
@@ -101,7 +101,6 @@
|
||||
chat-type
|
||||
group-chat
|
||||
invitation-admin
|
||||
mutual-contact-requests-enabled?
|
||||
contact-name
|
||||
color
|
||||
loading-messages?
|
||||
@@ -136,25 +135,23 @@
|
||||
:no-messages? no-messages?}]
|
||||
[react/text {:style (assoc style/intro-header-description :margin-bottom 32)}
|
||||
(str (i18n/label :t/empty-chat-description-one-to-one) contact-name)])
|
||||
(when (and mutual-contact-requests-enabled?
|
||||
(= chat-type constants/one-to-one-chat-type)
|
||||
(or (= contact-request-state constants/contact-request-state-none)
|
||||
(= contact-request-state constants/contact-request-state-received)
|
||||
(= contact-request-state constants/contact-request-state-dismissed)))
|
||||
[contact-request])])
|
||||
(when
|
||||
(= chat-type constants/one-to-one-chat-type)
|
||||
(or (= contact-request-state constants/contact-request-state-none)
|
||||
(= contact-request-state constants/contact-request-state-received)
|
||||
(= contact-request-state constants/contact-request-state-dismissed)))
|
||||
[contact-request]])
|
||||
|
||||
(defn chat-intro-one-to-one
|
||||
[{:keys [chat-id] :as opts}]
|
||||
(let [contact @(re-frame/subscribe [:contacts/contact-by-identity chat-id])
|
||||
mutual-contact-requests-enabled? @(re-frame/subscribe [:mutual-contact-requests/enabled?])
|
||||
contact-names @(re-frame/subscribe [:contacts/contact-two-names-by-identity
|
||||
chat-id])]
|
||||
(let [contact @(rf/subscribe [:contacts/contact-by-identity chat-id])
|
||||
contact-names @(rf/subscribe [:contacts/contact-two-names-by-identity
|
||||
chat-id])]
|
||||
[chat-intro
|
||||
(assoc opts
|
||||
:mutual-contact-requests-enabled? mutual-contact-requests-enabled?
|
||||
:contact-name (first contact-names)
|
||||
:contact-request-state (or (:contact-request-state contact)
|
||||
constants/contact-request-state-none))]))
|
||||
:contact-name (first contact-names)
|
||||
:contact-request-state (or (:contact-request-state contact)
|
||||
constants/contact-request-state-none))]))
|
||||
|
||||
(defn chat-intro-header-container
|
||||
[{:keys [group-chat invitation-admin
|
||||
@@ -217,8 +214,8 @@
|
||||
(defn invitation-bar
|
||||
[chat-id]
|
||||
(let [{:keys [state chat-id] :as invitation}
|
||||
(first @(re-frame/subscribe [:group-chat/invitations-by-chat-id chat-id]))
|
||||
{:keys [retry? message]} @(re-frame/subscribe [:chats/current-chat-membership])
|
||||
(first @(rf/subscribe [:group-chat/invitations-by-chat-id chat-id]))
|
||||
{:keys [retry? message]} @(rf/subscribe [:chats/current-chat-membership])
|
||||
message-length (count message)]
|
||||
[react/view {:margin-horizontal 16 :margin-top 10}
|
||||
(cond
|
||||
@@ -238,13 +235,13 @@
|
||||
[quo/button
|
||||
{:type :secondary
|
||||
:accessibility-label :retry-button
|
||||
:on-press #(re-frame/dispatch [:group-chats.ui/membership-retry])}
|
||||
:on-press #(rf/dispatch [:group-chats.ui/membership-retry])}
|
||||
(i18n/label :t/mailserver-retry)]
|
||||
:left
|
||||
[quo/button
|
||||
{:type :secondary
|
||||
:accessibility-label :remove-group-button
|
||||
:on-press #(re-frame/dispatch [:group-chats.ui/remove-chat-confirmed chat-id])}
|
||||
:on-press #(rf/dispatch [:group-chats.ui/remove-chat-confirmed chat-id])}
|
||||
(i18n/label :t/remove-group)]}]
|
||||
:else
|
||||
[toolbar/toolbar
|
||||
@@ -255,7 +252,7 @@
|
||||
:accessibility-label :introduce-yourself-button
|
||||
:disabled (or (string/blank? message)
|
||||
(> message-length chat.group/message-max-length))
|
||||
:on-press #(re-frame/dispatch [:send-group-chat-membership-request])}
|
||||
:on-press #(rf/dispatch [:send-group-chat-membership-request])}
|
||||
(i18n/label :t/request-membership)]}])]))
|
||||
|
||||
(defn get-space-keeper-ios
|
||||
@@ -289,9 +286,9 @@
|
||||
|
||||
(defn list-footer
|
||||
[{:keys [chat-id] :as chat}]
|
||||
(let [loading-messages? @(re-frame/subscribe [:chats/loading-messages? chat-id])
|
||||
no-messages? @(re-frame/subscribe [:chats/chat-no-messages? chat-id])
|
||||
all-loaded? @(re-frame/subscribe [:chats/all-loaded? chat-id])]
|
||||
(let [loading-messages? @(rf/subscribe [:chats/loading-messages? chat-id])
|
||||
no-messages? @(rf/subscribe [:chats/chat-no-messages? chat-id])
|
||||
all-loaded? @(rf/subscribe [:chats/all-loaded? chat-id])]
|
||||
[react/view {:style (when platform/android? {:scaleY -1})}
|
||||
(if (or loading-messages? (not chat-id) (not all-loaded?))
|
||||
[react/view {:height 324 :align-items :center :justify-content :center}
|
||||
@@ -340,15 +337,15 @@
|
||||
(defn list-on-end-reached
|
||||
[]
|
||||
(if @state/scrolling
|
||||
(re-frame/dispatch [:chat.ui/load-more-messages-for-current-chat])
|
||||
(utils/set-timeout #(re-frame/dispatch [:chat.ui/load-more-messages-for-current-chat])
|
||||
(rf/dispatch [:chat.ui/load-more-messages-for-current-chat])
|
||||
(utils/set-timeout #(rf/dispatch [:chat.ui/load-more-messages-for-current-chat])
|
||||
(if platform/low-device? 700 200))))
|
||||
|
||||
(defn get-render-data
|
||||
[{:keys [group-chat chat-id public? community-id admins space-keeper show-input? edit-enabled
|
||||
in-pinned-view?]}]
|
||||
(let [current-public-key @(re-frame/subscribe [:multiaccount/public-key])
|
||||
community @(re-frame/subscribe [:communities/community community-id])
|
||||
(let [current-public-key @(rf/subscribe [:multiaccount/public-key])
|
||||
community @(rf/subscribe [:communities/community community-id])
|
||||
group-admin? (get admins current-public-key)
|
||||
community-admin? (when community (community :admin))
|
||||
message-pin-enabled (and (not public?)
|
||||
@@ -371,17 +368,15 @@
|
||||
[{:keys [chat
|
||||
bottom-space
|
||||
pan-responder
|
||||
mutual-contact-requests-enabled?
|
||||
space-keeper
|
||||
show-input?]}]
|
||||
(let [{:keys [group-chat chat-type chat-id public? community-id admins]} chat
|
||||
|
||||
messages @(re-frame/subscribe [:chats/raw-chat-messages-stream chat-id])
|
||||
messages @(rf/subscribe [:chats/raw-chat-messages-stream chat-id])
|
||||
one-to-one? (= chat-type constants/one-to-one-chat-type)
|
||||
contact-added? (when one-to-one? @(re-frame/subscribe [:contacts/contact-added? chat-id]))
|
||||
contact-added? (when one-to-one? @(rf/subscribe [:contacts/contact-added? chat-id]))
|
||||
should-send-contact-request?
|
||||
(and
|
||||
mutual-contact-requests-enabled?
|
||||
one-to-one?
|
||||
(not contact-added?))]
|
||||
|
||||
@@ -423,13 +418,13 @@
|
||||
[]
|
||||
(when (and (not @navigation.state/curr-modal) (= (get @re-frame.db/app-db :view-id) :chat))
|
||||
(react/hw-back-remove-listener navigate-back-handler)
|
||||
(re-frame/dispatch [:close-chat])
|
||||
(re-frame/dispatch [:navigate-back])))
|
||||
(rf/dispatch [:close-chat])
|
||||
(rf/dispatch [:navigate-back])))
|
||||
|
||||
(defn topbar-content
|
||||
[]
|
||||
(let [window-width @(re-frame/subscribe [:dimensions/window-width])
|
||||
{:keys [group-chat chat-id] :as chat-info} @(re-frame/subscribe [:chats/current-chat])]
|
||||
(let [window-width @(rf/subscribe [:dimensions/window-width])
|
||||
{:keys [group-chat chat-id] :as chat-info} @(rf/subscribe [:chats/current-chat])]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(when-not group-chat
|
||||
(debounce/dispatch-and-chill [:chat.ui/show-profile chat-id] 1000))
|
||||
@@ -452,9 +447,9 @@
|
||||
[react/view {:flex 1 :left 52 :right 52 :top 0 :bottom 0 :position :absolute}
|
||||
[topbar-content]]
|
||||
[react/touchable-highlight
|
||||
{:on-press-in #(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn [] [sheets/current-chat-actions])
|
||||
:height 256}])
|
||||
{:on-press-in #(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn [] [sheets/current-chat-actions])
|
||||
:height 256}])
|
||||
:accessibility-label :chat-menu-button
|
||||
:style {:right 0
|
||||
:top 0
|
||||
@@ -481,26 +476,28 @@
|
||||
set-active-panel (get-set-active-panel active-panel)
|
||||
on-close #(set-active-panel nil)]
|
||||
(fn []
|
||||
(let [{:keys [chat-id show-input? group-chat admins invitation-admin] :as chat}
|
||||
;;we want to react only on these fields, do not use full chat map here
|
||||
@(re-frame/subscribe [:chats/current-chat-chat-view])
|
||||
mutual-contact-requests-enabled? @(re-frame/subscribe [:mutual-contact-requests/enabled?])
|
||||
max-bottom-space (max @bottom-space @panel-space)]
|
||||
(let [{:keys [chat-id
|
||||
show-input?
|
||||
group-chat
|
||||
admins
|
||||
invitation-admin]
|
||||
:as chat}
|
||||
@(rf/subscribe [:chats/current-chat-chat-view])
|
||||
max-bottom-space (max @bottom-space
|
||||
@panel-space)]
|
||||
[:<>
|
||||
[topbar]
|
||||
[connectivity/loading-indicator]
|
||||
(when chat-id
|
||||
(if group-chat
|
||||
[invitation-requests chat-id admins]
|
||||
(when-not mutual-contact-requests-enabled? [add-contact-bar chat-id])))
|
||||
(when group-chat
|
||||
[invitation-requests chat-id admins]))
|
||||
;;MESSAGES LIST
|
||||
[messages-view
|
||||
{:chat chat
|
||||
:bottom-space max-bottom-space
|
||||
:pan-responder pan-responder
|
||||
:mutual-contact-requests-enabled? mutual-contact-requests-enabled?
|
||||
:space-keeper space-keeper
|
||||
:show-input? show-input?}]
|
||||
{:chat chat
|
||||
:bottom-space max-bottom-space
|
||||
:pan-responder pan-responder
|
||||
:space-keeper space-keeper
|
||||
:show-input? show-input?}]
|
||||
(when (and group-chat invitation-admin)
|
||||
[accessory/view
|
||||
{:y position-y
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:communities/load-category-states id])
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:navigate-to :community {:community-id id}]))
|
||||
(rf/dispatch [:navigate-to-nav2 :community {:community-id id}]))
|
||||
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn []
|
||||
[community/community-actions community])}])}
|
||||
@@ -111,7 +111,7 @@
|
||||
(i18n/label :t/open-membership))]]
|
||||
:on-press #(do
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:navigate-to :community {:community-id id}]))}]))
|
||||
(rf/dispatch [:navigate-to-nav2 :community {:community-id id}]))}]))
|
||||
|
||||
(defn communities-actions
|
||||
[]
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
(ns status-im.ui.screens.home.sheet.views
|
||||
(:require [quo.core :as quo]
|
||||
(:require [i18n.i18n :as i18n]
|
||||
[quo.core :as quo]
|
||||
[quo2.core :as quo2]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[re-frame.core :as rf]
|
||||
[i18n.i18n :as i18n]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.background-timer :as timer]
|
||||
[status-im.qr-scanner.core :as qr-scanner]
|
||||
[status-im.ui.components.invite.views :as invite]
|
||||
[status-im.ui.components.react :as rn]
|
||||
[status-im.ui.screens.home.sheet.styles :as style]
|
||||
[status-im.ui2.screens.chat.components.new-chat.view :as new-chat-aio]
|
||||
[status-im.utils.config :as config]
|
||||
[quo2.core :as quo2]
|
||||
[status-im.ui.screens.home.sheet.styles :as style]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn hide-sheet-and-dispatch
|
||||
(defn- hide-sheet-and-dispatch
|
||||
[event]
|
||||
(rf/dispatch [:bottom-sheet/hide])
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
(rf/dispatch event))
|
||||
|
||||
(defn add-new-view
|
||||
@@ -28,7 +30,7 @@
|
||||
{:type :icon
|
||||
:theme :icon
|
||||
:accessibility-label :universal-qr-scanner
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
:on-press #(rf/dispatch
|
||||
[::qr-scanner/scan-code
|
||||
{:handler ::qr-scanner/on-scan-success}])}
|
||||
:main-icons/qr]]
|
||||
@@ -51,46 +53,59 @@
|
||||
:accessibility-label :join-public-chat-button
|
||||
:icon :main-icons/public-chat
|
||||
:on-press #(hide-sheet-and-dispatch [:open-modal :new-public-chat])}]
|
||||
(when @(rf/subscribe [:communities/enabled?])
|
||||
(when (rf/sub [:communities/enabled?])
|
||||
[quo/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/communities-alpha)
|
||||
:accessibility-label :communities-button
|
||||
:icon :main-icons/communities
|
||||
:on-press #(hide-sheet-and-dispatch [:navigate-to :communities])}])
|
||||
:on-press #(rf/dispatch [:navigate-to :communities])}])
|
||||
[invite/list-item
|
||||
{:accessibility-label :chats-menu-invite-friends-button}]])
|
||||
|
||||
(defn new-chat-bottom-sheet
|
||||
[]
|
||||
[rn/view
|
||||
[quo2/menu-item
|
||||
{:theme :main
|
||||
:title (i18n/label :t/new-chat)
|
||||
:icon-bg-color :transparent
|
||||
:container-padding-vertical 12
|
||||
:title-column-style {:margin-left 2}
|
||||
:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)
|
||||
:accessibility-label :start-a-new-chat
|
||||
:icon :i/new-message
|
||||
:on-press #(hide-sheet-and-dispatch [:bottom-sheet/show-sheet
|
||||
:start-a-new-chat])}]
|
||||
[quo2/menu-item
|
||||
{:theme :main
|
||||
:title (i18n/label :t/add-a-contact)
|
||||
:icon-bg-color :transparent
|
||||
:icon-container-style {:padding-horizontal 0}
|
||||
:container-padding-horizontal {:padding-horizontal 4}
|
||||
:style-props {:margin-top 18
|
||||
:margin-bottom 9}
|
||||
:container-padding-vertical 12
|
||||
:title-column-style {:margin-left 2}
|
||||
:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)
|
||||
:accessibility-label :add-a-contact
|
||||
:subtitle (i18n/label :t/enter-a-chat-key)
|
||||
:subtitle-color colors/neutral-50
|
||||
:icon :i/add-user
|
||||
:on-press #(hide-sheet-and-dispatch [:open-modal :new-contact])}]])
|
||||
(let [{:keys [animation-delay]} (rf/sub [:bottom-sheet/config])]
|
||||
[rn/view
|
||||
[quo2/menu-item
|
||||
{:theme :main
|
||||
:title (i18n/label :t/new-chat)
|
||||
:icon-bg-color :transparent
|
||||
:type :transparent
|
||||
:container-padding-vertical 12
|
||||
:style-props {:border-bottom-width 1
|
||||
:border-color (colors/theme-colors colors/neutral-10
|
||||
colors/neutral-90)}
|
||||
:title-column-style {:margin-left 2}
|
||||
:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)
|
||||
:accessibility-label :start-a-new-chat
|
||||
:icon :i/new-message
|
||||
:on-press (fn []
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
(timer/set-timeout
|
||||
#(rf/dispatch [:bottom-sheet/show-sheet :start-a-new-chat])
|
||||
(or animation-delay 450)))}]
|
||||
[quo2/menu-item
|
||||
{:theme :main
|
||||
:title (i18n/label :t/connect-with-users)
|
||||
:icon-bg-color :transparent
|
||||
:type :transparent
|
||||
:icon-container-style {:padding-horizontal 0}
|
||||
:container-padding-horizontal {:padding-horizontal 4}
|
||||
:style-props {:margin-top 18
|
||||
:margin-bottom 9}
|
||||
:container-padding-vertical 12
|
||||
:title-column-style {:margin-left 2}
|
||||
:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)
|
||||
:accessibility-label :connect-with-users
|
||||
:subtitle (i18n/label :t/enter-a-chat-key)
|
||||
:subtitle-color colors/neutral-50
|
||||
:icon :i/add-user
|
||||
:on-press (fn []
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
(timer/set-timeout
|
||||
#(rf/dispatch [:open-modal :new-contact])
|
||||
(or animation-delay 450)))}]]))
|
||||
|
||||
|
||||
(def new-chat-bottom-sheet-comp
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
[status-im.ui.screens.home.styles :as styles]
|
||||
[status-im.ui.screens.home.views.inner-item :as inner-item]
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im2.setup.config :as config]
|
||||
[utils.debounce :as debounce])
|
||||
(:require-macros [status-im.utils.views :as views]))
|
||||
|
||||
@@ -152,9 +151,7 @@
|
||||
home-item
|
||||
{:on-press (fn []
|
||||
(re-frame/dispatch [:dismiss-keyboard])
|
||||
(if config/new-ui-enabled?
|
||||
(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])
|
||||
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id]))
|
||||
(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])
|
||||
(re-frame/dispatch [:search/home-filter-changed nil]))
|
||||
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn []
|
||||
@@ -169,9 +166,7 @@
|
||||
home-item
|
||||
{:on-press (fn []
|
||||
(re-frame/dispatch [:dismiss-keyboard])
|
||||
(if config/new-ui-enabled?
|
||||
(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])
|
||||
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id]))
|
||||
(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])
|
||||
(re-frame/dispatch [:search/home-filter-changed nil]))
|
||||
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn []
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
(ns status-im.ui.screens.multiaccounts.sheets
|
||||
(:require [quo.core :as quo]
|
||||
[re-frame.core :as re-frame]
|
||||
[i18n.i18n :as i18n]))
|
||||
[i18n.i18n :as i18n]
|
||||
status-im2.common.bottom-sheet.view))
|
||||
|
||||
(defn- hide-sheet-and-dispatch
|
||||
[event]
|
||||
(re-frame/dispatch [:dismiss-bottom-sheet])
|
||||
(re-frame/dispatch event))
|
||||
|
||||
(defn actions-sheet
|
||||
[]
|
||||
[quo/list-item
|
||||
{:theme :accent
|
||||
:on-press #(do (re-frame/dispatch [:bottom-sheet/hide])
|
||||
(re-frame/dispatch [:generate-and-derive-addresses]))
|
||||
:on-press #(hide-sheet-and-dispatch [:generate-and-derive-addresses])
|
||||
:icon :main-icons/add
|
||||
:accessibility-label :generate-a-new-key
|
||||
:title (i18n/label :t/generate-a-new-key)}])
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.toolbar :as toolbar]
|
||||
[status-im.ui.screens.chat.photos :as photos]
|
||||
[status-im.ui.screens.multiaccounts.sheets :as sheets]
|
||||
[status-im.ui.screens.multiaccounts.styles :as styles]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
@@ -41,8 +40,7 @@
|
||||
|
||||
(defn topbar-button
|
||||
[]
|
||||
(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||
{:content sheets/actions-sheet}]))
|
||||
(re-frame/dispatch [:bottom-sheet/show-sheet :generate-a-new-key {}]))
|
||||
|
||||
(defview multiaccounts
|
||||
[]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
(ns status-im.ui2.screens.chat.components.new-chat.styles)
|
||||
|
||||
(def contact-selection-heading
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :space-between
|
||||
@@ -13,4 +14,9 @@
|
||||
:margin-left 20
|
||||
:margin-bottom 36
|
||||
:justify-content :center
|
||||
:align-items :center})
|
||||
:align-items :center})
|
||||
|
||||
(defn chat-button
|
||||
[{:keys [bottom]}]
|
||||
{:position :absolute
|
||||
:bottom (- bottom 50)})
|
||||
@@ -8,12 +8,19 @@
|
||||
[i18n.i18n :as i18n]
|
||||
[status-im.ui.components.react :as react]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im.ui.screens.chat.sheets :refer [hide-sheet-and-dispatch]]
|
||||
[status-im.ui.components.toolbar :as toolbar]
|
||||
[status-im.ui2.screens.common.contact-list.view :as contact-list]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[status-im.ui.components.invite.events :as invite.events]
|
||||
[status-im.ui2.screens.chat.components.new-chat.styles :as style]))
|
||||
[status-im.ui2.screens.chat.components.new-chat.styles :as style]
|
||||
status-im2.common.bottom-sheet.view
|
||||
[quo.react :as quo.react]
|
||||
[quo.components.safe-area :as safe-area]))
|
||||
|
||||
(defn- hide-sheet-and-dispatch
|
||||
[event]
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
(rf/dispatch event))
|
||||
|
||||
(defn- on-toggle
|
||||
[allow-new-users? checked? public-key]
|
||||
@@ -39,81 +46,87 @@
|
||||
:size :paragraph-1
|
||||
:style {:margin-bottom 2
|
||||
:margin-top 20}}
|
||||
"You have no contacts"]
|
||||
(i18n/label :t/you-have-no-contacts)]
|
||||
[text/text
|
||||
{:weight :regular
|
||||
:size :label
|
||||
:style {:margin-bottom 20}}
|
||||
"Invite your friends and family to Status"]
|
||||
(i18n/label :t/invite-friends-and-family)]
|
||||
[quo2/button
|
||||
{:type :primary
|
||||
:style {:margin-bottom 12}
|
||||
:on-press #(rf/dispatch [::invite.events/share-link nil])}
|
||||
"Invite friends"]
|
||||
(i18n/label :t/invite-friends)]
|
||||
[quo2/button
|
||||
{:type :grey
|
||||
:on-press #(hide-sheet-and-dispatch [:open-modal :new-contact])}
|
||||
"Add a contact"]])
|
||||
(i18n/label :t/add-a-contact)]])
|
||||
|
||||
(defn contact-selection-list
|
||||
[]
|
||||
(let [contacts (rf/sub
|
||||
[:contacts/sorted-and-grouped-by-first-letter])
|
||||
selected-contacts-count (rf/sub [:selected-contacts-count])
|
||||
window-height (rf/sub [:dimensions/window-height])
|
||||
one-contact-selected? (= selected-contacts-count 1)
|
||||
contacts-selected? (pos? selected-contacts-count)
|
||||
{:keys [names public-key]} (-> contacts first :data first)
|
||||
added? (reagent/atom '())
|
||||
{:keys [nickname ens-name three-words-name]} names
|
||||
first-username (or ens-name nickname three-words-name)
|
||||
no-contacts? (empty? contacts)]
|
||||
[react/view {:style {:height (* window-height 0.95)}}
|
||||
[quo2/button
|
||||
{:type :grey
|
||||
:icon true
|
||||
:on-press #(rf/dispatch [:bottom-sheet/hide])
|
||||
:style style/contact-selection-close
|
||||
:override-background-color (quo2.colors/theme-colors quo2.colors/neutral-10
|
||||
quo2.colors/neutral-90)}
|
||||
:i/close]
|
||||
[react/view style/contact-selection-heading
|
||||
[quo2/text
|
||||
{:weight :semi-bold
|
||||
:size :heading-1
|
||||
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-100 quo2.colors/white)}}
|
||||
(i18n/label :t/new-chat)]
|
||||
(when-not no-contacts?
|
||||
[quo2/text
|
||||
{:size :paragraph-2
|
||||
:weight :regular
|
||||
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-40 quo2.colors/neutral-50)}}
|
||||
(i18n/label :t/selected-count-from-max
|
||||
{:selected (inc selected-contacts-count)
|
||||
:max constants/max-group-chat-participants})])]
|
||||
[react/view
|
||||
{:style {:height 430
|
||||
:margin-bottom -20}}
|
||||
(if no-contacts?
|
||||
[no-contacts-view]
|
||||
[contact-list/contact-list
|
||||
{:icon :check
|
||||
:group nil
|
||||
:added? added?
|
||||
:search? false
|
||||
:start-a-new-chat? true
|
||||
:on-toggle on-toggle}])]
|
||||
(when contacts-selected?
|
||||
[toolbar/toolbar
|
||||
{:show-border? false
|
||||
:center [button/button
|
||||
{:type :primary
|
||||
:accessibility-label :next-button
|
||||
:on-press #(do
|
||||
(if one-contact-selected?
|
||||
(hide-sheet-and-dispatch [:chat.ui/start-chat
|
||||
public-key])
|
||||
(hide-sheet-and-dispatch [:navigate-to :new-group])))}
|
||||
(if one-contact-selected?
|
||||
(i18n/label :t/chat-with {:selected-user first-username})
|
||||
(i18n/label :t/setup-group-chat))]}])]))
|
||||
[:f>
|
||||
(fn []
|
||||
(quo.react/effect! #(rf/dispatch [:clear-contacts]) [])
|
||||
(let [contacts (rf/sub
|
||||
[:contacts/sorted-and-grouped-by-first-letter])
|
||||
selected-contacts-count (rf/sub [:selected-contacts-count])
|
||||
window-height (rf/sub [:dimensions/window-height])
|
||||
one-contact-selected? (= selected-contacts-count 1)
|
||||
contacts-selected? (pos? selected-contacts-count)
|
||||
{:keys [names public-key]} (-> contacts first :data first)
|
||||
added? (reagent/atom '())
|
||||
{:keys [nickname ens-name three-words-name]} names
|
||||
first-username (or ens-name nickname three-words-name)
|
||||
no-contacts? (empty? contacts)
|
||||
safe-area (safe-area/use-safe-area)]
|
||||
[react/view {:style {:height (* window-height 0.9)}}
|
||||
[quo2/button
|
||||
{:type :grey
|
||||
:icon true
|
||||
:on-press #(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
:style style/contact-selection-close
|
||||
:override-background-color (quo2.colors/theme-colors quo2.colors/neutral-10
|
||||
quo2.colors/neutral-90)}
|
||||
:i/close]
|
||||
[react/view style/contact-selection-heading
|
||||
[quo2/text
|
||||
{:weight :semi-bold
|
||||
:size :heading-1
|
||||
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-100 quo2.colors/white)}}
|
||||
(i18n/label :t/new-chat)]
|
||||
(when-not no-contacts?
|
||||
[quo2/text
|
||||
{:size :paragraph-2
|
||||
:weight :regular
|
||||
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-40 quo2.colors/neutral-50)}}
|
||||
(i18n/label :t/selected-count-from-max
|
||||
{:selected (inc selected-contacts-count)
|
||||
:max constants/max-group-chat-participants})])]
|
||||
[react/view
|
||||
{:style {:height 430
|
||||
:margin-bottom -20}}
|
||||
(if no-contacts?
|
||||
[no-contacts-view]
|
||||
[contact-list/contact-list
|
||||
{:icon :check
|
||||
:group nil
|
||||
:added? added?
|
||||
:search? false
|
||||
:start-a-new-chat? true
|
||||
:on-toggle on-toggle}])]
|
||||
(when contacts-selected?
|
||||
[toolbar/toolbar
|
||||
{:show-border? false
|
||||
:center [button/button
|
||||
{:type :primary
|
||||
:accessibility-label :next-button
|
||||
:style (style/chat-button safe-area)
|
||||
:on-press #(do
|
||||
(if one-contact-selected?
|
||||
(hide-sheet-and-dispatch [:chat.ui/start-chat
|
||||
public-key])
|
||||
(hide-sheet-and-dispatch [:navigate-to
|
||||
:new-group])))}
|
||||
(if one-contact-selected?
|
||||
(i18n/label :t/chat-with {:selected-user first-username})
|
||||
(i18n/label :t/setup-group-chat))]}])]))])
|
||||
|
||||
@@ -450,7 +450,7 @@
|
||||
[quo/text
|
||||
{:style {:margin-top 6}
|
||||
:weight :bold
|
||||
:size :large}
|
||||
:size :heading-2}
|
||||
(i18n/label :t/contact-request)]
|
||||
[rn/view {:style {:padding-horizontal 16}}
|
||||
[quo/text
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
|
||||
(defn pin-popover
|
||||
[width]
|
||||
{:position :absolute
|
||||
:width (- width 16)
|
||||
:left 8
|
||||
{:width (- width 16)
|
||||
:margin-left 8
|
||||
:background-color (colors/theme-colors colors/neutral-80-opa-90 colors/white-opa-90)
|
||||
:flex-direction :row
|
||||
:border-radius 16
|
||||
|
||||
@@ -24,38 +24,41 @@
|
||||
(reanimated/with-timing (if show-pin-limit-modal? 1 0)))
|
||||
(reanimated/set-shared-value z-index-animation
|
||||
(reanimated/with-timing (if show-pin-limit-modal? 10 -1)))))
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:opacity opacity-animation
|
||||
:z-index z-index-animation}
|
||||
(style/pin-popover width))
|
||||
:accessibility-label :pin-limit-popover}
|
||||
[rn/view {:style (style/pin-alert-container)}
|
||||
[rn/view {:style style/pin-alert-circle}
|
||||
[rn/text {:style {:color colors/danger-50}} "!"]]]
|
||||
[rn/view {:style {:margin-left 8}}
|
||||
[quo/text {:weight :semi-bold :color (colors/theme-colors colors/white colors/neutral-100)}
|
||||
(i18n/label :t/cannot-pin-title)]
|
||||
[quo/text {:size :paragraph-2 :color (colors/theme-colors colors/white colors/neutral-100)}
|
||||
(i18n/label :t/cannot-pin-desc)]
|
||||
[rn/touchable-opacity
|
||||
{:accessibility-label :view-pinned-messages
|
||||
:active-opacity 1
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:pin-message/hide-pin-limit-modal chat-id])
|
||||
(rf/dispatch [:bottom-sheet/show-sheet :pinned-messages-list chat-id]))
|
||||
:style style/view-pinned-messages}
|
||||
[quo/text {:size :paragraph-2 :weight :medium :color colors/white}
|
||||
(i18n/label :t/view-pinned-messages)]]]
|
||||
[rn/touchable-opacity
|
||||
{:accessibility-label :close-pin-limit-popover
|
||||
:active-opacity 1
|
||||
:on-press #(rf/dispatch [:pin-message/hide-pin-limit-modal chat-id])
|
||||
:style {:position :absolute
|
||||
:top 16
|
||||
:right 16}}
|
||||
[quo/icon :i/close
|
||||
{:color (colors/theme-colors colors/white colors/neutral-100)
|
||||
:size 12}]]]))])
|
||||
(when show-pin-limit-modal?
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:opacity opacity-animation
|
||||
:z-index z-index-animation}
|
||||
(style/pin-popover width))
|
||||
:accessibility-label :pin-limit-popover}
|
||||
[rn/view {:style (style/pin-alert-container)}
|
||||
[rn/view {:style style/pin-alert-circle}
|
||||
[rn/text {:style {:color colors/danger-50}} "!"]]]
|
||||
[rn/view {:style {:margin-left 8}}
|
||||
[quo/text {:weight :semi-bold :color (colors/theme-colors colors/white colors/neutral-100)}
|
||||
(i18n/label :t/cannot-pin-title)]
|
||||
[quo/text {:size :paragraph-2 :color (colors/theme-colors colors/white colors/neutral-100)}
|
||||
(i18n/label :t/cannot-pin-desc)]
|
||||
[rn/touchable-opacity
|
||||
{:accessibility-label :view-pinned-messages
|
||||
:active-opacity 1
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:pin-message/hide-pin-limit-modal chat-id])
|
||||
(rf/dispatch [:bottom-sheet/show-sheet :pinned-messages-list
|
||||
chat-id])
|
||||
(rf/dispatch [:dismiss-keyboard]))
|
||||
:style style/view-pinned-messages}
|
||||
[quo/text {:size :paragraph-2 :weight :medium :color colors/white}
|
||||
(i18n/label :t/view-pinned-messages)]]]
|
||||
[rn/touchable-opacity
|
||||
{:accessibility-label :close-pin-limit-popover
|
||||
:active-opacity 1
|
||||
:on-press #(rf/dispatch [:pin-message/hide-pin-limit-modal chat-id])
|
||||
:style {:position :absolute
|
||||
:top 16
|
||||
:right 16}}
|
||||
[quo/icon :i/close
|
||||
{:color (colors/theme-colors colors/white colors/neutral-100)
|
||||
:size 12}]]])))])
|
||||
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
(ns status-im.ui2.screens.chat.pinned-banner.view
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
;; TODO (flexsurfer) this should be a banner component in quo2
|
||||
;; https://github.com/status-im/status-mobile/issues/14528
|
||||
(defn pinned-banner
|
||||
[{:keys [latest-pin-text pins-count on-press]}]
|
||||
[rn/touchable-opacity
|
||||
{:accessibility-label :pinned-banner
|
||||
:style {:height 50
|
||||
:background-color colors/primary-50-opa-20
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:padding-horizontal 20
|
||||
:padding-vertical 10}
|
||||
:active-opacity 1
|
||||
:on-press on-press}
|
||||
[quo/icon :i/pin {:size 20}]
|
||||
[quo/text
|
||||
{:number-of-lines 1
|
||||
:size :paragraph-2
|
||||
:style {:margin-left 10 :margin-right 50}}
|
||||
latest-pin-text]
|
||||
[rn/view
|
||||
{:accessibility-label :pins-count
|
||||
:style {:position :absolute
|
||||
:right 22
|
||||
:height 20
|
||||
:width 20
|
||||
:border-radius 8
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color colors/neutral-80-opa-5}}
|
||||
[quo/text {:size :label :weight :medium} pins-count]]])
|
||||
@@ -9,10 +9,12 @@
|
||||
[quo/divider-label {:label title}])
|
||||
|
||||
(defn contact-list
|
||||
[data]
|
||||
(let [contacts (if (:group data)
|
||||
(rf/sub [:contacts/add-members-sections])
|
||||
(rf/sub [:contacts/filtered-active-sections]))]
|
||||
[{:keys [start-a-new-chat?] :as data}]
|
||||
(let [contacts (if start-a-new-chat?
|
||||
(rf/sub [:contacts/sorted-and-grouped-by-first-letter])
|
||||
(if (:group data)
|
||||
(rf/sub [:contacts/grouped-by-first-letter])
|
||||
(rf/sub [:contacts/filtered-active-sections])))]
|
||||
[rn/section-list
|
||||
{:key-fn :title
|
||||
:sticky-section-headers-enabled false
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
(rf/defn handle-community-chat
|
||||
[cofx {:keys [chat-id]}]
|
||||
(log/info "universal-links: handling community chat" chat-id)
|
||||
{:dispatch [:chat.ui/navigate-to-chat chat-id]})
|
||||
{:dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]})
|
||||
|
||||
(rf/defn handle-public-chat
|
||||
[cofx {:keys [topic]}]
|
||||
|
||||
@@ -22,14 +22,35 @@
|
||||
:top 0
|
||||
:background-color colors/neutral-100})
|
||||
|
||||
(def container
|
||||
{:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:top 0
|
||||
:bottom 0
|
||||
:overflow :hidden})
|
||||
|
||||
(defn content-style
|
||||
[insets]
|
||||
{:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:top 0
|
||||
:padding-top border-radius
|
||||
:padding-bottom (:bottom insets)})
|
||||
|
||||
(defn selected-background
|
||||
[]
|
||||
{:border-radius 12
|
||||
:padding-left 12
|
||||
:margin-horizontal 8
|
||||
:margin-bottom 10
|
||||
:height 48
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-90)})
|
||||
|
||||
(defn background
|
||||
[]
|
||||
{:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:top 0
|
||||
:bottom 0
|
||||
{:background-color (colors/theme-colors colors/white colors/neutral-95)
|
||||
:flex 1
|
||||
:border-top-left-radius border-radius
|
||||
:border-top-right-radius border-radius
|
||||
:overflow :hidden
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95)})
|
||||
:border-top-right-radius border-radius})
|
||||
|
||||
@@ -10,13 +10,11 @@
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def bottom-sheet-js (js/require "../src/js/bottom_sheet.js"))
|
||||
|
||||
(def animation-delay 450)
|
||||
|
||||
(defn with-animation
|
||||
(defn- with-animation
|
||||
[value & [options callback]]
|
||||
(reanimated/with-spring
|
||||
value
|
||||
@@ -26,20 +24,6 @@
|
||||
options)
|
||||
callback))
|
||||
|
||||
(def content-height (reagent/atom nil))
|
||||
(def show-bottom-sheet? (reagent/atom nil))
|
||||
(def keyboard-was-shown? (reagent/atom false))
|
||||
(def expanded? (reagent/atom false))
|
||||
(def gesture-running? (reagent/atom false))
|
||||
|
||||
(defn reset-atoms
|
||||
[]
|
||||
(reset! show-bottom-sheet? nil)
|
||||
(reset! content-height nil)
|
||||
(reset! expanded? false)
|
||||
(reset! keyboard-was-shown? false)
|
||||
(reset! gesture-running? false))
|
||||
|
||||
(defn get-bottom-sheet-gesture
|
||||
[pan-y translate-y bg-height bg-height-expanded
|
||||
window-height keyboard-shown disable-drag? expandable?
|
||||
@@ -47,16 +31,16 @@
|
||||
(-> (gesture/gesture-pan)
|
||||
(gesture/on-start
|
||||
(fn [_]
|
||||
(reset! gesture-running? true)
|
||||
(rf/dispatch [:bottom-sheet/gesture-running? true])
|
||||
(when (and keyboard-shown (not disable-drag?) show-bottom-sheet?)
|
||||
(re-frame/dispatch [:dismiss-keyboard]))))
|
||||
(gesture/on-update
|
||||
(fn [evt]
|
||||
(when (and (not disable-drag?) show-bottom-sheet?)
|
||||
(let [max-pan-up (if (or @expanded? (not expandable?))
|
||||
(let [max-pan-up (if (or expanded? (not expandable?))
|
||||
0
|
||||
(- (- bg-height-expanded bg-height)))
|
||||
max-pan-down (if @expanded?
|
||||
max-pan-down (if expanded?
|
||||
bg-height-expanded
|
||||
bg-height)]
|
||||
(reanimated/set-shared-value pan-y
|
||||
@@ -67,21 +51,21 @@
|
||||
max-pan-up))))))
|
||||
(gesture/on-end
|
||||
(fn [_]
|
||||
(reset! gesture-running? false)
|
||||
(rf/dispatch [:bottom-sheet/gesture-running? false])
|
||||
(when (and (not disable-drag?) show-bottom-sheet?)
|
||||
(let [end-pan-y (- window-height (.-value translate-y))
|
||||
expand-threshold (min (* bg-height * 1.1) (+ bg-height 50))
|
||||
collapse-threshold (max (* bg-height-expanded * 0.9) (- bg-height-expanded 50))
|
||||
expand-threshold (min (* bg-height 1.1) (+ bg-height 50))
|
||||
collapse-threshold (max (* bg-height-expanded 0.9) (- bg-height-expanded 50))
|
||||
should-close-bottom-sheet? (< end-pan-y (max (* bg-height 0.7) 50))]
|
||||
(cond
|
||||
should-close-bottom-sheet?
|
||||
(close-bottom-sheet)
|
||||
|
||||
(and (not @expanded?) (> end-pan-y expand-threshold))
|
||||
(reset! expanded? true)
|
||||
(and (not expanded?) (> end-pan-y expand-threshold))
|
||||
(rf/dispatch [:bottom-sheet/did-expand true])
|
||||
|
||||
(and @expanded? (< end-pan-y collapse-threshold))
|
||||
(reset! expanded? false))))))))
|
||||
(and expanded? (< end-pan-y collapse-threshold))
|
||||
(rf/dispatch [:bottom-sheet/did-expand false]))))))))
|
||||
|
||||
(defn bottom-sheet
|
||||
[props children]
|
||||
@@ -91,28 +75,26 @@
|
||||
visible? :visible?
|
||||
backdrop-dismiss? :backdrop-dismiss?
|
||||
expandable? :expandable?
|
||||
selected-item :selected-item
|
||||
:or {show-handle? true
|
||||
backdrop-dismiss? true
|
||||
expandable? false}}
|
||||
props
|
||||
close-bottom-sheet (fn []
|
||||
(reset! show-bottom-sheet? false)
|
||||
(when (fn? on-cancel) (on-cancel))
|
||||
(timer/set-timeout
|
||||
#(do
|
||||
(re-frame/dispatch [:bottom-sheet/hide-navigation-overlay])
|
||||
(reset-atoms))
|
||||
animation-delay))]
|
||||
close-bottom-sheet #(re-frame/dispatch-sync [:dismiss-bottom-sheet on-cancel])]
|
||||
[safe-area/consumer
|
||||
(fn [insets]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [{window-height :height
|
||||
window-width :width}
|
||||
(let [{height :height
|
||||
window-width :width}
|
||||
(rn/use-window-dimensions)
|
||||
window-height (if selected-item (- height 72) height)
|
||||
{:keys [keyboard-shown]} (hooks/use-keyboard)
|
||||
bg-height-expanded (- window-height (:top insets))
|
||||
bg-height (max (min @content-height bg-height-expanded) 200)
|
||||
{:keys [content-height show-bottom-sheet? keyboard-was-shown? expanded? gesture-running?
|
||||
animation-delay]}
|
||||
(rf/sub [:bottom-sheet/config])
|
||||
bg-height (max (min content-height bg-height-expanded) 150)
|
||||
bottom-sheet-dy (reanimated/use-shared-value 0)
|
||||
pan-y (reanimated/use-shared-value 0)
|
||||
translate-y (.useTranslateY ^js bottom-sheet-js window-height bottom-sheet-dy pan-y)
|
||||
@@ -120,7 +102,7 @@
|
||||
(.useBackgroundOpacity ^js bottom-sheet-js translate-y bg-height window-height)
|
||||
on-content-layout (fn [evt]
|
||||
(let [height (oget evt "nativeEvent" "layout" "height")]
|
||||
(reset! content-height height)))
|
||||
(rf/dispatch [:bottom-sheet/update-height height])))
|
||||
on-expanded (fn []
|
||||
(reanimated/set-shared-value bottom-sheet-dy bg-height-expanded)
|
||||
(reanimated/set-shared-value pan-y 0))
|
||||
@@ -143,30 +125,30 @@
|
||||
(react/effect! #(do
|
||||
(cond
|
||||
(and
|
||||
(nil? @show-bottom-sheet?)
|
||||
(nil? show-bottom-sheet?)
|
||||
visible?
|
||||
(some? @content-height)
|
||||
(> @content-height 0))
|
||||
(reset! show-bottom-sheet? true)
|
||||
(some? content-height)
|
||||
(> content-height 0))
|
||||
(rf/dispatch [:bottom-sheet/show-quo2-bottom-sheet true])
|
||||
|
||||
(and @show-bottom-sheet? (not visible?))
|
||||
(and show-bottom-sheet? (not visible?))
|
||||
(close-bottom-sheet)))
|
||||
[@show-bottom-sheet? @content-height visible?])
|
||||
[show-bottom-sheet? content-height visible?])
|
||||
(react/effect! #(do
|
||||
(when @show-bottom-sheet?
|
||||
(when show-bottom-sheet?
|
||||
(cond
|
||||
keyboard-shown
|
||||
(do
|
||||
(reset! keyboard-was-shown? true)
|
||||
(reset! expanded? true))
|
||||
(and @keyboard-was-shown? (not keyboard-shown))
|
||||
(reset! expanded? false))))
|
||||
[@show-bottom-sheet? @keyboard-was-shown?])
|
||||
(rf/dispatch [:bottom-sheet/show-quo2-bottom-sheet true])
|
||||
(rf/dispatch [:bottom-sheet/did-expand true]))
|
||||
(and keyboard-was-shown? (not keyboard-shown))
|
||||
(rf/dispatch [:bottom-sheet/did-expand false]))))
|
||||
[show-bottom-sheet? keyboard-was-shown?])
|
||||
(react/effect! #(do
|
||||
(when-not @gesture-running?
|
||||
(when-not gesture-running?
|
||||
(cond
|
||||
@show-bottom-sheet?
|
||||
(if @expanded?
|
||||
show-bottom-sheet?
|
||||
(if expanded?
|
||||
(do
|
||||
(reanimated/set-shared-value
|
||||
bottom-sheet-dy
|
||||
@@ -176,7 +158,7 @@
|
||||
;; withTiming/withSpring callback not working
|
||||
;; on-expanded should be called as a callback of
|
||||
;; with-animation instead, once this issue has been resolved
|
||||
(timer/set-timeout on-expanded animation-delay))
|
||||
(timer/set-timeout on-expanded (or animation-delay 450)))
|
||||
(do
|
||||
(reanimated/set-shared-value
|
||||
bottom-sheet-dy
|
||||
@@ -186,11 +168,11 @@
|
||||
;; withTiming/withSpring callback not working
|
||||
;; on-collapsed should be called as a callback of
|
||||
;; with-animation instead, once this issue has been resolved
|
||||
(timer/set-timeout on-collapsed animation-delay)))
|
||||
(timer/set-timeout on-collapsed (or animation-delay 450))))
|
||||
|
||||
(= @show-bottom-sheet? false)
|
||||
(= show-bottom-sheet? false)
|
||||
(reanimated/set-shared-value bottom-sheet-dy (with-animation 0)))))
|
||||
[@show-bottom-sheet? @expanded? @gesture-running?])
|
||||
[show-bottom-sheet? expanded? gesture-running?])
|
||||
|
||||
[:<>
|
||||
[rn/touchable-without-feedback {:on-press (when backdrop-dismiss? close-bottom-sheet)}
|
||||
@@ -205,22 +187,21 @@
|
||||
{:transform [{:translateY translate-y}]}
|
||||
{:width window-width
|
||||
:height window-height})}
|
||||
[rn/view {:style (styles/background)}
|
||||
[rn/keyboard-avoiding-view
|
||||
{:behaviour (if platform/ios? :padding :height)
|
||||
:style {:flex 1}}
|
||||
[rn/view
|
||||
{:style {:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:top 0
|
||||
:padding-top styles/border-radius
|
||||
:padding-bottom (:bottom insets)}
|
||||
:on-layout (when-not (and
|
||||
(some? @content-height)
|
||||
(> @content-height 0))
|
||||
on-content-layout)}
|
||||
children]]
|
||||
[rn/view {:style styles/container}
|
||||
(when selected-item
|
||||
[rn/view {:style (styles/selected-background)}
|
||||
[selected-item]])
|
||||
[rn/view {:style (styles/background)}
|
||||
[rn/keyboard-avoiding-view
|
||||
{:behaviour (if platform/ios? :padding :height)
|
||||
:style {:flex 1}}
|
||||
[rn/view
|
||||
{:style (styles/content-style insets)
|
||||
:on-layout (when-not (and
|
||||
(some? content-height)
|
||||
(> content-height 0))
|
||||
on-content-layout)}
|
||||
children]]
|
||||
|
||||
(when show-handle?
|
||||
[rn/view {:style (styles/handle)}])]]]]))])]))
|
||||
(when show-handle?
|
||||
[rn/view {:style (styles/handle)}])]]]]]))])]))
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.common.confirmation-drawer.style :as style]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[re-frame.core :as re-frame]
|
||||
status-im2.common.bottom-sheet.view))
|
||||
|
||||
(defn avatar
|
||||
[group-chat color display-name photo-path]
|
||||
@@ -56,7 +58,7 @@
|
||||
[quo/button
|
||||
{:type :grey
|
||||
:style {:flex 0.48} ;;WUT? 0.48 , whats that ?
|
||||
:on-press #(rf/dispatch [:bottom-sheet/hide])}
|
||||
:on-press #(re-frame/dispatch-sync [:dismiss-bottom-sheet])}
|
||||
(i18n/label :t/close)]
|
||||
[quo/button
|
||||
{:type :danger
|
||||
|
||||
@@ -2,21 +2,19 @@
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[status-im2.common.home.actions.view :as actions]
|
||||
[status-im2.contexts.chat.home.chat-list-item.style :as style]
|
||||
[utils.address :as utils.address]
|
||||
[utils.re-frame :as rf]
|
||||
[reagent.core :as reagent]))
|
||||
[reagent.core :as reagent]
|
||||
[quo.react :as react]))
|
||||
|
||||
(defn open-chat
|
||||
[chat-id]
|
||||
(let [view-id (rf/sub [:view-id])]
|
||||
(when (= view-id :shell-stack)
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(if platform/android?
|
||||
(rf/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])
|
||||
(rf/dispatch [:chat.ui/navigate-to-chat chat-id]))
|
||||
(rf/dispatch [:chat.ui/show-profile chat-id])
|
||||
(rf/dispatch [:search/home-filter-changed nil]))))
|
||||
|
||||
(defn action-icon
|
||||
@@ -28,31 +26,39 @@
|
||||
admin? (get admins current-pk)
|
||||
checked? (reagent/atom (if start-a-new-chat?
|
||||
user-selected?
|
||||
member?))]
|
||||
[rn/touchable-opacity
|
||||
{:on-press #(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn [] [actions/actions item extra-data])}])
|
||||
:style {:position :absolute
|
||||
:right 20}}
|
||||
(if (= icon :options)
|
||||
[quo/icon :i/options {:size 20 :color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]
|
||||
[quo/checkbox
|
||||
{:default-checked? @checked?
|
||||
:accessibility-label :contact-toggle-check
|
||||
:disabled? (and member? (not admin?))
|
||||
:on-change (fn [selected]
|
||||
(if start-a-new-chat?
|
||||
(on-toggle true @checked? public-key)
|
||||
(if-not member?
|
||||
(if selected
|
||||
(rf/dispatch [:select-participant public-key true])
|
||||
(rf/dispatch [:deselect-participant public-key true]))
|
||||
(if selected
|
||||
(rf/dispatch [:undo-deselect-member public-key true])
|
||||
(rf/dispatch [:deselect-member public-key true])))))}])]))
|
||||
member?))
|
||||
on-check (fn [selected]
|
||||
(if start-a-new-chat?
|
||||
(on-toggle true @checked? public-key)
|
||||
(if-not member?
|
||||
(if selected
|
||||
(rf/dispatch [:select-participant public-key true])
|
||||
(rf/dispatch [:deselect-participant public-key true]))
|
||||
(if selected
|
||||
(rf/dispatch [:undo-deselect-member public-key true])
|
||||
(rf/dispatch [:deselect-member public-key true])))))]
|
||||
[:f>
|
||||
(fn []
|
||||
[rn/touchable-opacity
|
||||
{:on-press #(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn [] [actions/actions item extra-data])}])
|
||||
:style {:position :absolute
|
||||
:right 20}}
|
||||
(if (= icon :options)
|
||||
[quo/icon :i/options
|
||||
{:size 20
|
||||
:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]
|
||||
(react/use-memo
|
||||
(fn []
|
||||
[quo/checkbox
|
||||
{:default-checked? @checked?
|
||||
:accessibility-label :contact-toggle-check
|
||||
:disabled? (and member? (not admin?))
|
||||
:on-change on-check}])
|
||||
[checked?]))])]))
|
||||
|
||||
(defn contact-list-item
|
||||
[item _ _ {:keys [group start-a-new-chat? on-toggle] :as extra-data}]
|
||||
[item _ _ {:keys [start-a-new-chat? on-toggle] :as extra-data}]
|
||||
(let [{:keys [public-key ens-verified added? images]} item
|
||||
display-name (first (rf/sub
|
||||
[:contacts/contact-two-names-by-identity
|
||||
@@ -71,9 +77,8 @@
|
||||
:on-press #(if start-a-new-chat?
|
||||
(on-toggle true user-selected? public-key)
|
||||
(open-chat public-key))
|
||||
:on-long-press #(when (some? group)
|
||||
(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn [] [actions/actions item extra-data])}]))})
|
||||
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn [] [actions/actions item extra-data])}])})
|
||||
[quo/user-avatar
|
||||
{:full-name display-name
|
||||
:profile-picture photo-path
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
(ns status-im2.common.home.actions.view
|
||||
(:require [i18n.i18n :as i18n]
|
||||
[quo2.components.drawers.action-drawers :as drawer]
|
||||
[status-im.chat.models :as chat.models]
|
||||
[status-im2.common.confirmation-drawer.view :as confirmation-drawer] ;;TODO move to
|
||||
;;status-im2
|
||||
[status-im2.common.constants :as constants]
|
||||
[utils.re-frame :as rf]))
|
||||
(:require ;;TODO move to
|
||||
;;status-im2
|
||||
[i18n.i18n :as i18n]
|
||||
[quo2.components.drawers.action-drawers :as drawer]
|
||||
[status-im.chat.models :as chat.models]
|
||||
[status-im2.common.confirmation-drawer.view :as confirmation-drawer] ;;TODO move to
|
||||
[status-im2.common.constants :as constants]
|
||||
[utils.re-frame :as rf]
|
||||
[react-native.background-timer :as timer]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn- entry
|
||||
[{:keys [icon label on-press danger? sub-label chevron? add-divider? accessibility-label]}]
|
||||
@@ -25,8 +28,11 @@
|
||||
|
||||
(defn hide-sheet-and-dispatch
|
||||
[event]
|
||||
(rf/dispatch [:bottom-sheet/hide])
|
||||
(rf/dispatch event))
|
||||
(let [{:keys [animation-delay]} (rf/sub [:bottom-sheet/config])]
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
(timer/set-timeout (fn []
|
||||
(rf/dispatch event))
|
||||
(or animation-delay 450))))
|
||||
|
||||
(defn show-profile-action
|
||||
[chat-id]
|
||||
@@ -43,11 +49,11 @@
|
||||
|
||||
(defn mute-chat-action
|
||||
[chat-id]
|
||||
(hide-sheet-and-dispatch [::chat.models/mute-chat-toggled chat-id true]))
|
||||
(rf/dispatch [::chat.models/mute-chat-toggled chat-id true]))
|
||||
|
||||
(defn unmute-chat-action
|
||||
[chat-id]
|
||||
(hide-sheet-and-dispatch [::chat.models/mute-chat-toggled chat-id false]))
|
||||
(rf/dispatch [::chat.models/mute-chat-toggled chat-id false]))
|
||||
|
||||
(defn clear-history-action
|
||||
[{:keys [chat-id] :as item}]
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
|
||||
(defn not-implemented
|
||||
[content]
|
||||
[rn/view {:border-color :red :border-width 1}
|
||||
content])
|
||||
(when content
|
||||
[rn/view {:border-color :red :border-width 1}
|
||||
content]))
|
||||
|
||||
@@ -3,25 +3,25 @@
|
||||
|
||||
(rf/defn upsert
|
||||
{:events [:toasts/upsert]}
|
||||
[{:keys [db]} id opts]
|
||||
(let [{:keys [ordered toasts]} (:toasts db)
|
||||
update? (some #(= % id) ordered)
|
||||
ordered (if (not update?) (conj ordered id) ordered)
|
||||
toasts (assoc toasts id opts)
|
||||
db (-> db
|
||||
(update :toasts assoc :ordered ordered :toasts toasts)
|
||||
(update :toasts dissoc :hide-toasts-timer-set))]
|
||||
(if (and (not update?) (= (count ordered) 1))
|
||||
{:show-toasts []
|
||||
:db db}
|
||||
{:db db})))
|
||||
|
||||
(rf/defn create
|
||||
{:events [:toasts/create]}
|
||||
[{:keys [db]} opts]
|
||||
(let [next-toast-id (or (get-in [:toasts :next-toast-id] db) 1)]
|
||||
{:db (assoc-in db [:toasts :next-toast-id] (inc next-toast-id))
|
||||
:dispatch [:toasts/upsert (str "toast-" next-toast-id) opts]}))
|
||||
(let [{:keys [ordered toasts]} (:toasts db)
|
||||
next-toast-number (get-in db [:toasts :next-toast-number] 1)
|
||||
id (or (:id opts)
|
||||
(str "toast-" next-toast-number))
|
||||
update? (some #(= % id) ordered)
|
||||
ordered (if (not update?)
|
||||
(conj ordered id)
|
||||
ordered)
|
||||
toasts (assoc toasts id (dissoc opts :id))]
|
||||
(cond-> {:db (-> db
|
||||
(update :toasts assoc :ordered ordered :toasts toasts)
|
||||
(update :toasts dissoc :hide-toasts-timer-set))}
|
||||
|
||||
(and (not update?) (= (count ordered) 1))
|
||||
(assoc :show-toasts [])
|
||||
|
||||
(not (:id opts))
|
||||
(update-in [:db :toasts :next-toast-number] inc))))
|
||||
|
||||
(rf/defn hide-toasts-with-check
|
||||
{:events [:toasts/hide-with-check]}
|
||||
|
||||
@@ -8,23 +8,28 @@
|
||||
[status-im2.common.toasts.style :as style]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def ^:private slide-out-up-animation
|
||||
(-> ^js reanimated/slide-out-up-animation
|
||||
.springify
|
||||
(.damping 20)
|
||||
(.stiffness 300)))
|
||||
;; (def ^:private slide-out-up-animation
|
||||
;; (-> ^js reanimated/slide-out-up-animation
|
||||
;; .springify
|
||||
;; (.damping 20)
|
||||
;; (.stiffness 300)))
|
||||
|
||||
(def ^:private slide-in-up-animation
|
||||
(-> ^js reanimated/slide-in-up-animation
|
||||
.springify
|
||||
(.damping 20)
|
||||
(.stiffness 300)))
|
||||
;; (def ^:private slide-in-up-animation
|
||||
;; (-> ^js reanimated/slide-in-up-animation
|
||||
;; .springify
|
||||
;; (.damping 20)
|
||||
;; (.stiffness 300)))
|
||||
|
||||
(def ^:private linear-transition
|
||||
(-> ^js reanimated/linear-transition
|
||||
.springify
|
||||
(.damping 20)
|
||||
(.stiffness 300)))
|
||||
;; (def ^:private linear-transition
|
||||
;; (-> ^js reanimated/linear-transition
|
||||
;; .springify
|
||||
;; (.damping 20)
|
||||
;; (.stiffness 300)))
|
||||
|
||||
(defn toast
|
||||
[id]
|
||||
(let [toast-opts (rf/sub [:toasts/toast id])]
|
||||
[quo/toast toast-opts]))
|
||||
|
||||
(defn container
|
||||
[id]
|
||||
@@ -35,13 +40,11 @@
|
||||
(fn []
|
||||
[:f>
|
||||
(fn []
|
||||
(let [toast-opts (rf/sub [:toasts/toast id])
|
||||
duration (get toast-opts :duration 3000)
|
||||
on-dismissed #((get toast-opts :on-dismissed identity) id)
|
||||
translate-y (reanimated/use-shared-value 0)
|
||||
(let [duration (or (rf/sub [:toasts/toast-cursor id :duration]) 3000)
|
||||
on-dismissed #((or (rf/sub [:toasts/toast-cursor id :on-dismissed]) identity) id)
|
||||
create-timer (fn []
|
||||
(reset! timer (utils.utils/set-timeout #(do (close!) (on-dismissed))
|
||||
duration)))
|
||||
(reset! timer (utils.utils/set-timeout close! duration)))
|
||||
translate-y (reanimated/use-shared-value 0)
|
||||
pan
|
||||
(->
|
||||
(gesture/gesture-pan)
|
||||
@@ -78,13 +81,16 @@
|
||||
(rn/use-unmount on-dismissed)
|
||||
[gesture/gesture-detector {:gesture pan}
|
||||
[reanimated/view
|
||||
{:entering slide-in-up-animation
|
||||
:exiting slide-out-up-animation
|
||||
:layout reanimated/linear-transition
|
||||
:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}]}
|
||||
style/each-toast-container)}
|
||||
[quo/toast toast-opts]]]))])))
|
||||
{;; TODO: this will eanble layout animation at runtime and causing flicker on android
|
||||
;; we need to resolve this and re-enable layout animation
|
||||
;; issue at https://github.com/status-im/status-mobile/issues/14752
|
||||
;; :entering slide-in-up-animation
|
||||
;; :exiting slide-out-up-animation
|
||||
;; :layout reanimated/linear-transition
|
||||
:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}]}
|
||||
style/each-toast-container)}
|
||||
[toast id]]]))])))
|
||||
|
||||
(defn toasts
|
||||
[]
|
||||
@@ -92,6 +98,4 @@
|
||||
[into
|
||||
[rn/view
|
||||
{:style style/outmost-transparent-container}]
|
||||
(->> toasts-ordered
|
||||
reverse
|
||||
(map (fn [id] ^{:key id} [container id])))]))
|
||||
(map (fn [id] ^{:key id} [container id]) toasts-ordered)]))
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
[status-im.constants :as constants]
|
||||
[utils.datetime :as datetime]
|
||||
[status-im2.contexts.activity-center.notification.common.view :as common]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[re-frame.core :as re-frame]
|
||||
status-im2.common.bottom-sheet.view))
|
||||
|
||||
(defn- hide-bottom-sheet-and-dispatch
|
||||
[event]
|
||||
(rf/dispatch [:bottom-sheet/hide])
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:dismiss-bottom-sheet])
|
||||
(re-frame/dispatch-sync [:dismiss-keyboard])
|
||||
(rf/dispatch event))
|
||||
|
||||
(defn- context-tags
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
[rn/touchable-opacity
|
||||
{:on-press (fn []
|
||||
(rf/dispatch [:hide-popover])
|
||||
(rf/dispatch [:chat.ui/navigate-to-chat chat-id]))}
|
||||
(rf/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]))}
|
||||
[quo/activity-log
|
||||
{:title (i18n/label :t/mention)
|
||||
:icon :i/mention
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
[rn/touchable-opacity
|
||||
{:on-press (fn []
|
||||
(rf/dispatch [:hide-popover])
|
||||
(rf/dispatch [:chat.ui/navigate-to-chat chat-id]))}
|
||||
(rf/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]))}
|
||||
[quo/activity-log
|
||||
{:title (i18n/label :t/message-reply)
|
||||
:icon :i/reply
|
||||
|
||||
@@ -42,8 +42,9 @@
|
||||
(defn tabs
|
||||
[]
|
||||
(let [filter-type (rf/sub [:activity-center/filter-type])]
|
||||
[quo/scrollable-tabs
|
||||
[quo/tabs
|
||||
{:size 32
|
||||
:scrollable? true
|
||||
:blur? true
|
||||
:override-theme :dark
|
||||
:style style/tabs
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
[status-im.ui2.screens.common.contact-list.view :as contact-list]
|
||||
[status-im2.common.contact-list-item.view :as contact-list-item]
|
||||
[status-im2.common.home.actions.view :as actions]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[re-frame.core :as re-frame]
|
||||
status-im2.common.bottom-sheet.view))
|
||||
|
||||
(defn back-button
|
||||
[]
|
||||
@@ -76,7 +78,7 @@
|
||||
deselected-members (rf/sub [:group-chat/deselected-members])]
|
||||
[rn/view {:style {:height (- window-height (:top safe-area))}}
|
||||
[rn/touchable-opacity
|
||||
{:on-press #(rf/dispatch [:bottom-sheet/hide])
|
||||
{:on-press #(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
:accessibility-label :close-manage-members
|
||||
:style (style/close-icon)}
|
||||
[quo2/icon :i/close {:color (colors/theme-colors colors/neutral-100 colors/white)}]]
|
||||
@@ -97,7 +99,7 @@
|
||||
(rf/dispatch [:group-chats.ui/add-members-pressed])
|
||||
(js/setTimeout #(rf/dispatch [:group-chats.ui/remove-members-pressed])
|
||||
500)
|
||||
(rf/dispatch [:bottom-sheet/hide]))
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet]))
|
||||
:disabled (and (zero? (count selected-participants))
|
||||
(zero? (count deselected-members)))}
|
||||
(i18n/label :t/save)]]]))])
|
||||
@@ -136,6 +138,7 @@
|
||||
{:style (style/action-container color)
|
||||
:accessibility-label :pinned-messages
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:bottom-sheet/show-sheet :pinned-messages-list chat-id]))}
|
||||
[rn/view
|
||||
{:style {:flex-direction :row
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
(ns status-im2.contexts.chat.messages.contact-requests.bottom-drawer
|
||||
(:require
|
||||
[i18n.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[quo2.core :as quo]
|
||||
[quo2.components.drawers.permission-context.view :as permission-context]
|
||||
[status-im2.common.constants :as constants]))
|
||||
|
||||
(defn view
|
||||
[contact-id contact-request-state]
|
||||
(let [names (rf/sub [:contacts/contact-two-names-by-identity contact-id])]
|
||||
[permission-context/view
|
||||
[quo/button
|
||||
{:type :ghost
|
||||
:on-press #(rf/dispatch [:chat.ui/show-profile contact-id])
|
||||
:before :i/communities}
|
||||
(cond
|
||||
(or (= contact-request-state
|
||||
constants/contact-request-state-none)
|
||||
(= contact-request-state
|
||||
constants/contact-request-state-received))
|
||||
(i18n/label :t/contact-request-chat-add {:name (first names)})
|
||||
(= contact-request-state
|
||||
constants/contact-request-state-sent)
|
||||
|
||||
(i18n/label :t/contact-request-chat-pending))]]))
|
||||
@@ -1,6 +1,6 @@
|
||||
(ns status-im2.contexts.chat.messages.content.deleted.view
|
||||
(:require [quo2.core :as quo]
|
||||
[i18n.i18n :as i18n]))
|
||||
(:require [i18n.i18n :as i18n]
|
||||
[quo2.core :as quo]))
|
||||
|
||||
(defn deleted-message
|
||||
[{:keys [deleted? deleted-undoable-till timestamp-str deleted-for-me-undoable-till]}]
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
(let [response-to (:response-to (:content message))
|
||||
default-size 36]
|
||||
[rn/touchable-opacity
|
||||
{:on-press #(rf/dispatch [:bottom-sheet/show-sheet :pinned-messages-list chat-id])
|
||||
{:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:bottom-sheet/show-sheet :pinned-messages-list chat-id]))
|
||||
:active-opacity 1
|
||||
:style (merge {:flex-direction :row :margin-vertical 8}
|
||||
(old-style/message-wrapper message))}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
(:require [status-im2.common.constants :as constants]
|
||||
[quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.messages.drawers.view :as drawers]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn message-reactions-row
|
||||
[chat-id message-id]
|
||||
@@ -27,5 +26,7 @@
|
||||
:emoji-id emoji-id}]))
|
||||
:accessibility-label (str "emoji-reaction-" emoji-id)}]])
|
||||
[quo/add-reaction
|
||||
{:on-press #(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn [] [drawers/reactions chat-id message-id])}])}]])))
|
||||
{:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:bottom-sheet/show-sheet :drawer/reactions
|
||||
{:chat-id chat-id :message-id message-id}]))}]])))
|
||||
|
||||
@@ -69,8 +69,11 @@
|
||||
{:underlay-color (colors/theme-colors colors/neutral-5 colors/neutral-90)
|
||||
:style {:border-radius 16}
|
||||
:on-press #()
|
||||
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (drawers/reactions-and-actions message-data context)}])}
|
||||
:on-long-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (drawers/reactions-and-actions message-data
|
||||
context)}]))}
|
||||
[rn/view {:padding-vertical 8}
|
||||
(when (and (seq response-to) quoted-message)
|
||||
[old-message/quoted-message {:message-id response-to :chat-id chat-id} quoted-message])
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
(ns status-im2.contexts.chat.messages.delete-message.events
|
||||
(:require [status-im.chat.models.message-list :as message-list]
|
||||
[utils.datetime :as datetime]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
(:require
|
||||
[i18n.i18n :as i18n]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im.chat.models.message-list :as message-list]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- update-db-clear-undo-timer
|
||||
[db chat-id message-id]
|
||||
@@ -20,8 +23,7 @@
|
||||
[:messages chat-id message-id]
|
||||
assoc
|
||||
:deleted? true
|
||||
:deleted-undoable-till (+ (datetime/timestamp)
|
||||
undo-time-limit-ms))))
|
||||
:deleted-undoable-till (+ (datetime/timestamp) undo-time-limit-ms))))
|
||||
|
||||
(defn- update-db-undo-locally
|
||||
"Restore deleted message if called within timelimit"
|
||||
@@ -48,15 +50,44 @@
|
||||
{:events [:chat.ui/delete-message]}
|
||||
[{:keys [db]} {:keys [chat-id message-id]} undo-time-limit-ms]
|
||||
(when (get-in db [:messages chat-id message-id])
|
||||
(assoc
|
||||
(message-list/rebuild-message-list
|
||||
{:db (update-db-delete-locally db chat-id message-id undo-time-limit-ms)}
|
||||
chat-id)
|
||||
:utils/dispatch-later
|
||||
[{:dispatch [:chat.ui/delete-message-and-send
|
||||
{:chat-id chat-id
|
||||
:message-id message-id}]
|
||||
:ms undo-time-limit-ms}])))
|
||||
;; all delete message toast are the same toast with id :delete-message-for-everyone
|
||||
;; new delete operation will reset prev pending deletes' undo timelimit
|
||||
;; undo will undo all pending deletes
|
||||
;; all pending deletes are stored in toast
|
||||
(let [existing-undo-toast (get-in db [:toasts :toasts :delete-message-for-everyone])
|
||||
toast-count (inc (get existing-undo-toast :message-deleted-for-everyone-count 0))
|
||||
existing-undos (-> existing-undo-toast
|
||||
(get :message-deleted-for-everyone-undos [])
|
||||
(conj {:message-id message-id :chat-id chat-id}))]
|
||||
(assoc
|
||||
(message-list/rebuild-message-list
|
||||
{:db (reduce
|
||||
;; sync all pending deletes' undo timelimit, extend to the latest one
|
||||
(fn [db-acc {:keys [chat-id message-id]}]
|
||||
(update-db-delete-locally db-acc chat-id message-id undo-time-limit-ms))
|
||||
db
|
||||
existing-undos)}
|
||||
chat-id)
|
||||
|
||||
:dispatch-n
|
||||
[[:toasts/close :delete-message-for-everyone]
|
||||
[:toasts/upsert
|
||||
{:id :delete-message-for-everyone
|
||||
:icon :info
|
||||
:icon-color colors/danger-50-opa-40
|
||||
:message-deleted-for-everyone-count toast-count
|
||||
:message-deleted-for-everyone-undos existing-undos
|
||||
:text (i18n/label-pluralize
|
||||
toast-count
|
||||
:t/message-deleted-for-everyone-count)
|
||||
:duration undo-time-limit-ms
|
||||
:undo-duration (/ undo-time-limit-ms 1000)
|
||||
:undo-on-press #(do (rf/dispatch [:chat.ui/undo-all-delete-message])
|
||||
(rf/dispatch [:toasts/close
|
||||
:delete-message-for-everyone]))}]]
|
||||
:utils/dispatch-later [{:dispatch [:chat.ui/delete-message-and-send
|
||||
{:chat-id chat-id :message-id message-id}]
|
||||
:ms undo-time-limit-ms}]))))
|
||||
|
||||
(rf/defn undo
|
||||
{:events [:chat.ui/undo-delete-message]}
|
||||
@@ -66,22 +97,41 @@
|
||||
{:db (update-db-undo-locally db chat-id message-id)}
|
||||
chat-id)))
|
||||
|
||||
(rf/defn undo-all
|
||||
{:events [:chat.ui/undo-all-delete-message]}
|
||||
[{:keys [db]}]
|
||||
(when-let [pending-undos (get-in db
|
||||
[:toasts :toasts :delete-message-for-everyone
|
||||
:message-deleted-for-everyone-undos])]
|
||||
{:dispatch-n (mapv #(vector :chat.ui/undo-delete-message %) pending-undos)}))
|
||||
|
||||
(defn- check-before-delete-and-send
|
||||
"make sure message alredy deleted? locally and undo timelimit has passed"
|
||||
[db chat-id message-id]
|
||||
(let [message (get-in db [:messages chat-id message-id])
|
||||
{:keys [deleted? deleted-undoable-till]} message]
|
||||
(and deleted?
|
||||
deleted-undoable-till
|
||||
(>= (datetime/timestamp) deleted-undoable-till))))
|
||||
|
||||
(rf/defn delete-and-send
|
||||
{:events [:chat.ui/delete-message-and-send]}
|
||||
[{:keys [db]} {:keys [message-id chat-id]}]
|
||||
[{:keys [db]} {:keys [message-id chat-id]} force?]
|
||||
(when-let [message (get-in db [:messages chat-id message-id])]
|
||||
(cond-> {:db (update-db-clear-undo-timer db chat-id message-id)
|
||||
:json-rpc/call [{:method "wakuext_deleteMessageAndSend"
|
||||
:params [message-id]
|
||||
:js-response true
|
||||
:on-error #(log/error "failed to delete message "
|
||||
{:message-id message-id :error %})
|
||||
:on-success #(rf/dispatch [:sanitize-messages-and-process-response
|
||||
%])}]}
|
||||
(get-in db [:pin-messages chat-id message-id])
|
||||
(assoc :dispatch
|
||||
[:pin-message/send-pin-message
|
||||
{:chat-id chat-id :message-id message-id :pinned false}]))))
|
||||
(when (or force? (check-before-delete-and-send db chat-id message-id))
|
||||
(cond-> {:db (update-db-clear-undo-timer db chat-id message-id)
|
||||
:json-rpc/call [{:method "wakuext_deleteMessageAndSend"
|
||||
:params [message-id]
|
||||
:js-response true
|
||||
:on-error #(log/error "failed to delete message "
|
||||
{:message-id message-id :error %})
|
||||
:on-success #(rf/dispatch
|
||||
[:sanitize-messages-and-process-response
|
||||
%])}]}
|
||||
(get-in db [:pin-messages chat-id message-id])
|
||||
(assoc :dispatch
|
||||
[:pin-message/send-pin-message
|
||||
{:chat-id chat-id :message-id message-id :pinned false}])))))
|
||||
|
||||
(defn- filter-pending-send-messages
|
||||
"traverse all messages find not yet synced deleted? messages"
|
||||
@@ -96,7 +146,7 @@
|
||||
{:events [:chat.ui/send-all-deleted-messages]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [pending-send-messages (reduce-kv filter-pending-send-messages [] (:messages db))]
|
||||
(apply rf/merge cofx (map delete-and-send pending-send-messages))))
|
||||
(apply rf/merge cofx (map #(delete-and-send % true) pending-send-messages))))
|
||||
|
||||
(rf/defn delete-messages-localy
|
||||
"Mark messages :deleted? localy in client"
|
||||
|
||||
@@ -15,11 +15,46 @@
|
||||
(let [result-message (get-in (delete-message/delete {:db db} message 1000)
|
||||
[:db :messages cid mid])]
|
||||
(is (= (:id result-message) mid))
|
||||
(is (true? (:deleted? result-message)))
|
||||
(is (= (:deleted-undoable-till result-message) 1001))))
|
||||
(is (true? (:deleted? result-message)) "mark message :deleted?")
|
||||
(is (= (:deleted-undoable-till result-message) 1001) "set message undo timelimit")))
|
||||
(testing "delete with pending deletes"
|
||||
(let [db (-> db
|
||||
(update-in [:messages cid "pending-delete-message"]
|
||||
assoc
|
||||
:deleted? true
|
||||
:deleted-undoable-till 0
|
||||
:whisper-timestamp 0)
|
||||
(update-in [:toasts :toasts :delete-message-for-everyone]
|
||||
assoc
|
||||
:message-deleted-for-everyone-count 1
|
||||
:message-deleted-for-everyone-undos [{:message-id
|
||||
"pending-delete-message"
|
||||
:chat-id cid}]))
|
||||
effects (delete-message/delete {:db db} message 1000)]
|
||||
(is (= (get-in effects [:db :messages cid mid :deleted-undoable-till])
|
||||
(get-in effects [:db :messages cid "pending-delete-message" :deleted-undoable-till])
|
||||
1001)
|
||||
"sync all pending delete undo timelimit")
|
||||
(let [upsert-toast (-> effects :dispatch-n second)]
|
||||
(is (= (-> upsert-toast last :message-deleted-for-everyone-count) 2)
|
||||
"+1 pending deletes")
|
||||
(is
|
||||
(and
|
||||
(-> upsert-toast
|
||||
last
|
||||
:message-deleted-for-everyone-undos
|
||||
first
|
||||
:message-id
|
||||
(= "pending-delete-message"))
|
||||
(-> upsert-toast
|
||||
last
|
||||
:message-deleted-for-everyone-undos
|
||||
second
|
||||
:message-id
|
||||
(= mid)))
|
||||
"pending deletes are in order"))))
|
||||
(testing "return nil if message not in db"
|
||||
(is (= (delete-message/delete {:db {:messages []}} message 1000)
|
||||
nil)))))))
|
||||
(is (= (delete-message/delete {:db {:messages []}} message 1000) nil)))))))
|
||||
|
||||
(deftest undo-delete
|
||||
(let [db {:messages {cid {mid {:id mid :whisper-timestamp 1}}}}
|
||||
@@ -30,14 +65,11 @@
|
||||
[:messages cid mid]
|
||||
assoc
|
||||
:deleted? true
|
||||
:deleted-undoable-till
|
||||
(+ (datetime/timestamp) 1000))
|
||||
result-message (get-in (delete-message/undo {:db db} message)
|
||||
[:db :messages cid mid])]
|
||||
:deleted-undoable-till (+ (datetime/timestamp) 1000))
|
||||
result-message (get-in (delete-message/undo {:db db} message) [:db :messages cid mid])]
|
||||
(is (= (:id result-message) mid))
|
||||
(is (nil? (:deleted? result-message)))
|
||||
(is (nil? (:deleted-undoable-till result-message)))))
|
||||
|
||||
(testing "remain deleted when undo after timelimit"
|
||||
(let [db (update-in db
|
||||
[:messages cid mid]
|
||||
@@ -48,47 +80,46 @@
|
||||
(is (= (:id result-message) mid))
|
||||
(is (nil? (:deleted-undoable-till result-message)))
|
||||
(is (true? (:deleted? result-message)))))
|
||||
|
||||
(testing "return nil if message not in db"
|
||||
(is (= (delete-message/undo {:db {:messages []}} message)
|
||||
nil))))))
|
||||
(is (= (delete-message/undo {:db {:messages []}} message) nil))))))
|
||||
|
||||
(deftest delete-and-send
|
||||
(let [db {:messages {cid {mid {:id mid}}}}
|
||||
(let [db {:messages {cid {mid {:id mid :deleted? true :deleted-undoable-till 0}}}}
|
||||
message {:message-id mid :chat-id cid}]
|
||||
(testing "delete and send"
|
||||
(testing "dispatch right rpc call fx"
|
||||
(let [expected-db {:messages {cid {mid {:id mid}}}}
|
||||
effects (delete-message/delete-and-send {:db db} message)
|
||||
(let [expected-db {:messages {cid {mid {:id mid :deleted? true}}}}
|
||||
effects (delete-message/delete-and-send {:db db} message false)
|
||||
result-db (:db effects)
|
||||
rpc-calls (:json-rpc/call effects)]
|
||||
(is (= result-db expected-db))
|
||||
(is (= (count rpc-calls) 1))
|
||||
(is (= (-> rpc-calls
|
||||
first
|
||||
:method)
|
||||
"wakuext_deleteMessageAndSend"))
|
||||
(is (= (-> rpc-calls
|
||||
first
|
||||
:params
|
||||
count)
|
||||
1))
|
||||
(is (= (-> rpc-calls
|
||||
first
|
||||
:params
|
||||
first)
|
||||
mid))))
|
||||
(is (= (-> rpc-calls first :method) "wakuext_deleteMessageAndSend"))
|
||||
(is (= (-> rpc-calls first :params count) 1))
|
||||
(is (= (-> rpc-calls first :params first) mid))))
|
||||
(testing "clean undo timer"
|
||||
(let [expected-db {:messages {cid {mid {:id mid}}}}
|
||||
(let [expected-db {:messages {cid {mid {:id mid :deleted? true}}}}
|
||||
effects (delete-message/delete-and-send
|
||||
{:db (update-in db
|
||||
[:messages cid mid
|
||||
:deleted-undoable-till]
|
||||
[:messages cid mid :deleted-undoable-till]
|
||||
(constantly (datetime/timestamp)))}
|
||||
message)
|
||||
message
|
||||
false)
|
||||
result-db (:db effects)]
|
||||
(is (= result-db expected-db))))
|
||||
(testing "before deleted locally"
|
||||
(let [effects (delete-message/delete-and-send
|
||||
{:db (update-in db [:messages cid mid] dissoc :deleted?)}
|
||||
message
|
||||
false)]
|
||||
(is (-> effects :db nil?) "not delete and send")))
|
||||
(testing "before undo timelimit"
|
||||
(with-redefs [datetime/timestamp (constantly 1)]
|
||||
(let [effects (delete-message/delete-and-send
|
||||
{:db (update-in db [:messages cid mid] assoc :deleted-undoable-till 2)}
|
||||
message
|
||||
false)]
|
||||
(is (-> effects :db nil?)))))
|
||||
(testing "return nil if message not in db"
|
||||
(is (= (delete-message/delete-and-send {:db {:messages []}}
|
||||
message)
|
||||
(is (= (delete-message/delete-and-send {:db {:messages []}} message false)
|
||||
nil))))))
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
(ns status-im2.contexts.chat.messages.delete-message-for-me.events
|
||||
(:require [status-im.chat.models.message-list :as message-list]
|
||||
[utils.datetime :as datetime]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
(:require
|
||||
[i18n.i18n :as i18n]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im.chat.models.message-list :as message-list]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- update-db-clear-undo-timer
|
||||
[db chat-id message-id]
|
||||
@@ -42,15 +45,38 @@
|
||||
{:events [:chat.ui/delete-message-for-me]}
|
||||
[{:keys [db]} {:keys [chat-id message-id]} undo-time-limit-ms]
|
||||
(when (get-in db [:messages chat-id message-id])
|
||||
(assoc
|
||||
(message-list/rebuild-message-list
|
||||
{:db (update-db-delete-locally db chat-id message-id undo-time-limit-ms)}
|
||||
chat-id)
|
||||
:utils/dispatch-later
|
||||
[{:dispatch [:chat.ui/delete-message-for-me-and-sync
|
||||
{:chat-id chat-id
|
||||
:message-id message-id}]
|
||||
:ms undo-time-limit-ms}])))
|
||||
(let [existing-undo-toast (get-in db [:toasts :toasts :delete-message-for-me])
|
||||
toast-count (inc (get existing-undo-toast :message-deleted-for-me-count 0))
|
||||
existing-undos (-> existing-undo-toast
|
||||
(get :message-deleted-for-me-undos [])
|
||||
(conj {:message-id message-id :chat-id chat-id}))]
|
||||
(assoc
|
||||
(message-list/rebuild-message-list
|
||||
{:db (reduce
|
||||
;; sync all pending deletes' undo timelimit, extend to the latest one
|
||||
(fn [db-acc {:keys [message-id chat-id]}]
|
||||
(update-db-delete-locally db-acc chat-id message-id undo-time-limit-ms))
|
||||
db
|
||||
existing-undos)}
|
||||
chat-id)
|
||||
:dispatch-n [[:toasts/close :delete-message-for-me]
|
||||
[:toasts/upsert
|
||||
{:id :delete-message-for-me
|
||||
:icon :info
|
||||
:icon-color colors/danger-50-opa-40
|
||||
:message-deleted-for-me-count toast-count
|
||||
:message-deleted-for-me-undos existing-undos
|
||||
:text (i18n/label-pluralize toast-count
|
||||
:t/message-deleted-for-you-count)
|
||||
:duration undo-time-limit-ms
|
||||
:undo-duration (/ undo-time-limit-ms 1000)
|
||||
:undo-on-press #(do (rf/dispatch
|
||||
[:chat.ui/undo-all-delete-message-for-me])
|
||||
(rf/dispatch [:toasts/close
|
||||
:delete-message-for-me]))}]]
|
||||
:utils/dispatch-later [{:dispatch [:chat.ui/delete-message-for-me-and-sync
|
||||
{:chat-id chat-id :message-id message-id}]
|
||||
:ms undo-time-limit-ms}]))))
|
||||
|
||||
(rf/defn undo
|
||||
{:events [:chat.ui/undo-delete-message-for-me]}
|
||||
@@ -60,17 +86,37 @@
|
||||
{:db (update-db-undo-locally db chat-id message-id)}
|
||||
chat-id)))
|
||||
|
||||
(rf/defn undo-all
|
||||
{:events [:chat.ui/undo-all-delete-message-for-me]}
|
||||
[{:keys [db]}]
|
||||
(when-let [pending-undos (get-in db
|
||||
[:toasts :toasts :delete-message-for-me
|
||||
:message-deleted-for-me-undos])]
|
||||
{:dispatch-n (mapv #(vector :chat.ui/undo-delete-message-for-me %) pending-undos)}))
|
||||
|
||||
(defn- check-before-delete-and-sync
|
||||
"Make sure message alredy deleted-for-me? locally and undo timelimit has passed"
|
||||
[db chat-id message-id]
|
||||
(let [message (get-in db [:messages chat-id message-id])
|
||||
{:keys [deleted-for-me? deleted-for-me-undoable-till]} message]
|
||||
(and deleted-for-me?
|
||||
deleted-for-me-undoable-till
|
||||
(>= (datetime/timestamp) deleted-for-me-undoable-till))))
|
||||
|
||||
(rf/defn delete-and-sync
|
||||
{:events [:chat.ui/delete-message-for-me-and-sync]}
|
||||
[{:keys [db]} {:keys [message-id chat-id]}]
|
||||
(when (get-in db [:messages chat-id message-id])
|
||||
{:db (update-db-clear-undo-timer db chat-id message-id)
|
||||
:json-rpc/call [{:method "wakuext_deleteMessageForMeAndSync"
|
||||
:params [chat-id message-id]
|
||||
:js-response true
|
||||
:on-error #(log/error "failed to delete message for me, message id: "
|
||||
{:message-id message-id :error %})
|
||||
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])}]}))
|
||||
[{:keys [db]} {:keys [message-id chat-id]} force?]
|
||||
(when-let [message (get-in db [:messages chat-id message-id])]
|
||||
(when (or force? (check-before-delete-and-sync db chat-id message-id))
|
||||
{:db (update-db-clear-undo-timer db chat-id message-id)
|
||||
:json-rpc/call [{:method "wakuext_deleteMessageForMeAndSync"
|
||||
:params [chat-id message-id]
|
||||
:js-response true
|
||||
:on-error #(log/error
|
||||
"failed to delete message for me, message id: "
|
||||
{:message-id message-id :error %})
|
||||
:on-success #(rf/dispatch [:sanitize-messages-and-process-response
|
||||
%])}]})))
|
||||
|
||||
(defn- filter-pending-sync-messages
|
||||
"traverse all messages find not yet synced deleted-for-me? messages"
|
||||
@@ -86,4 +132,4 @@
|
||||
{:events [:chat.ui/sync-all-deleted-for-me-messages]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [pending-sync-messages (reduce-kv filter-pending-sync-messages [] (:messages db))]
|
||||
(apply rf/merge cofx (map delete-and-sync pending-sync-messages))))
|
||||
(apply rf/merge cofx (map #(delete-and-sync % true) pending-sync-messages))))
|
||||
|
||||
@@ -18,6 +18,43 @@
|
||||
(is (= (:id result-message) mid))
|
||||
(is (true? (:deleted-for-me? result-message)))
|
||||
(is (= (:deleted-for-me-undoable-till result-message) 1001))))
|
||||
(testing "delete with pending deletes"
|
||||
(let [db (-> db
|
||||
(update-in [:messages cid "pending-delete-message"]
|
||||
assoc
|
||||
:deleted-for-me? true
|
||||
:deleted-for-me-undoable-till 0
|
||||
:whisper-timestamp 0)
|
||||
(update-in [:toasts :toasts :delete-message-for-me]
|
||||
assoc
|
||||
:message-deleted-for-me-count 1
|
||||
:message-deleted-for-me-undos [{:message-id
|
||||
"pending-delete-message"
|
||||
:chat-id cid}]))
|
||||
effects (delete-message-for-me/delete {:db db} message 1000)]
|
||||
(is (= (get-in effects [:db :messages cid mid :deleted-for-me-undoable-till])
|
||||
(get-in effects
|
||||
[:db :messages cid "pending-delete-message" :deleted-for-me-undoable-till])
|
||||
1001)
|
||||
"sync all pending delete undo timelimit")
|
||||
(let [upsert-toast (-> effects :dispatch-n second)]
|
||||
(is (= (-> upsert-toast last :message-deleted-for-me-count) 2)
|
||||
"+1 pending deletes")
|
||||
(is
|
||||
(and
|
||||
(-> upsert-toast
|
||||
last
|
||||
:message-deleted-for-me-undos
|
||||
first
|
||||
:message-id
|
||||
(= "pending-delete-message"))
|
||||
(-> upsert-toast
|
||||
last
|
||||
:message-deleted-for-me-undos
|
||||
second
|
||||
:message-id
|
||||
(= mid)))
|
||||
"pending deletes are in order"))))
|
||||
(testing "return nil if message not in db"
|
||||
(is (= (delete-message-for-me/delete {:db {:messages []}} message 1000)
|
||||
nil)))))))
|
||||
@@ -56,46 +93,42 @@
|
||||
nil))))))
|
||||
|
||||
(deftest delete-for-me-and-sync
|
||||
(let [db {:messages {cid {mid {:id mid}}}}
|
||||
(let [db {:messages {cid {mid {:id mid :deleted-for-me? true :deleted-for-me-undoable-till 0}}}}
|
||||
message {:message-id mid :chat-id cid}]
|
||||
(testing "delete for me and sync"
|
||||
(testing "dispatch right rpc call"
|
||||
(let [expected-db {:messages {cid {mid {:id mid}}}}
|
||||
effects (delete-message-for-me/delete-and-sync {:db db} message)
|
||||
(let [expected-db {:messages {cid {mid {:id mid :deleted-for-me? true}}}}
|
||||
effects (delete-message-for-me/delete-and-sync {:db db} message false)
|
||||
result-db (:db effects)
|
||||
rpc-calls (:json-rpc/call effects)]
|
||||
(is (= result-db expected-db))
|
||||
(is (= (count rpc-calls) 1))
|
||||
(is (= (-> rpc-calls
|
||||
first
|
||||
:method)
|
||||
"wakuext_deleteMessageForMeAndSync"))
|
||||
(is (= (-> rpc-calls
|
||||
first
|
||||
:params
|
||||
count)
|
||||
2))
|
||||
(is (= (-> rpc-calls
|
||||
first
|
||||
:params
|
||||
first)
|
||||
cid))
|
||||
(is (= (-> rpc-calls
|
||||
first
|
||||
:params
|
||||
second)
|
||||
mid))))
|
||||
(is (= (-> rpc-calls first :method) "wakuext_deleteMessageForMeAndSync"))
|
||||
(is (= (-> rpc-calls first :params count) 2))
|
||||
(is (= (-> rpc-calls first :params first) cid))
|
||||
(is (= (-> rpc-calls first :params second) mid))))
|
||||
(testing "clean undo timer"
|
||||
(let [expected-db {:messages {cid {mid {:id mid}}}}
|
||||
(let [expected-db {:messages {cid {mid {:id mid :deleted-for-me? true}}}}
|
||||
effects (delete-message-for-me/delete-and-sync
|
||||
{:db (update-in db
|
||||
[:messages cid mid
|
||||
:deleted-for-me-undoable-till]
|
||||
[:messages cid mid :deleted-for-me-undoable-till]
|
||||
(constantly (datetime/timestamp)))}
|
||||
message)
|
||||
message
|
||||
false)
|
||||
result-db (:db effects)]
|
||||
(is (= result-db expected-db))))
|
||||
(testing "before deleted locally"
|
||||
(let [effects (delete-message-for-me/delete-and-sync
|
||||
{:db (update-in db [:messages cid mid] dissoc :deleted-for-me?)}
|
||||
message
|
||||
false)]
|
||||
(is (-> effects :db nil?) "not delete and send")))
|
||||
(testing "before undo timelimit"
|
||||
(with-redefs [datetime/timestamp (constantly 1)]
|
||||
(let [effects (delete-message-for-me/delete-and-sync
|
||||
{:db (update-in db [:messages cid mid] assoc :deleted-for-me-undoable-till 2)}
|
||||
message
|
||||
false)]
|
||||
(is (-> effects :db nil?)))))
|
||||
(testing "return nil if message not in db"
|
||||
(is (= (delete-message-for-me/delete-and-sync {:db {:messages []}}
|
||||
message)
|
||||
nil))))))
|
||||
(is (= (delete-message-for-me/delete-and-sync {:db {:messages []}} message false) nil))))))
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
[status-im2.setup.config :as config]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui2.screens.chat.components.reply :as components.reply]
|
||||
[status-im2.common.not-implemented :as not-implemented]))
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[re-frame.core :as re-frame]
|
||||
status-im2.common.bottom-sheet.view))
|
||||
|
||||
(defn pin-message
|
||||
[{:keys [chat-id pinned] :as message-data}]
|
||||
@@ -51,15 +53,19 @@
|
||||
:id (if pinned :unpin :pin)}])
|
||||
(when-not pinned
|
||||
[{:type :danger
|
||||
:on-press #(rf/dispatch [:chat.ui/delete-message-for-me message-data
|
||||
constants/delete-message-for-me-undo-time-limit-ms])
|
||||
:on-press #(do
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
(rf/dispatch [:chat.ui/delete-message-for-me message-data
|
||||
constants/delete-message-for-me-undo-time-limit-ms]))
|
||||
:label (i18n/label :t/delete-for-me)
|
||||
:icon :i/delete
|
||||
:id :delete-for-me}])
|
||||
(when (and (or outgoing can-delete-message-for-everyone?) config/delete-message-enabled?)
|
||||
[{:type :danger
|
||||
:on-press #(rf/dispatch [:chat.ui/delete-message message-data
|
||||
constants/delete-message-undo-time-limit-ms])
|
||||
:on-press #(do
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
(rf/dispatch [:chat.ui/delete-message message-data
|
||||
constants/delete-message-undo-time-limit-ms]))
|
||||
:label (i18n/label :t/delete-for-everyone)
|
||||
:icon :i/delete
|
||||
:id :delete-for-all}])))
|
||||
@@ -72,7 +78,7 @@
|
||||
:emoji-reaction-id))
|
||||
|
||||
(defn reactions
|
||||
[chat-id message-id]
|
||||
[{:keys [chat-id message-id]}]
|
||||
(let [reactions (rf/sub [:chats/message-reactions message-id chat-id])
|
||||
own-reactions (reduce (fn [acc {:keys [emoji-id own emoji-reaction-id]}]
|
||||
(if own
|
||||
@@ -107,7 +113,7 @@
|
||||
(rf/dispatch [:models.reactions/send-emoji-reaction
|
||||
{:message-id message-id
|
||||
:emoji-id id}]))
|
||||
(rf/dispatch [:bottom-sheet/hide]))})
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet]))})
|
||||
icon]])))]))
|
||||
|
||||
(defn reactions-and-actions
|
||||
@@ -119,7 +125,7 @@
|
||||
admin-actions (filter #(= (:type %) :admin) actions)]
|
||||
[:<>
|
||||
;; REACTIONS
|
||||
[reactions chat-id message-id]
|
||||
[reactions {:chat-id chat-id :message-id message-id}]
|
||||
|
||||
;; MAIN ACTIONS
|
||||
[rn/view {:style {:padding-horizontal 8}}
|
||||
@@ -133,7 +139,7 @@
|
||||
:icon (:icon action)
|
||||
:on-press #(do
|
||||
(when on-press (on-press))
|
||||
(rf/dispatch [:bottom-sheet/hide]))}]))
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet]))}]))
|
||||
(when-not (empty? danger-actions)
|
||||
[quo/separator])
|
||||
|
||||
@@ -148,7 +154,7 @@
|
||||
:icon (:icon action)
|
||||
:on-press #(do
|
||||
(when on-press (on-press))
|
||||
(rf/dispatch [:bottom-sheet/hide]))}]))
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet]))}]))
|
||||
(when-not (empty? admin-actions)
|
||||
[quo/separator])
|
||||
|
||||
@@ -163,4 +169,4 @@
|
||||
:icon (:icon action)
|
||||
:on-press #(do
|
||||
(when on-press (on-press))
|
||||
(rf/dispatch [:bottom-sheet/hide]))}]))]])))
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet]))}]))]])))
|
||||
|
||||
@@ -131,18 +131,12 @@
|
||||
[{:keys [chat
|
||||
pan-responder
|
||||
show-input?]}]
|
||||
(let [{:keys [group-chat chat-type chat-id public? community-id admins]} chat
|
||||
mutual-contact-requests-enabled? (rf/sub [:mutual-contact-requests/enabled?])
|
||||
messages (rf/sub [:chats/raw-chat-messages-stream chat-id])
|
||||
one-to-one? (= chat-type constants/one-to-one-chat-type)
|
||||
contact-added? (when one-to-one? (rf/sub [:contacts/contact-added? chat-id]))
|
||||
should-send-contact-request?
|
||||
(and
|
||||
mutual-contact-requests-enabled?
|
||||
one-to-one?
|
||||
(not contact-added?))
|
||||
bottom-space 15]
|
||||
[:<>
|
||||
(let [{:keys [group-chat chat-id public? community-id admins]} chat
|
||||
messages (rf/sub [:chats/raw-chat-messages-stream
|
||||
chat-id])
|
||||
bottom-space 15]
|
||||
[rn/view
|
||||
{:style {:flex 1}}
|
||||
;;DO NOT use anonymous functions for handlers
|
||||
[rn/flat-list
|
||||
(merge
|
||||
@@ -151,7 +145,7 @@
|
||||
:ref list-ref
|
||||
:header [list-header chat]
|
||||
:footer [list-footer chat]
|
||||
:data (when-not should-send-contact-request? messages)
|
||||
:data messages
|
||||
:render-data (get-render-data {:group-chat group-chat
|
||||
:chat-id chat-id
|
||||
:public? public?
|
||||
@@ -164,7 +158,7 @@
|
||||
:on-viewable-items-changed on-viewable-items-changed
|
||||
:on-end-reached list-on-end-reached
|
||||
:on-scroll-to-index-failed identity ;;don't remove this
|
||||
:content-container-style {:padding-top (+ bottom-space 16)
|
||||
:content-container-style {:padding-top (+ bottom-space 32)
|
||||
:padding-bottom 16}
|
||||
:scroll-indicator-insets {:top bottom-space} ;;ios only
|
||||
:keyboard-dismiss-mode :interactive
|
||||
@@ -180,10 +174,10 @@
|
||||
[quo/floating-shell-button
|
||||
(merge {:jump-to
|
||||
{:on-press #(do
|
||||
(rf/dispatch [:close-chat])
|
||||
(rf/dispatch [:close-chat true])
|
||||
(rf/dispatch [:shell/navigate-to-jump-to]))
|
||||
:label (i18n/label :t/jump-to)}}
|
||||
(when @show-floating-scroll-down-button
|
||||
{:scroll-to-bottom {:on-press scroll-to-bottom}}))
|
||||
{:position :absolute
|
||||
:bottom 12}]]))
|
||||
:bottom 6}]]))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(ns status-im2.contexts.chat.messages.pin.banner.view
|
||||
(:require [status-im.ui2.screens.chat.pinned-banner.view :as pinned-banner]
|
||||
(:require [quo2.core :as quo]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn banner
|
||||
@@ -7,14 +7,16 @@
|
||||
(let [pinned-messages (rf/sub [:chats/pinned chat-id])
|
||||
latest-pin-id (-> pinned-messages
|
||||
vals
|
||||
last
|
||||
first
|
||||
(get :message-id))
|
||||
latest-pin-text (get-in (rf/sub [:chats/chat-messages chat-id])
|
||||
[latest-pin-id :content :text])
|
||||
pins-count (count (seq pinned-messages))]
|
||||
(when (> pins-count 0)
|
||||
;; TODO (flexsurfer) this should be banner component in quo2
|
||||
[pinned-banner/pinned-banner
|
||||
{:latest-pin-text latest-pin-text
|
||||
:pins-count pins-count
|
||||
:on-press #(rf/dispatch [:bottom-sheet/show-sheet :pinned-messages-list chat-id])}])))
|
||||
[quo/banner
|
||||
{:latest-pin-text latest-pin-text
|
||||
:pins-count pins-count
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:bottom-sheet/show-sheet :pinned-messages-list chat-id]))}]))
|
||||
|
||||
|
||||
|
||||
@@ -7,18 +7,24 @@
|
||||
[status-im.ui2.screens.chat.pin-limit-popover.view :as pin-limit-popover]
|
||||
[status-im2.common.constants :as constants]
|
||||
[status-im2.contexts.chat.messages.list.view :as messages.list]
|
||||
[status-im2.contexts.chat.messages.contact-requests.bottom-drawer :as
|
||||
contact-requests.bottom-drawer]
|
||||
[status-im2.contexts.chat.messages.pin.banner.view :as pin.banner] ;;TODO move to status-im2
|
||||
[status-im2.navigation.state :as navigation.state]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.common.not-implemented :as not-implemented]))
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn navigate-back-handler
|
||||
[]
|
||||
(when (and (not @navigation.state/curr-modal) (= (get @re-frame.db/app-db :view-id) :chat))
|
||||
(rn/hw-back-remove-listener navigate-back-handler)
|
||||
(rf/dispatch [:close-chat])
|
||||
(rf/dispatch [:navigate-back])))
|
||||
(rf/dispatch [:navigate-back])
|
||||
;; If true is not returned back button event will bubble up,
|
||||
;; and will call system back button action
|
||||
true))
|
||||
|
||||
(defn page-nav
|
||||
[]
|
||||
@@ -32,44 +38,56 @@
|
||||
[quo/page-nav
|
||||
{:align-mid? true
|
||||
|
||||
:mid-section
|
||||
(if group-chat
|
||||
{:type :text-only
|
||||
:main-text display-name}
|
||||
{:type :user-avatar
|
||||
:avatar {:full-name display-name
|
||||
:online? online?
|
||||
:profile-picture photo-path
|
||||
:size :medium}
|
||||
:main-text display-name
|
||||
:on-press #(debounce/dispatch-and-chill [:chat.ui/show-profile chat-id] 1000)})
|
||||
:mid-section (if group-chat
|
||||
{:type :text-only
|
||||
:main-text display-name}
|
||||
{:type :user-avatar
|
||||
:avatar {:full-name display-name
|
||||
:online? online?
|
||||
:profile-picture photo-path
|
||||
:size :medium}
|
||||
:main-text display-name
|
||||
:on-press #(debounce/dispatch-and-chill [:chat.ui/show-profile chat-id]
|
||||
1000)})
|
||||
|
||||
:left-section
|
||||
{:on-press #(do
|
||||
(rf/dispatch [:close-chat])
|
||||
(rf/dispatch [:navigate-back]))
|
||||
:icon :i/arrow-left
|
||||
:accessibility-label :back-button}
|
||||
:left-section {:on-press #(do
|
||||
(rf/dispatch [:close-chat])
|
||||
(rf/dispatch [:navigate-back]))
|
||||
:icon :i/arrow-left
|
||||
:accessibility-label :back-button}
|
||||
|
||||
:right-section-buttons
|
||||
[{:on-press #()
|
||||
:style {:border-width 1 :border-color :red}
|
||||
:icon :i/options
|
||||
:accessibility-label :options-button}]}]))
|
||||
:right-section-buttons [{:on-press #()
|
||||
:style {:border-width 1
|
||||
:border-color :red}
|
||||
:icon :i/options
|
||||
:accessibility-label :options-button}]}]))
|
||||
|
||||
(defn chat-render
|
||||
[]
|
||||
(let [;;NOTE: we want to react only on these fields, do not use full chat map here
|
||||
{:keys [chat-id show-input?] :as chat} (rf/sub [:chats/current-chat-chat-view])]
|
||||
[rn/keyboard-avoiding-view {:style {:flex 1}}
|
||||
(let [{:keys [chat-id
|
||||
contact-request-state
|
||||
show-input?]
|
||||
:as chat}
|
||||
(rf/sub [:chats/current-chat-chat-view])]
|
||||
[rn/keyboard-avoiding-view {:style {:position :relative :flex 1}}
|
||||
[rn/view
|
||||
{:style {:position :absolute
|
||||
:top 56
|
||||
:z-index 2
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-100)
|
||||
:width "100%"}}
|
||||
|
||||
[pin.banner/banner chat-id]
|
||||
[not-implemented/not-implemented
|
||||
[pin-limit-popover/pin-limit-popover chat-id]]]
|
||||
[page-nav]
|
||||
[not-implemented/not-implemented
|
||||
[pin-limit-popover/pin-limit-popover chat-id]]
|
||||
[not-implemented/not-implemented
|
||||
[pin.banner/banner chat-id]]
|
||||
[messages.list/messages-list {:chat chat :show-input? show-input?}]
|
||||
(when show-input?
|
||||
[composer/composer chat-id])]))
|
||||
(cond (and (not show-input?)
|
||||
contact-request-state)
|
||||
[contact-requests.bottom-drawer/view chat-id contact-request-state]
|
||||
|
||||
show-input?
|
||||
[composer/composer chat-id])]))
|
||||
|
||||
(defn chat
|
||||
[]
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
(ns status-im2.contexts.chat.photo-selector.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]))
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn gradient-container
|
||||
[safe-area]
|
||||
{:width "100%"
|
||||
:height (+ (:bottom safe-area) 65)
|
||||
:position :absolute
|
||||
:bottom (if platform/ios? 0 65)})
|
||||
:bottom 0})
|
||||
|
||||
(defn buttons-container
|
||||
[safe-area]
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.chat.photo-selector.style :as style]
|
||||
[status-im.utils.core :as utils]
|
||||
[quo.react]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[re-frame.core :as re-frame]
|
||||
status-im2.common.bottom-sheet.view))
|
||||
|
||||
(def selected (reagent/atom []))
|
||||
|
||||
@@ -20,7 +21,7 @@
|
||||
(doseq [item @selected]
|
||||
(rf/dispatch [:chat.ui/camera-roll-pick item]))
|
||||
(reset! selected [])
|
||||
(rf/dispatch [:bottom-sheet/hide]))
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet]))
|
||||
|
||||
(defn bottom-gradient
|
||||
[chat-id selected-images]
|
||||
@@ -36,7 +37,9 @@
|
||||
[quo/button
|
||||
{:style {:align-self :stretch
|
||||
:margin-horizontal 20}
|
||||
:on-press #(on-press-confirm-selection chat-id)
|
||||
:on-press (fn []
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
(on-press-confirm-selection chat-id))
|
||||
:accessibility-label :confirm-selection}
|
||||
(i18n/label :t/confirm-selection)]])))])
|
||||
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
(:require [i18n.i18n :as i18n]
|
||||
[quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[re-frame.core :as re-frame]
|
||||
status-im2.common.bottom-sheet.view))
|
||||
|
||||
(defn hide-sheet-and-dispatch
|
||||
[event]
|
||||
(rf/dispatch [:bottom-sheet/hide])
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
(rf/dispatch event))
|
||||
|
||||
(def not-joined-options
|
||||
@@ -87,7 +89,7 @@
|
||||
:align-items :center
|
||||
:justify-content :space-evenly}}
|
||||
[quo/button
|
||||
{:on-press #(rf/dispatch [:bottom-sheet/hide])
|
||||
{:on-press #(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
:type :grey
|
||||
:style {:flex 1
|
||||
:margin-right 12}}
|
||||
@@ -98,10 +100,8 @@
|
||||
(i18n/label :t/leave-community)]]])
|
||||
|
||||
(defn actions
|
||||
[]
|
||||
(let [community-mock (rf/sub [:get-screen-params :community-overview]) ;;TODO stop using mock data and
|
||||
;;only pass community id
|
||||
community (rf/sub [:communities/community (:id community-mock)])]
|
||||
[id]
|
||||
(let [community (rf/sub [:communities/community id])]
|
||||
[quo/action-drawer
|
||||
[(get (if (:joined community)
|
||||
(joined-options (:id community))
|
||||
|
||||
@@ -16,9 +16,12 @@
|
||||
(rf/dispatch [:communities/load-category-states id])
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:navigate-to-nav2 :community {:community-id id}]))
|
||||
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn []
|
||||
[home.actions/actions community-item])}])}
|
||||
:on-long-press #(rf/dispatch
|
||||
[:bottom-sheet/show-sheet
|
||||
{:content (fn []
|
||||
[home.actions/actions id])
|
||||
:selected-item (fn []
|
||||
[quo/communities-membership-list-item {} community-item])}])}
|
||||
community-item]))
|
||||
|
||||
(defn get-item-layout-js
|
||||
@@ -56,9 +59,8 @@
|
||||
(let [ids-by-user-involvement (rf/sub [:communities/community-ids-by-user-involvement])
|
||||
tab @selected-tab]
|
||||
[rn/view
|
||||
{:style {:padding-left 20
|
||||
:padding-right 8
|
||||
:padding-vertical 12}}
|
||||
{:style {:padding-horizontal 20
|
||||
:padding-vertical 12}}
|
||||
(case tab
|
||||
:joined
|
||||
[communities-list (:joined ids-by-user-involvement)]
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
[status-im.react-native.resources :as resources]
|
||||
[status-im2.contexts.communities.requests.actions.style :as style]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.requests :as requests]))
|
||||
[utils.requests :as requests]
|
||||
[re-frame.core :as re-frame]
|
||||
status-im2.common.bottom-sheet.view))
|
||||
|
||||
;; TODO: update with real data
|
||||
(def community-rules
|
||||
@@ -116,7 +118,7 @@
|
||||
{:style style/request-button}
|
||||
[quo/button
|
||||
{:accessibility-label :cancel
|
||||
:on-press #(rf/dispatch [:bottom-sheet/hide])
|
||||
:on-press #(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
:type :grey
|
||||
:style style/cancel-button} (i18n/label :t/cancel)]
|
||||
[quo/button
|
||||
@@ -125,12 +127,12 @@
|
||||
(when-not joined
|
||||
(when can-join?
|
||||
(rf/dispatch [::communities/join id]))
|
||||
(rf/dispatch [:bottom-sheet/hide])
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
|
||||
(when
|
||||
(and can-request-access?
|
||||
(not (pos? requested-to-join-at))
|
||||
(requests/can-request-access-again? requested-to-join-at))
|
||||
(rf/dispatch [::communities/request-to-join id])
|
||||
(rf/dispatch [:bottom-sheet/hide]))))
|
||||
(re-frame/dispatch-sync [:dismiss-bottom-sheet]))))
|
||||
:disabled (not @agreed-to-rules?)
|
||||
:style {:flex 1}} (request-to-join-text is-open?)]]])))
|
||||
|
||||
@@ -12,16 +12,17 @@
|
||||
{:label "number of messages"
|
||||
:key :pins-count
|
||||
:type :text}
|
||||
{:label "show pin icon?"
|
||||
:key :show-pin?
|
||||
{:label "hide pin icon?"
|
||||
:key :hide-pin?
|
||||
:type :boolean}
|
||||
])
|
||||
|
||||
(defn cool-preview
|
||||
[]
|
||||
(let [state (reagent/atom {:show-pin? true
|
||||
:pins-count 2
|
||||
:latest-pin-text "Be respectful of fellow community member..."})]
|
||||
(let [state (reagent/atom
|
||||
{:hide-pin? false
|
||||
:pins-count 2
|
||||
:latest-pin-text "Be respectful of fellow community members, even if they"})]
|
||||
(fn []
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view {:padding-bottom 150}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
([text id opts]
|
||||
(let [toast-opts (rf/sub [:toasts/toast id])
|
||||
dismiss! #(rf/dispatch [:toasts/close id])
|
||||
toast! #(rf/dispatch [:toasts/upsert id opts])
|
||||
toast! #(rf/dispatch [:toasts/upsert (assoc opts :id id)])
|
||||
dismissed? (not toast-opts)]
|
||||
[rn/view {:style {:margin-bottom 10}}
|
||||
[button/button
|
||||
@@ -34,7 +34,7 @@
|
||||
:duration 4000
|
||||
:undo-duration 4
|
||||
:undo-on-press #(do
|
||||
(rf/dispatch [:toasts/create
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:icon :placeholder
|
||||
:icon-color "green"
|
||||
:text "Undo pressed"}])
|
||||
@@ -53,7 +53,7 @@
|
||||
:undo-on-press
|
||||
#(do
|
||||
(rf/dispatch
|
||||
[:toasts/create
|
||||
[:toasts/upsert
|
||||
{:icon :placeholder :icon-color "green" :text "Undo pressed"}])
|
||||
(rf/dispatch [:toasts/close "Toast: with undo action"]))}])
|
||||
|
||||
@@ -78,8 +78,8 @@
|
||||
:on-press
|
||||
#(rf/dispatch
|
||||
[:toasts/upsert
|
||||
"Toast: 30s duration"
|
||||
{:icon :placeholder
|
||||
{:id "Toast: 30s duration"
|
||||
:icon :placeholder
|
||||
:icon-color "red"
|
||||
:text (str "This is an updated example toast" " - " (swap! suffix inc))
|
||||
:duration 3000}])}
|
||||
|
||||
@@ -12,11 +12,15 @@
|
||||
:options [{:key 32
|
||||
:value "32"}
|
||||
{:key 24
|
||||
:value "24"}]}])
|
||||
:value "24"}]}
|
||||
{:label "Scrollable:"
|
||||
:key :scrollable?
|
||||
:type :boolean}])
|
||||
|
||||
(defn cool-preview
|
||||
[]
|
||||
(let [state (reagent/atom {:size 32})]
|
||||
(let [state (reagent/atom {:size 32
|
||||
:scrollable? false})]
|
||||
(fn []
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view {:padding-bottom 150}
|
||||
@@ -33,7 +37,11 @@
|
||||
{:id 2 :label "Tab 2"}
|
||||
{:id 3 :label "Tab 3"}
|
||||
{:id 4 :label "Tab 4"}]
|
||||
:on-change #(println "Active tab" %)})]]]])))
|
||||
:on-change #(println "Active tab" %)}
|
||||
(when (:scrollable? @state)
|
||||
{:scroll-on-press? true
|
||||
:fade-end-percentage 0.4
|
||||
:fade-end? true}))]]]])))
|
||||
|
||||
(defn preview-tabs
|
||||
[]
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
(ns status-im2.contexts.quo-preview.tags.tag
|
||||
(:require [quo.react-native :as rn]
|
||||
[quo.previews.preview :as preview]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.tags.tag :as tag]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(def descriptor
|
||||
[{:label "Size:"
|
||||
:key :size
|
||||
:type :select
|
||||
:options [{:key 32
|
||||
:value "32"}
|
||||
{:key 24
|
||||
:value "24"}]}
|
||||
{:label "Type:"
|
||||
:key :type
|
||||
:type :select
|
||||
:options [{:key :emoji
|
||||
:value "Emoji"}
|
||||
{:key :icon
|
||||
:value "Icons"}
|
||||
{:key :label
|
||||
:value "Label"}]}
|
||||
{:label "Labelled:"
|
||||
:key :labelled?
|
||||
:type :boolean}
|
||||
{:label "Disabled:"
|
||||
:key :disabled?
|
||||
:type :boolean}
|
||||
{:label "Blurred background:"
|
||||
:key :blurred?
|
||||
:type :boolean}])
|
||||
|
||||
(defn cool-preview
|
||||
[]
|
||||
(let [state (reagent/atom {:size 32
|
||||
:labelled? true
|
||||
:type :emoji})]
|
||||
(fn []
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view
|
||||
{:style {:padding-bottom 150
|
||||
:padding-top 60}}
|
||||
[rn/view {:flex 1}
|
||||
[preview/customizer state descriptor]]
|
||||
[rn/view
|
||||
{:style {:flex 1
|
||||
:justify-content :center
|
||||
:top 60
|
||||
:padding-horizontal 16}}
|
||||
(when (:blurred? @state)
|
||||
[rn/view
|
||||
{:style {:flex 1
|
||||
:height 100}}
|
||||
[react/image
|
||||
{:source (resources/get-image :community-cover)
|
||||
:style {:flex 1
|
||||
:width "100%"
|
||||
:border-radius 16}}]
|
||||
[react/blur-view
|
||||
{:flex 1
|
||||
:style {:border-radius 16
|
||||
:height 100
|
||||
:position :absolute
|
||||
:left 0
|
||||
:right 0}
|
||||
:blur-amount 20
|
||||
:overlay-color (colors/theme-colors
|
||||
colors/white-opa-70
|
||||
colors/neutral-80-opa-80)}]])
|
||||
[rn/view
|
||||
{:style {:position :absolute
|
||||
:align-self :center}}
|
||||
[tag/tag
|
||||
(merge @state
|
||||
{:id 1
|
||||
:label "Tag"
|
||||
:labelled? (if (= (:type @state) :label)
|
||||
true
|
||||
(:labelled? @state))
|
||||
:resource (if (= :emoji (:type @state))
|
||||
(resources/get-image :music)
|
||||
:main-icons2/placeholder)})]]]]])))
|
||||
(defn preview-tag
|
||||
[]
|
||||
[rn/view
|
||||
{:flex 1
|
||||
:background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-90)}
|
||||
[rn/flat-list
|
||||
{:flex 1
|
||||
:keyboardShouldPersistTaps :always
|
||||
:header [cool-preview]
|
||||
:key-fn str}]])
|
||||
@@ -24,70 +24,85 @@
|
||||
:value "Icons"}
|
||||
{:key :label
|
||||
:value "Label"}]}
|
||||
{:label "Scrollable:"
|
||||
:key :scrollable?
|
||||
:type :boolean}
|
||||
{:label "Fade Out:"
|
||||
:key :fade-end-percentage
|
||||
:type :select
|
||||
:options [{:key 1
|
||||
:value "1%"}
|
||||
{:key 0.4
|
||||
:value "0.4%"}]}
|
||||
{:label "Labelled:"
|
||||
:key :labelled
|
||||
:key :labelled?
|
||||
:type :boolean}
|
||||
{:label "Disabled:"
|
||||
:key :disabled
|
||||
:key :disabled?
|
||||
:type :boolean}
|
||||
{:label "Blurred background:"
|
||||
:key :blurred
|
||||
:key :blurred?
|
||||
:type :boolean}])
|
||||
|
||||
(defn cool-preview
|
||||
[]
|
||||
(let [state (reagent/atom {:size 32
|
||||
:labelled true
|
||||
:type :emoji})]
|
||||
(let [state (reagent/atom {:size 32
|
||||
:labelled? true
|
||||
:type :emoji
|
||||
:fade-end-percentage 0.4
|
||||
:scrollable? false})]
|
||||
(fn []
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view
|
||||
{:padding-bottom 150
|
||||
:padding-top 60}
|
||||
[rn/view {:flex 1}
|
||||
{:style {:padding-bottom 150
|
||||
:padding-top 60}}
|
||||
[rn/view {:style {:flex 1}}
|
||||
[preview/customizer state descriptor]]
|
||||
[rn/view
|
||||
{:flex 1
|
||||
:justify-content :center
|
||||
:top 60}
|
||||
(when (:blurred @state)
|
||||
[rn/view {:flex 1}
|
||||
[react/view
|
||||
{:flex-direction :row
|
||||
:height 100}
|
||||
[react/image
|
||||
{:source (resources/get-image :community-cover)
|
||||
:style {:flex 1
|
||||
:height 100
|
||||
:border-radius 16}}]]
|
||||
[react/view
|
||||
{:flex-direction :row
|
||||
:height 100
|
||||
:position :absolute
|
||||
:left 0
|
||||
:right 0}
|
||||
[react/blur-view
|
||||
{:flex 1
|
||||
:style {:border-radius 16
|
||||
:height 100}
|
||||
:blur-amount 40
|
||||
:overlay-color (colors/theme-colors
|
||||
colors/white-opa-70
|
||||
colors/neutral-80-opa-80)}]]])
|
||||
[rn/scroll-view
|
||||
{:justify-content :center
|
||||
:align-items :center
|
||||
:position :absolute
|
||||
:padding-horizontal 10}
|
||||
{:style {:flex 1
|
||||
:justify-content :center
|
||||
:top 60
|
||||
:padding-horizontal 16}}
|
||||
(when (:blurred? @state)
|
||||
[rn/view
|
||||
{:align-items :center
|
||||
:height 100
|
||||
:border-radius 16}
|
||||
[react/image
|
||||
{:source (resources/get-image :community-cover)
|
||||
:style {:flex 1
|
||||
:width "100%"
|
||||
:border-radius 16}}]
|
||||
[react/blur-view
|
||||
{:flex 1
|
||||
:style {:border-radius 16
|
||||
:height 100
|
||||
:position :absolute
|
||||
:left 0
|
||||
:right 0}
|
||||
:blur-amount 20
|
||||
:overlay-color (colors/theme-colors
|
||||
colors/white-opa-70
|
||||
colors/neutral-80-opa-80)}]])
|
||||
[rn/view
|
||||
{:style {:position :absolute
|
||||
:align-self :center}}
|
||||
[tags/tags
|
||||
(merge
|
||||
@state
|
||||
{:default-active 1
|
||||
:data [{:id 1 :tag-label "Music" :resource (resources/get-image :music)}
|
||||
{:id 2 :tag-label "Lifestyle" :resource (resources/get-image :lifestyle)}
|
||||
{:id 3
|
||||
:tag-label "Podcasts"
|
||||
:resource (resources/get-image :podcasts)}]})]]]]])))
|
||||
:component :tags
|
||||
:labelled? (if (= :label type) true (:labelled? @state))
|
||||
:resource (when (= type :icon)
|
||||
:main-icons2/placeholder)
|
||||
:data [{:id 1 :label "Music" :resource (resources/get-image :music)}
|
||||
{:id 2 :label "Lifestyle" :resource (resources/get-image :lifestyle)}
|
||||
{:id 2 :label "Podcasts" :resource (resources/get-image :podcasts)}
|
||||
{:id 2 :label "Music" :resource (resources/get-image :music)}
|
||||
{:id 3 :label "Lifestyle" :resource (resources/get-image :lifestyle)}]}
|
||||
(when (:scrollable? @state)
|
||||
{:scroll-on-press? true
|
||||
:fade-end? true}))]]]]])))
|
||||
(defn preview-tags
|
||||
[]
|
||||
[rn/view
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
:chat/spam-messages-frequency 0
|
||||
:chats-home-list #{}
|
||||
:home-items-show-number 20
|
||||
:toasts {:ordered '() :toasts {}}
|
||||
:tooltips {}
|
||||
:dimensions/window (rn/get-window)
|
||||
:registry {}
|
||||
|
||||
@@ -171,11 +171,10 @@
|
||||
:<- [:multiaccount/public-key]
|
||||
:<- [:communities/current-community]
|
||||
:<- [:contacts/blocked-set]
|
||||
:<- [:contacts/contacts]
|
||||
:<- [:contacts/contacts-raw]
|
||||
:<- [:chat/inputs]
|
||||
:<- [:mutual-contact-requests/enabled?]
|
||||
(fn [[{:keys [group-chat chat-id] :as current-chat} my-public-key community blocked-users-set contacts
|
||||
inputs mutual-contact-requests-enabled?]]
|
||||
inputs]]
|
||||
(when current-chat
|
||||
(cond-> current-chat
|
||||
(chat.models/public-chat? current-chat)
|
||||
@@ -191,23 +190,35 @@
|
||||
(assoc :show-input? true)
|
||||
|
||||
(not group-chat)
|
||||
(assoc :show-input?
|
||||
(and
|
||||
(or
|
||||
(not mutual-contact-requests-enabled?)
|
||||
(get-in inputs [chat-id :metadata :sending-contact-request])
|
||||
(and mutual-contact-requests-enabled?
|
||||
(= constants/contact-request-state-mutual
|
||||
(get-in contacts [chat-id :contact-request-state]))))
|
||||
(not (contains? blocked-users-set chat-id))))))))
|
||||
(assoc
|
||||
:contact-request-state (get-in contacts [chat-id :contact-request-state])
|
||||
:show-input?
|
||||
(and
|
||||
(or
|
||||
(get-in inputs [chat-id :metadata :sending-contact-request])
|
||||
(= constants/contact-request-state-mutual
|
||||
(get-in contacts [chat-id :contact-request-state])))
|
||||
(not (contains? blocked-users-set chat-id))))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:chats/current-chat-chat-view
|
||||
:<- [:chats/current-chat]
|
||||
(fn [current-chat]
|
||||
(select-keys current-chat
|
||||
[:chat-id :show-input? :group-chat :admins :invitation-admin :public? :chat-type :color
|
||||
:chat-name :synced-to :synced-from :community-id :emoji])))
|
||||
[:chat-id
|
||||
:show-input?
|
||||
:group-chat
|
||||
:admins
|
||||
:invitation-admin
|
||||
:public?
|
||||
:chat-type
|
||||
:color
|
||||
:contact-request-state
|
||||
:chat-name
|
||||
:synced-to
|
||||
:synced-from
|
||||
:community-id
|
||||
:emoji])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:current-chat/metadata
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
(ns status-im2.subs.chat.chats-test
|
||||
(:require [cljs.test :refer [is testing]]
|
||||
[re-frame.db :as rf-db]
|
||||
[test-helpers.unit :as h]
|
||||
[status-im2.common.constants :as constants]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def public-key "0xpk")
|
||||
(def multiaccount {:public-key public-key})
|
||||
(def chat-id "1")
|
||||
(def chat {:chat-id chat-id})
|
||||
|
||||
(def private-group-chat
|
||||
(assoc
|
||||
chat
|
||||
:members #{{:id public-key}}
|
||||
:group-chat true
|
||||
:chat-type constants/private-group-chat-type))
|
||||
|
||||
(def one-to-one-chat
|
||||
(assoc
|
||||
chat
|
||||
:chat-type
|
||||
constants/one-to-one-chat-type))
|
||||
|
||||
(h/deftest-sub :chats/current-chat
|
||||
[sub-name]
|
||||
(testing "private group chat, user is a member"
|
||||
(let [chats {chat-id private-group-chat}]
|
||||
(swap! rf-db/app-db assoc
|
||||
:multiaccount multiaccount
|
||||
:current-chat-id chat-id
|
||||
:chats chats)
|
||||
(is (true? (:show-input? (rf/sub [sub-name]))))))
|
||||
(testing "private group chat, user is not member"
|
||||
(let [chats {chat-id (dissoc private-group-chat :members)}]
|
||||
(swap! rf-db/app-db assoc
|
||||
:multiaccount multiaccount
|
||||
:current-chat-id chat-id
|
||||
:chats chats)
|
||||
(is (not (:show-input? (rf/sub [sub-name]))))))
|
||||
(testing "one to one chat, mutual contacts"
|
||||
(let [chats {chat-id one-to-one-chat}]
|
||||
(swap! rf-db/app-db assoc
|
||||
:contacts/contacts {chat-id {:contact-request-state constants/contact-request-state-mutual}}
|
||||
:multiaccount multiaccount
|
||||
:current-chat-id chat-id
|
||||
:chats chats)
|
||||
(is (:show-input? (rf/sub [sub-name])))))
|
||||
(testing "one to one chat, not a contact"
|
||||
(let [chats {chat-id one-to-one-chat}]
|
||||
(swap! rf-db/app-db assoc
|
||||
:contacts/contacts {chat-id {:contact-request-state constants/contact-request-state-sent}}
|
||||
:multiaccount multiaccount
|
||||
:current-chat-id chat-id
|
||||
:chats chats)
|
||||
(is (not (:show-input? (rf/sub [sub-name])))))))
|
||||
@@ -137,7 +137,7 @@
|
||||
:muted? (:muted community)
|
||||
:unread-messages? (pos? (:unviewed-messages-count counts))
|
||||
:unread-mentions-count (:unviewed-mentions-count counts)
|
||||
:community-icon (get-in community [:images :thumbnail :uri])})
|
||||
:community-icon (:images community)})
|
||||
|
||||
(re-frame/reg-sub
|
||||
:communities/home-item
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
[status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils]
|
||||
[status-im.utils.gfycat.core :as gfycat]
|
||||
[status-im.utils.image-server :as image-server]
|
||||
[utils.collection]))
|
||||
[utils.collection]
|
||||
[status-im.constants :as constants]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::query-current-chat-contacts
|
||||
@@ -23,12 +24,6 @@
|
||||
(fn [multiaccount]
|
||||
(get multiaccount :profile-pictures-show-to)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:mutual-contact-requests/enabled?
|
||||
:<- [:multiaccount]
|
||||
(fn [settings]
|
||||
(boolean (:mutual-contact-enabled? settings))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::profile-pictures-visibility
|
||||
:<- [:multiaccount]
|
||||
@@ -93,7 +88,7 @@
|
||||
vals)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:contacts/add-members-sections
|
||||
:contacts/grouped-by-first-letter
|
||||
:<- [:contacts/current-chat-contacts]
|
||||
:<- [:contacts/active]
|
||||
(fn [[members contacts]]
|
||||
@@ -108,6 +103,23 @@
|
||||
sort
|
||||
vals)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:contacts/sorted-and-grouped-by-first-letter
|
||||
:<- [:contacts/active]
|
||||
:<- [:selected-contacts-count]
|
||||
(fn [[contacts selected-contacts-count]]
|
||||
(->> contacts
|
||||
(filter :mutual?)
|
||||
(map #(assoc %
|
||||
:allow-new-users?
|
||||
(< selected-contacts-count
|
||||
(dec constants/max-group-chat-participants))))
|
||||
(group-by (comp (fnil string/upper-case "") first :alias))
|
||||
(sort-by (fn [[title]] title))
|
||||
(map (fn [[title data]]
|
||||
{:title title
|
||||
:data data})))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:contacts/sorted-contacts
|
||||
:<- [:contacts/active]
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
(ns status-im2.subs.contact-test
|
||||
(:require [cljs.test :refer [is testing]]
|
||||
[re-frame.db :as rf-db]
|
||||
[test-helpers.unit :as h]
|
||||
status-im2.subs.contact
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def ^:private contacts-sample-data
|
||||
{:selected-contacts-count 1
|
||||
:contacts/contacts {"0xtest" {:last-updated 1672582629695
|
||||
:mutual? true
|
||||
:contactRequestClock 0
|
||||
:images {}
|
||||
:added true
|
||||
:name "slim.shady"
|
||||
:Removed false
|
||||
:trustStatus 0
|
||||
:alias "Real Slim Shady"
|
||||
:bio ""
|
||||
:IsSyncing false
|
||||
:display-name ""
|
||||
:ens-verified true
|
||||
:socialLinks nil
|
||||
:blocked false
|
||||
:verificationStatus 0
|
||||
:lastUpdatedLocally 1672582563204
|
||||
:public-key "0xtest"
|
||||
:has-added-us true
|
||||
:contact-request-state 1}
|
||||
"0xtest2" {:last-updated 1672582629695
|
||||
:mutual? true
|
||||
:contactRequestClock 0
|
||||
:images {}
|
||||
:added true
|
||||
:name "slim.shady"
|
||||
:Removed false
|
||||
:trustStatus 0
|
||||
:alias "Fake Slim Shady"
|
||||
:bio ""
|
||||
:IsSyncing false
|
||||
:display-name ""
|
||||
:ens-verified true
|
||||
:socialLinks nil
|
||||
:blocked false
|
||||
:verificationStatus 0
|
||||
:lastUpdatedLocally 1672582563204
|
||||
:public-key "0xtest"
|
||||
:has-added-us true
|
||||
:contact-request-state 1}
|
||||
"0xtest3" {:last-updated 1672582629695
|
||||
:mutual? true
|
||||
:contactRequestClock 0
|
||||
:images {}
|
||||
:added true
|
||||
:name "slim.shady"
|
||||
:Removed false
|
||||
:trustStatus 0
|
||||
:alias "Instant noodles"
|
||||
:bio ""
|
||||
:IsSyncing false
|
||||
:display-name ""
|
||||
:ens-verified true
|
||||
:socialLinks nil
|
||||
:blocked false
|
||||
:verificationStatus 0
|
||||
:lastUpdatedLocally 1672582563204
|
||||
:public-key "0xtest"
|
||||
:has-added-us true
|
||||
:contact-request-state 1}}})
|
||||
|
||||
(def ^:private expected-sorted-contacts
|
||||
'({:title "F"
|
||||
:data ({:active? true
|
||||
:last-updated 1672582629695
|
||||
:mutual? true
|
||||
:blocked? false
|
||||
:contactRequestClock 0
|
||||
:images {}
|
||||
:added true
|
||||
:name "slim.shady"
|
||||
:added? true
|
||||
:Removed false
|
||||
:trustStatus 0
|
||||
:alias "Fake Slim Shady"
|
||||
:bio ""
|
||||
:IsSyncing false
|
||||
:display-name ""
|
||||
:ens-verified true
|
||||
:socialLinks nil
|
||||
:blocked false
|
||||
:allow-new-users? true
|
||||
:verificationStatus 0
|
||||
:lastUpdatedLocally 1672582563204
|
||||
:public-key "0xtest"
|
||||
:names {:nickname nil
|
||||
:display-name ""
|
||||
:three-words-name "Fake Slim Shady"
|
||||
:ens-name "@slim.shady"}
|
||||
:has-added-us true
|
||||
:contact-request-state 1})}
|
||||
{:title "I"
|
||||
:data ({:active? true
|
||||
:last-updated 1672582629695
|
||||
:mutual? true
|
||||
:blocked? false
|
||||
:contactRequestClock 0
|
||||
:images {}
|
||||
:added true
|
||||
:name "slim.shady"
|
||||
:added? true
|
||||
:Removed false
|
||||
:trustStatus 0
|
||||
:alias "Instant noodles"
|
||||
:bio ""
|
||||
:IsSyncing false
|
||||
:display-name ""
|
||||
:ens-verified true
|
||||
:socialLinks nil
|
||||
:blocked false
|
||||
:allow-new-users? true
|
||||
:verificationStatus 0
|
||||
:lastUpdatedLocally 1672582563204
|
||||
:public-key "0xtest"
|
||||
:names {:nickname nil
|
||||
:display-name ""
|
||||
:three-words-name "Instant noodles"
|
||||
:ens-name "@slim.shady"}
|
||||
:has-added-us true
|
||||
:contact-request-state 1})}
|
||||
{:title "R"
|
||||
:data ({:active? true
|
||||
:last-updated 1672582629695
|
||||
:mutual? true
|
||||
:blocked? false
|
||||
:contactRequestClock 0
|
||||
:images {}
|
||||
:added true
|
||||
:name "slim.shady"
|
||||
:added? true
|
||||
:Removed false
|
||||
:trustStatus 0
|
||||
:alias "Real Slim Shady"
|
||||
:bio ""
|
||||
:IsSyncing false
|
||||
:display-name ""
|
||||
:ens-verified true
|
||||
:socialLinks nil
|
||||
:blocked false
|
||||
:allow-new-users? true
|
||||
:verificationStatus 0
|
||||
:lastUpdatedLocally 1672582563204
|
||||
:public-key "0xtest"
|
||||
:names {:nickname nil
|
||||
:display-name ""
|
||||
:three-words-name "Real Slim Shady"
|
||||
:ens-name "@slim.shady"}
|
||||
:has-added-us true
|
||||
:contact-request-state 1})}))
|
||||
|
||||
(h/deftest-sub :contacts/sorted-and-grouped-by-first-letter
|
||||
[sub-name]
|
||||
(testing "Returning empty sequence when no contacts"
|
||||
(swap! rf-db/app-db merge (assoc contacts-sample-data :contacts/contacts {}))
|
||||
(is (empty? (rf/sub [sub-name]))))
|
||||
(testing "Returning empty sequence when no mutual contacts"
|
||||
(let [remove-contact-as-mutual #(-> %
|
||||
(assoc-in ["0xtest" :mutual?] false)
|
||||
(assoc-in ["0xtest2" :mutual?] false)
|
||||
(assoc-in ["0xtest3" :mutual?] false))]
|
||||
(swap! rf-db/app-db merge
|
||||
(update contacts-sample-data :contacts/contacts remove-contact-as-mutual))
|
||||
(is (empty? (rf/sub [sub-name])))))
|
||||
(testing "Returning sorted contacts"
|
||||
(swap! rf-db/app-db merge contacts-sample-data)
|
||||
(let [contact-list-without-identicons (map (fn [contact-group]
|
||||
(update contact-group
|
||||
:data
|
||||
#(map (fn [contact]
|
||||
(dissoc contact :identicon))
|
||||
%)))
|
||||
(rf/sub [sub-name]))]
|
||||
|
||||
(is (= expected-sorted-contacts contact-list-without-identicons)))))
|
||||
@@ -198,6 +198,22 @@
|
||||
(fn [seed]
|
||||
(or seed {:step :intro})))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:bottom-sheet/config
|
||||
(fn [db]
|
||||
(let [content-height (get-in db [:bottom-sheet/config :content-height])
|
||||
show-bottom-sheet? (get-in db [:bottom-sheet/config :show-bottom-sheet?])
|
||||
keyboard-was-shown? (get-in db [:bottom-sheet/config :keyboard-was-shown?])
|
||||
expanded? (get-in db [:bottom-sheet/config :expanded?])
|
||||
gesture-running? (get-in db [:bottom-sheet/config :gesture-running?])
|
||||
animation-delay (get-in db [:bottom-sheet/config :animation-delay])]
|
||||
{:content-height (or content-height nil)
|
||||
:show-bottom-sheet? (or show-bottom-sheet? nil)
|
||||
:keyboard-was-shown? (or keyboard-was-shown? false)
|
||||
:expanded? (or expanded? false)
|
||||
:gesture-running? (or gesture-running? false)
|
||||
:animation-delay (or animation-delay 450)})))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:bottom-sheet
|
||||
:<- [:bottom-sheet/show?]
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
(reg-root-key-sub :bottom-sheet/show? :bottom-sheet/show?)
|
||||
(reg-root-key-sub :bottom-sheet/view :bottom-sheet/view)
|
||||
(reg-root-key-sub :bottom-sheet/options :bottom-sheet/options)
|
||||
(reg-root-key-sub :bottom-sheet/config :bottom-sheet/config)
|
||||
|
||||
;;general
|
||||
(reg-root-key-sub :sync-state :sync-state)
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
{:content {:community-channel {:emoji (:emoji channel)
|
||||
:channel-name (str "# " (:name channel))}}
|
||||
:on-press (fn []
|
||||
(re-frame/dispatch [:navigate-to :community {:community-id community-id}])
|
||||
(re-frame/dispatch [:navigate-to-nav2 :community {:community-id community-id}])
|
||||
(js/setTimeout
|
||||
#(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 channel-id true])
|
||||
100))}))
|
||||
|
||||
@@ -6,3 +6,9 @@
|
||||
:<- [:toasts]
|
||||
(fn [toasts [_ toast-id]]
|
||||
(get-in toasts [:toasts toast-id])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:toasts/toast-cursor
|
||||
:<- [:toasts]
|
||||
(fn [toasts [_ toast-id & cursor]]
|
||||
(get-in toasts (into [:toasts toast-id] cursor))))
|
||||
|
||||
@@ -84,10 +84,18 @@ class BaseTestReport:
|
||||
tests = self.get_all_tests()
|
||||
failed = list()
|
||||
for test in tests:
|
||||
if not self.is_test_successful(test):
|
||||
if not self.is_test_successful(test) and not self.is_test_xfailed(test):
|
||||
failed.append(test)
|
||||
return failed
|
||||
|
||||
def get_xfailed_tests(self):
|
||||
tests = self.get_all_tests()
|
||||
xfailed = list()
|
||||
for test in tests:
|
||||
if self.is_test_xfailed(test) and not self.is_test_successful(test):
|
||||
xfailed.append(test)
|
||||
return xfailed
|
||||
|
||||
def get_passed_tests(self):
|
||||
tests = self.get_all_tests()
|
||||
passed = list()
|
||||
@@ -126,6 +134,11 @@ class BaseTestReport:
|
||||
# Test passed if last testrun has passed
|
||||
return test.testruns[-1].error is None
|
||||
|
||||
@staticmethod
|
||||
def is_test_xfailed(test):
|
||||
# Test failed if xfail is defined
|
||||
return test.testruns[-1].xfail != ""
|
||||
|
||||
@staticmethod
|
||||
def separate_xfail_error(error):
|
||||
issue_id_list = re.findall(r'#\d+', error)
|
||||
|
||||
@@ -21,6 +21,7 @@ class GithubHtmlReport(BaseTestReport):
|
||||
tests = self.get_all_tests()
|
||||
passed_tests = self.get_passed_tests()
|
||||
failed_tests = self.get_failed_tests()
|
||||
xfailed_tests = self.get_xfailed_tests()
|
||||
not_executed_tests = TestrailReport().get_not_executed_tests(run_id)
|
||||
|
||||
if len(tests) > 0:
|
||||
@@ -32,9 +33,7 @@ class GithubHtmlReport(BaseTestReport):
|
||||
if not_executed_tests:
|
||||
summary_html += "Not executed tests: %d\n" % len(not_executed_tests)
|
||||
summary_html += "```\n"
|
||||
not_executed_tests_html = str()
|
||||
failed_tests_html = str()
|
||||
passed_tests_html = str()
|
||||
failed_tests_html, xfailed_tests_html, passed_tests_html, not_executed_tests_html = str(), str(), str(), str()
|
||||
if not_executed_tests:
|
||||
not_executed_tests_html = self.build_tests_table_html(not_executed_tests, run_id,
|
||||
not_executed_tests=True)
|
||||
@@ -44,19 +43,26 @@ class GithubHtmlReport(BaseTestReport):
|
||||
if failed_tests:
|
||||
failed_tests_html = self.build_tests_table_html(failed_tests, run_id, failed_tests=True)
|
||||
summary_html += "```\n"
|
||||
summary_html += 'IDs of failed tests: %s \n' % self.list_of_failed_testrail_ids(failed_tests)
|
||||
summary_html += 'IDs of failed tests(should be reviewed): %s \n' % self.list_of_failed_testrail_ids(failed_tests)
|
||||
summary_html += "```\n"
|
||||
if xfailed_tests:
|
||||
xfailed_tests_html = self.build_tests_table_html(xfailed_tests, run_id, failed_tests=False, xfailed_tests=True)
|
||||
summary_html += "```\n"
|
||||
summary_html += 'IDs of failed tests(existing issues): %s \n' % self.list_of_failed_testrail_ids(xfailed_tests)
|
||||
summary_html += "```\n"
|
||||
if passed_tests:
|
||||
passed_tests_html = self.build_tests_table_html(passed_tests, run_id, failed_tests=False)
|
||||
return title_html + summary_html + not_executed_tests_html + failed_tests_html + passed_tests_html
|
||||
return title_html + summary_html + not_executed_tests_html + failed_tests_html + passed_tests_html + xfailed_tests_html
|
||||
else:
|
||||
return None
|
||||
|
||||
def build_tests_table_html(self, tests, run_id, failed_tests=False, not_executed_tests=False):
|
||||
def build_tests_table_html(self, tests, run_id, failed_tests=False, not_executed_tests=False, xfailed_tests=False):
|
||||
if failed_tests:
|
||||
tests_type = "Failed tests"
|
||||
tests_type = "Failed tests (for review)"
|
||||
elif not_executed_tests:
|
||||
tests_type = "Not executed tests"
|
||||
elif xfailed_tests:
|
||||
tests_type = "Failed tests (known)"
|
||||
else:
|
||||
tests_type = "Passed tests"
|
||||
html = "<h3>%s (%d)</h3>" % (tests_type, len(tests))
|
||||
|
||||
@@ -28,7 +28,8 @@ class TestrailReport(BaseTestReport):
|
||||
|
||||
self.outcomes = {
|
||||
'passed': 1,
|
||||
'undefined_fail': 10}
|
||||
'undefined_fail': 10,
|
||||
'fail': 5}
|
||||
|
||||
self.headers = dict()
|
||||
self.headers['Authorization'] = 'Basic %s' % str(
|
||||
@@ -181,6 +182,7 @@ class TestrailReport(BaseTestReport):
|
||||
test_steps = "# Steps: \n"
|
||||
devices = str()
|
||||
last_testrun = test.testruns[-1]
|
||||
status = self.outcomes['passed']
|
||||
for step in last_testrun.steps:
|
||||
test_steps += step + "\n"
|
||||
for i, device in enumerate(last_testrun.jobs):
|
||||
@@ -192,7 +194,12 @@ class TestrailReport(BaseTestReport):
|
||||
comment = str()
|
||||
if test.group_name:
|
||||
comment += "# Class: %s \n" % test.group_name
|
||||
if last_testrun.error:
|
||||
if last_testrun.error and not last_testrun.xfail:
|
||||
status = self.outcomes['fail']
|
||||
error = last_testrun.error
|
||||
comment += '%s' % ('# Error: \n %s \n' % emoji.demojize(error)) + devices + test_steps
|
||||
elif last_testrun.error and last_testrun.xfail:
|
||||
status = self.outcomes['undefined_fail']
|
||||
full_error = last_testrun.error
|
||||
(code_error, no_code_error_str, issue_id) = self.separate_xfail_error(full_error)
|
||||
if issue_id:
|
||||
@@ -206,7 +213,7 @@ class TestrailReport(BaseTestReport):
|
||||
comment += devices + test_steps
|
||||
data.append(
|
||||
{'case_id': test.testrail_case_id,
|
||||
'status_id': self.outcomes['undefined_fail'] if last_testrun.error else self.outcomes['passed'],
|
||||
'status_id': status,
|
||||
'comment': comment})
|
||||
|
||||
results = self.post('add_results_for_cases/%s' % self.run_id, data={"results": data})
|
||||
@@ -239,58 +246,77 @@ class TestrailReport(BaseTestReport):
|
||||
|
||||
self.change_test_run_description()
|
||||
|
||||
def make_single_group_report(self, tests, xfailed=False):
|
||||
single_devices_block, group_blocks, case_info, test_ids = str(), dict(), str(), []
|
||||
for test in tests:
|
||||
if test.group_name:
|
||||
group_blocks[test.group_name] = "\n-------\n## Class: %s:\n" % test.group_name
|
||||
for test in tests:
|
||||
last_testrun = test.testruns[-1]
|
||||
test_rail_link = self.get_test_result_link(self.run_id, test.testrail_case_id)
|
||||
test_ids.append(test.testrail_case_id)
|
||||
case_title = '\n'
|
||||
case_title += '-------\n'
|
||||
case_title += "### ID %s: [%s](%s) \n" % (test.testrail_case_id, test.name, test_rail_link)
|
||||
if xfailed:
|
||||
full_error = last_testrun.error[-255:]
|
||||
(code_error, no_code_error_str, issue_id) = self.separate_xfail_error(full_error)
|
||||
if issue_id:
|
||||
test_rail_xfail = self.make_error_with_gh_issue_link(no_code_error_str, issue_id)
|
||||
error = "```%s```\n **%s** \n" % (code_error, test_rail_xfail)
|
||||
else:
|
||||
error = "```%s```\n **%s** \n" % (code_error, no_code_error_str)
|
||||
else:
|
||||
error = last_testrun.error[-255:]
|
||||
for job_id, f in last_testrun.jobs.items():
|
||||
if last_testrun.first_commands:
|
||||
job_url = self.get_sauce_job_url(job_id=job_id,
|
||||
first_command=last_testrun.first_commands[job_id])
|
||||
else:
|
||||
job_url = self.get_sauce_job_url(job_id=job_id)
|
||||
case_info = "Logs for device %d: [steps](%s), [failure screenshot](%s)" \
|
||||
% (f, job_url, self.get_sauce_final_screenshot_url(job_id))
|
||||
|
||||
if test.group_name:
|
||||
group_blocks[test.group_name] += case_title + error + case_info
|
||||
else:
|
||||
single_devices_block += case_title + error + case_info
|
||||
description = single_devices_block + ''.join([i for i in group_blocks.values()])
|
||||
return description, test_ids
|
||||
|
||||
def change_test_run_description(self):
|
||||
tests = self.get_all_tests()
|
||||
passed_tests = self.get_passed_tests()
|
||||
failed_tests = self.get_failed_tests()
|
||||
xfailed_tests = self.get_xfailed_tests()
|
||||
not_executed_tests = self.get_not_executed_tests(self.run_id)
|
||||
final_description = "Nothing to report this time..."
|
||||
if len(tests) > 0:
|
||||
description = ""
|
||||
description_title = "# %.0f%% of end-end tests have passed\n" % (len(passed_tests) / len(tests) * 100)
|
||||
description_title += "\n"
|
||||
description_title += "Total executed tests: %d\n" % len(tests)
|
||||
description_title += "Failed tests: %d\n" % len(failed_tests)
|
||||
description_title += "Undefined failed tests: %d\n" % len(failed_tests)
|
||||
description_title += "Failed tests: %d\n" % len(xfailed_tests)
|
||||
description_title += "Passed tests: %d\n" % len(passed_tests)
|
||||
if not_executed_tests:
|
||||
description_title += "Not executed tests: %d\n" % len(not_executed_tests)
|
||||
description_title += "\n"
|
||||
ids_failed_test = []
|
||||
single_devices_block, group_blocks, case_info = str(), dict(), str()
|
||||
if failed_tests:
|
||||
for test in failed_tests:
|
||||
if test.group_name:
|
||||
group_blocks[test.group_name] = "\n-------\n## Class: %s:\n" % test.group_name
|
||||
for test in failed_tests:
|
||||
last_testrun = test.testruns[-1]
|
||||
test_rail_link = self.get_test_result_link(self.run_id, test.testrail_case_id)
|
||||
ids_failed_test.append(test.testrail_case_id)
|
||||
case_title = '\n'
|
||||
case_title += '-------\n'
|
||||
case_title += "### ID %s: [%s](%s) \n" % (test.testrail_case_id, test.name, test_rail_link)
|
||||
full_error = last_testrun.error[-255:]
|
||||
(code_error, no_code_error_str, issue_id) = self.separate_xfail_error(full_error)
|
||||
if issue_id:
|
||||
test_rail_xfail = self.make_error_with_gh_issue_link(no_code_error_str, issue_id)
|
||||
error = "```%s```\n **%s** \n" % (code_error, test_rail_xfail)
|
||||
else:
|
||||
error = "```%s```\n **%s** \n" % (code_error, no_code_error_str)
|
||||
for job_id, f in last_testrun.jobs.items():
|
||||
if last_testrun.first_commands:
|
||||
job_url = self.get_sauce_job_url(job_id=job_id,
|
||||
first_command=last_testrun.first_commands[job_id])
|
||||
else:
|
||||
job_url = self.get_sauce_job_url(job_id=job_id)
|
||||
case_info = "Logs for device %d: [steps](%s), [failure screenshot](%s)" \
|
||||
% (f, job_url, self.get_sauce_final_screenshot_url(job_id))
|
||||
|
||||
if test.group_name:
|
||||
group_blocks[test.group_name] += case_title + error + case_info
|
||||
else:
|
||||
single_devices_block += case_title + error + case_info
|
||||
description_title += '## Failed tests: %s \n' % ','.join(map(str, ids_failed_test))
|
||||
description += "\n"
|
||||
description += "## Undefined failed tests:"
|
||||
failed_description, ids_failed_test = self.make_single_group_report(failed_tests)
|
||||
description += failed_description
|
||||
description_title += "## Undefined failed tests: %s\n" % ','.join([str(i) for i in ids_failed_test])
|
||||
if xfailed_tests:
|
||||
description += "\n"
|
||||
description += "## Failed tests (due to known issues):"
|
||||
xfailed_description, id_xfailed_tests = self.make_single_group_report(xfailed_tests, xfailed=True)
|
||||
description += xfailed_description
|
||||
description_title += "## Failed tests: %s\n" % ','.join([str(i) for i in id_xfailed_tests])
|
||||
if not_executed_tests:
|
||||
description_title += "## Not executed tests: %s\n" % ','.join([str(i) for i in not_executed_tests])
|
||||
final_description = description_title + single_devices_block + ''.join([i for i in group_blocks.values()])
|
||||
final_description = description_title + description
|
||||
|
||||
request_body = {'description': final_description}
|
||||
return self.post('update_run/%s' % self.run_id, request_body)
|
||||
|
||||
@@ -74,7 +74,7 @@ test_dapp_web_url = "status-im.github.io/dapp"
|
||||
test_dapp_url = 'https://simpledapp.status.im/'
|
||||
test_dapp_name = 'simpledapp.status.im'
|
||||
|
||||
emojis = {'thumbs-up': 5, 'thumbs-down': 6, 'love': 1, 'laugh': 4, 'angry': 2, 'sad': 3}
|
||||
emojis = {'thumbs-up': 2, 'thumbs-down': 3, 'love': 1, 'laugh': 4, 'angry': 6, 'sad': 5}
|
||||
|
||||
|
||||
with open(os.sep.join(__file__.split(os.sep)[:-1]) + '/../../../translations/en.json') as json_file:
|
||||
|
||||
@@ -283,6 +283,7 @@ class TestOneToOneChatMultipleSharedDevices(MultipleSharedDeviceTestCase):
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(5373)
|
||||
# moved
|
||||
def test_1_1_chat_emoji_send_reply_and_open_link(self):
|
||||
self.home_1.just_fyi("Check that can send emoji in 1-1 chat")
|
||||
emoji_name = random.choice(list(emoji.EMOJI_UNICODE))
|
||||
@@ -1230,6 +1231,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user,), (self.device_2.create_user,))))
|
||||
self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
|
||||
self.profile_1 = self.home_1.get_profile_view()
|
||||
self.profile_2 = self.home_2.get_profile_view()
|
||||
users = self.loop.run_until_complete(run_in_parallel(
|
||||
((self.home_1.get_public_key_and_username, True),
|
||||
(self.home_2.get_public_key_and_username, True))
|
||||
@@ -1238,6 +1240,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.public_key_2, self.default_username_2 = users[1]
|
||||
|
||||
self.profile_1.switch_push_notifications()
|
||||
self.profile_2.switch_push_notifications()
|
||||
|
||||
self.profile_1.just_fyi("Sending contact request via Profile > Contacts")
|
||||
self.profile_1.click_system_back_button_until_element_is_shown(self.profile_1.contacts_button)
|
||||
@@ -1269,12 +1272,61 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.device_2.just_fyi("Receiver sets own emoji and verifies counter on received message in 1-1 chat")
|
||||
message_receiver = self.chat_2.chat_element_by_text(message_from_sender)
|
||||
message_receiver.emojis_below_message().wait_for_element_text(1, 90)
|
||||
self.chat_2.set_reaction(message_from_sender)
|
||||
self.chat_2.add_remove_same_reaction(message_from_sender)
|
||||
message_receiver.emojis_below_message().wait_for_element_text(2)
|
||||
message_sender.emojis_below_message().wait_for_element_text(2, 90)
|
||||
|
||||
self.device_2.just_fyi("Receiver pick the same emoji and verify that counter will decrease for both users")
|
||||
self.chat_2.set_reaction(message_from_sender)
|
||||
message_sender.emojis_below_message().wait_for_element_text(1)
|
||||
message_receiver.emojis_below_message().wait_for_element_text(1, 90)
|
||||
self.chat_2.add_remove_same_reaction(message_from_sender)
|
||||
message_receiver.emojis_below_message().wait_for_element_text(1)
|
||||
message_sender.emojis_below_message().wait_for_element_text(1, 90)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702782)
|
||||
def test_1_1_chat_emoji_send_reply_and_open_link(self):
|
||||
self.home_1.just_fyi("Check that can send emoji in 1-1 chat")
|
||||
emoji_name = random.choice(list(emoji.EMOJI_UNICODE))
|
||||
emoji_unicode = emoji.EMOJI_UNICODE[emoji_name]
|
||||
self.chat_1.send_message(emoji.emojize(emoji_name))
|
||||
for chat in self.chat_1, self.chat_2:
|
||||
if not chat.chat_element_by_text(emoji_unicode).is_element_displayed():
|
||||
self.errors.append('Message with emoji was not sent or received in 1-1 chat')
|
||||
self.chat_1.quote_message(emoji_unicode)
|
||||
actual_text = self.chat_1.quote_username_in_message_input.text
|
||||
if actual_text != "You":
|
||||
self.errors.append("'You' is not displayed in reply quote snippet replying to own message, '%s' instead" % actual_text)
|
||||
|
||||
self.chat_1.just_fyi("Clear quote and check there is not snippet anymore")
|
||||
self.chat_1.cancel_reply_button.click()
|
||||
if self.chat_1.cancel_reply_button.is_element_displayed():
|
||||
self.errors.append("Message quote kept in public chat input after it was cancelled")
|
||||
|
||||
self.chat_1.just_fyi("Send reply")
|
||||
self.chat_1.quote_message(emoji_unicode)
|
||||
reply_to_message_from_sender = "hey, reply"
|
||||
self.chat_1.send_message(reply_to_message_from_sender)
|
||||
|
||||
self.chat_1.just_fyi("Receiver verifies received reply...")
|
||||
if self.chat_2.chat_element_by_text(reply_to_message_from_sender).replied_message_text != emoji_unicode:
|
||||
self.errors.append("No reply received in 1-1 chat")
|
||||
|
||||
self.home_1.just_fyi("Check that link can be opened and replied from 1-1 chat")
|
||||
reply = 'reply to link'
|
||||
url_message = 'Test with link: https://status.im/ here should be nothing unusual.'
|
||||
self.chat_1.send_message(url_message)
|
||||
self.chat_2.chat_element_by_text(url_message).wait_for_element(20)
|
||||
self.chat_2.quote_message(url_message)
|
||||
self.chat_2.send_message(reply)
|
||||
replied_message = self.chat_1.chat_element_by_text(reply)
|
||||
if replied_message.replied_message_text != url_message:
|
||||
self.errors.append("Reply for '%s' not present in message received in public chat" % url_message)
|
||||
# The "open_in_status" feature is not implemented yet
|
||||
# url_message = 'http://status.im'
|
||||
# self.chat_1.send_message(url_message)
|
||||
# self.chat_2.element_starts_with_text(url_message, 'button').click()
|
||||
# web_view = self.chat_2.open_in_status_button.click()
|
||||
# if not web_view.element_by_text('Private, Secure Communication').is_element_displayed(60):
|
||||
# self.errors.append('URL was not opened from 1-1 chat')
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702731)
|
||||
@@ -1412,19 +1464,80 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.errors.append("Image of user in 1-1 chat is too different from template!")
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702733)
|
||||
def test_1_1_chat_text_message_delete_push_disappear(self):
|
||||
@marks.testrail_id(702813)
|
||||
def test_1_1_chat_push_emoji(self):
|
||||
message_no_pn, message = 'No PN', 'Text push notification'
|
||||
|
||||
self.home_2.click_system_back_button_until_element_is_shown()
|
||||
self.home_2.browser_tab.click() # temp, until profile is on browser tab
|
||||
self.home_1.chats_tab.click()
|
||||
|
||||
self.device_2.just_fyi("Device 2 puts app on background being on Profile view to receive PN with text")
|
||||
if not self.chat_1.chat_message_input.is_element_displayed():
|
||||
self.home_1.get_chat(self.default_username_2).click()
|
||||
self.chat_1.send_message(message)
|
||||
|
||||
self.device_1.just_fyi("Device 1 puts app on background to receive emoji push notification")
|
||||
self.device_1.click_system_back_button_until_element_is_shown()
|
||||
self.device_1.browser_tab.click() # temp, until profile is on browser tab
|
||||
self.device_1.click_system_home_button()
|
||||
|
||||
self.device_2.just_fyi("Check text push notification and tap it")
|
||||
self.device_2.open_notification_bar()
|
||||
if not self.home_2.get_pn(message):
|
||||
self.device_2.driver.fail("Push notification with text was not received")
|
||||
chat_2 = self.device_2.click_upon_push_notification_by_text(message)
|
||||
|
||||
self.device_2.just_fyi("Send emoji message to Device 1 while it's on background")
|
||||
emoji_message = random.choice(list(emoji.EMOJI_UNICODE))
|
||||
emoji_unicode = emoji.EMOJI_UNICODE[emoji_message]
|
||||
chat_2.send_message(emoji.emojize(emoji_message))
|
||||
|
||||
self.device_1.just_fyi("Device 1 checks PN with emoji")
|
||||
self.device_1.open_notification_bar()
|
||||
if not self.device_1.element_by_text_part(emoji_unicode).is_element_displayed(10):
|
||||
self.device_1.driver.fail("Push notification with emoji was not received")
|
||||
chat_1 = self.device_1.click_upon_push_notification_by_text(emoji_unicode)
|
||||
|
||||
self.device_1.just_fyi("Check Device 1 is actually on chat")
|
||||
if not (chat_1.element_by_text_part(message).is_element_displayed()
|
||||
and chat_1.element_by_text_part(emoji_unicode).is_element_displayed()):
|
||||
self.device_1.driver.fail("Failed to open chat view after tap on PN")
|
||||
|
||||
self.device_1.just_fyi("Checks there are no PN after message was seen")
|
||||
[device.open_notification_bar() for device in (self.device_1, self.device_2)]
|
||||
if (self.device_2.element_by_text_part(message).is_element_displayed()
|
||||
or self.device_1.element_by_text_part(emoji_unicode).is_element_displayed()):
|
||||
self.errors.append("PN are keep staying after message was seen by user")
|
||||
[device.click_system_back_button_until_element_is_shown(element='chat') for device in (self.device_1, self.device_2)]
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702733)
|
||||
def test_1_1_chat_text_message_edit_delete_push_disappear(self):
|
||||
if not self.chat_1.chat_message_input.is_element_displayed():
|
||||
self.home_1.get_chat(self.default_username_2).click()
|
||||
if not self.chat_2.chat_message_input.is_element_displayed():
|
||||
self.home_1.get_chat(self.default_username_1).click()
|
||||
self.device_2.just_fyi("Verify Device1 can not edit and delete received message from Device2")
|
||||
message_after_edit_1_1 = 'smth I should edit'
|
||||
message_to_delete_for_me = 'message to delete for me'
|
||||
self.chat_2.send_message(message_after_edit_1_1)
|
||||
chat_1_element = self.chat_1.chat_element_by_text(message_after_edit_1_1)
|
||||
chat_1_element.long_press_element()
|
||||
for action in ("edit", "delete-for-everyone"):
|
||||
if self.chat_1.element_by_translation_id(action).is_element_displayed():
|
||||
self.errors.append('Option to %s someone else message available!' % action)
|
||||
self.home_1.click_system_back_button()
|
||||
self.home_1.tap_by_coordinates(500, 100)
|
||||
|
||||
self.device_2.just_fyi("Delete message for me and check it is only deleted for the author")
|
||||
self.chat_2.send_message(message_to_delete_for_me)
|
||||
self.chat_2.delete_message_in_chat(message_to_delete_for_me, everyone=False)
|
||||
if not self.chat_2.chat_element_by_text(message_to_delete_for_me).is_element_disappeared(20):
|
||||
self.errors.append("Deleted for me message is shown in chat for the author of message")
|
||||
if not self.chat_2.element_by_translation_id('message-deleted-for-you').is_element_displayed(20):
|
||||
self.errors.append("System message about deletion for you is not displayed")
|
||||
if not self.chat_1.chat_element_by_text(message_to_delete_for_me).is_element_displayed(20):
|
||||
self.errors.append("Deleted for me message is deleted for both users")
|
||||
|
||||
self.device_2.just_fyi("Delete message for everyone and check it is not shown in chat preview on home")
|
||||
self.chat_2.delete_message_in_chat(message_after_edit_1_1)
|
||||
@@ -1437,7 +1550,6 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
|
||||
self.device_2.just_fyi("Send one more message and check that PN will be deleted with message deletion")
|
||||
message_to_delete = 'DELETE ME'
|
||||
self.home_1.put_app_to_background()
|
||||
self.chat_2.send_message(message_to_delete)
|
||||
self.home_1.open_notification_bar()
|
||||
if not self.home_1.get_pn(message_to_delete):
|
||||
@@ -1445,7 +1557,73 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.chat_2.delete_message_in_chat(message_to_delete)
|
||||
pn_to_disappear = self.home_1.get_pn(message_to_delete)
|
||||
if pn_to_disappear:
|
||||
if not pn_to_disappear.is_element_disappeared(30):
|
||||
if not pn_to_disappear.is_element_disappeared(90):
|
||||
self.errors.append("Push notification was not removed after initial message deletion")
|
||||
[device.click_system_back_button_until_element_is_shown() for device in (self.device_1, self.device_2)]
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
# skipped to move to another 1-1 group
|
||||
# @marks.testrail_id(702783)
|
||||
# def test_1_1_chat_is_shown_message_sent_delivered_from_offline(self):
|
||||
# self.home_1.get_home_view()
|
||||
# self.home_2.chats_tab.click()
|
||||
#
|
||||
# self.home_1.just_fyi('Turn on airplane mode and check that offline status is shown on home view')
|
||||
# self.home_1.toggle_airplane_mode()
|
||||
# self.home_2.toggle_airplane_mode()
|
||||
# # Not implemented yet
|
||||
# # self.home_1.connection_offline_icon.wait_and_click(20)
|
||||
# # for element in self.home_1.not_connected_to_node_text, self.home_1.not_connected_to_peers_text:
|
||||
# # if not element.is_element_displayed():
|
||||
# # self.errors.append(
|
||||
# # 'Element "%s" is not shown in Connection status screen if device is offline' % element.locator)
|
||||
# # self.home_1.click_system_back_button()
|
||||
#
|
||||
# message_1 = 'test message'
|
||||
#
|
||||
# self.home_2.just_fyi('Device2 checks "Sending" status when sending message from offline')
|
||||
# self.home_2.get_chat(username=self.default_username_1).click()
|
||||
# self.chat_2.send_message(message_1)
|
||||
# chat_element = self.chat_2.chat_element_by_text(message_1)
|
||||
# if chat_element.status != 'sending':
|
||||
# self.errors.append('Message status is not "Sending", it is %s!' % chat_element.status)
|
||||
#
|
||||
# self.home_2.just_fyi('Device2 goes back online and checks that status of the message is changed to "Sent"')
|
||||
# self.chat_2.toggle_airplane_mode()
|
||||
# if chat_element.status != 'sent':
|
||||
# self.errors.append('Message status is not "Sent", it is %s!' % chat_element.status)
|
||||
#
|
||||
# self.home_1.just_fyi('Device1 goes back online and checks that 1-1 chat will be fetched')
|
||||
# self.home_1.toggle_airplane_mode()
|
||||
# self.home_1.get_home_view()
|
||||
# chat_element = self.home_1.get_chat(self.default_username_2, wait_time=60)
|
||||
# chat_element.click()
|
||||
# self.chat_1.chat_element_by_text(message_1).wait_for_visibility_of_element(20)
|
||||
#
|
||||
# self.home_2.just_fyi('Device2 checks offline fetching for another message, check delivered status for first message')
|
||||
# if self.chat_2.chat_element_by_text(message_1).status != 'delivered':
|
||||
# self.errors.append(
|
||||
# 'Message status is not "Delivered", it is %s!' % self.chat_2.chat_element_by_text(message_1).status)
|
||||
# self.home_1.toggle_airplane_mode()
|
||||
# message_2 = 'one more message'
|
||||
# self.chat_2.send_message(message_2)
|
||||
# self.home_1.toggle_airplane_mode()
|
||||
# chat_1 = chat_element.click()
|
||||
# chat_1.chat_element_by_text(message_2).wait_for_visibility_of_element(180)
|
||||
# self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702784)
|
||||
def test_1_1_chat_delete_via_long_press_relogin(self):
|
||||
self.home_1.driver.quit()
|
||||
self.home_2.click_system_back_button_until_element_is_shown()
|
||||
self.home_2.chats_tab.click()
|
||||
|
||||
self.home_2.just_fyi("Deleting chat via delete button and check it will not reappear after relaunching app")
|
||||
self.home_2.delete_chat_long_press(username=self.default_username_1)
|
||||
if self.home_2.get_chat_from_home_view(self.default_username_1).is_element_displayed():
|
||||
self.errors.append('Deleted %s chat is shown, but the chat has been deleted' % self.default_username_1)
|
||||
self.home_2.reopen_app()
|
||||
if self.home_2.get_chat_from_home_view(self.default_username_1).is_element_displayed(15):
|
||||
self.errors.append(
|
||||
'Deleted chat %s is shown after re-login, but the chat has been deleted' % self.default_username_1)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user