Anonymous metrics opt-in UI

Settings screen
Settings event handler and connection to UI
Both bottom sheets with text in place
Make links inline
Show metrics in progress
Event value in accordion
Repurpose metrics screen for first time users
Onboarding metrics screen working, but not connected to flow. No animations yet.
Show opt-in banner for new accounts
Show opt in screen on login for existing accounts. Don't start metrics service for accounts where metrics are disabled
Tighten start/stop logic
Pagination and loader
Remove prn and fix lint
Ui fixes
Thank you animation
lint fix
PR comment fixes
Get rid of set, fix lint
Have an overshoot but buttons stopped working
add accessibility labels
True modals and fix opt-in displayed multiple times error
Fix icon cutting off on the top on smaller screens
Replace "invite-instructions" to "how-it-works" in all translatiosn
Add pagination to view-data events
Refactor open and close modal functions
Remove dispatch from init-db
Update status go to include pagination of data
Put metrics behind a feature flag

Signed-off-by: Shivek Khurana <shivek@status.im>
This commit is contained in:
Shivek Khurana 2021-04-16 14:33:07 +05:30
parent e4e9556303
commit 8448570922
No known key found for this signature in database
GPG Key ID: 9BEB56E6E62968C7
51 changed files with 603 additions and 116 deletions

1
.env
View File

@ -28,3 +28,4 @@ MAX_IMAGES_BATCH=5
APN_TOPIC=im.status.ethereum.pr
COMMUNITIES_ENABLED=1
DATABASE_MANAGEMENT_ENABLED=1
METRICS_ENABLED=0

View File

@ -28,3 +28,4 @@ APN_TOPIC=im.status.ethereum.pr
VERIFY_TRANSACTION_CHAIN_ID=3
COMMUNITIES_ENABLED=1
COMMUNITIES_MANAGEMENT_ENABLED=1
METRICS_ENABLED=0

View File

@ -28,3 +28,4 @@ MAX_IMAGES_BATCH=5
GOOGLE_FREE=0
COMMUNITIES_ENABLED=1
COMMUNITIES_MANAGEMENT_ENABLED=1
METRICS_ENABLED=0

View File

@ -22,3 +22,4 @@ MAX_IMAGES_BATCH=5
BLANK_PREVIEW=0
COMMUNITIES_ENABLED=1
DATABASE_MANAGEMENT_ENABLED=1
METRICS_ENABLED=0

View File

@ -18,3 +18,4 @@ PARTITIONED_TOPIC=0
ENABLE_ROOT_ALERT=1
MAX_IMAGES_BATCH=1
ENABLE_REFERRAL_INVITE=0
METRICS_ENABLED=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

View File

@ -1,12 +1,15 @@
(ns status-im.anon-metrics.core
(:require [status-im.ethereum.json-rpc :as json-rpc]
[taoensso.timbre :as log]
(:require [taoensso.timbre :as log]
[re-frame.core :as re-frame]
[re-frame.interceptor :refer [->interceptor]]
[status-im.async-storage.core :as async-storage]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.utils.async :refer [async-periodic-exec async-periodic-stop!]]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.platform :as platform]
[status-im.utils.build :as build]
[status-im.utils.fx :as fx]
[status-im.utils.config :as config]
[status-im.anon-metrics.transformers :as txf]))
(defonce events-foyer (atom []))
@ -26,7 +29,7 @@
:on-error (fn [err]
(log/error {:error err
:events outstanding-events})
(log/warn "All outstanding events will be rejected"))}))))
(log/warn "The logged events will be rejected"))}))))
(re-frame/reg-fx
::transfer-data
@ -42,11 +45,10 @@
(async-periodic-exec onboard-events 4000 5000)))
(do
(log/info "[anon-metrics] Stop collection service")
(when @periodic-tasks-chan
(async-periodic-stop! @periodic-tasks-chan)
(reset! periodic-tasks-chan nil)
;; final onboard, will save and clear any pending events
(onboard-events)))))
(onboard-events) ; final onboard, will save and clear any pending events
(reset! periodic-tasks-chan nil))))))
(fx/defn start-transferring
[_]
@ -57,14 +59,25 @@
{::transfer-data false})
(defn transform-and-log [context]
(when-let [transformed-payload (txf/transform context)]
(let [transformed-payload (txf/transform context)
should-send? (get-in context
[:coeffects
:db
:multiaccount
:anon-metrics/should-send?]
false)]
(when (and config/metrics-enabled? ;metrics are enabled
should-send? ; user opted-in
transformed-payload); we were able to transform metrics-shape
(swap!
events-foyer
conj
{:event (-> context :coeffects :event first)
:value transformed-payload
:app_version build/version
:os platform/os})))
:os platform/os}))))
(re-frame/reg-fx ::transform-and-log transform-and-log)
(defn catch-events-before [context]
(transform-and-log context)
@ -75,8 +88,6 @@
:id :catch-events
:before catch-events-before))
(re-frame/reg-fx ::transform-and-log transform-and-log)
(fx/defn hoax-capture-event
"Due to usage of fx/defn with fx/merge, it might not be able to
intercept some events (like navigate-to-cofx). In cases like that,
@ -86,6 +97,79 @@
;; re-shape event to look like a context object
{::transform-and-log {:coeffects {:event og-event}}})
(fx/defn fetch-local-metrics-success
{:events [::fetch-local-metrics-success]}
[{:keys [db]} {:keys [metrics total-count clear-existing?]}]
{:db (-> db
(as-> db
(if clear-existing?
(assoc db
:anon-metrics/events metrics
:anon-metrics/total-count total-count)
(update db :anon-metrics/events concat metrics)))
(dissoc :anon-metrics/fetching?))})
(fx/defn fetch-local-metrics
{:events [::fetch-local-metrics]}
[{:keys [db]} {:keys [limit offset clear-existing?]}]
{::json-rpc/call [{:method "appmetrics_getAppMetrics"
:params [(or limit 3) (or offset 0)]
:on-success #(re-frame/dispatch
[::fetch-local-metrics-success
{:metrics (get % :AppMetrics [])
:total-count (get % :TotalCount 0)
:clear-existing? clear-existing?}])}]
:db (assoc db :anon-metrics/fetching? true)})
(fx/defn set-opt-in-screen-displayed-flag
[{:keys [db]}]
{::async-storage/set! {:anon-metrics/opt-in-screen-displayed? true}
:db (assoc db :anon-metrics/opt-in-screen-displayed? true)})
(fx/defn set-show-thank-you
{:events [::set-show-thank-you]}
[{:keys [db]} show?]
{:db (assoc db :anon-metrics/show-thank-you? show?)})
(defn on-opt-in-success [enabled?]
(if enabled?
(do
;; animate
(re-frame/dispatch [::set-show-thank-you true])
;; and redirect after 1 second
(js/setTimeout
(fn []
(re-frame/dispatch [:navigate-reset {:index 0
:routes [{:name :tabs}]}])
(re-frame/dispatch [::set-show-thank-you false]))
1000))
(re-frame/dispatch [:navigate-reset {:index 0
:routes [{:name :tabs}]}])))
(fx/defn fetch-opt-in-displayed-success
{:events [::fetch-opt-in-displayed-success]}
[{:keys [db]} [k v]]
{:db (assoc db k v)})
(fx/defn fetch-opt-in-screen-displayed?
{:events [::fetch-opt-in-screen-displayed?]}
[cofx]
{::async-storage/get
{:keys [:anon-metrics/opt-in-screen-displayed?]
:cb #(re-frame/dispatch [::fetch-opt-in-displayed-success (first %)])}})
(fx/defn opt-in
{:events [::opt-in]}
[cofx enabled?]
(fx/merge cofx
(set-opt-in-screen-displayed-flag)
(if enabled?
(start-transferring)
(stop-transferring))
(multiaccounts.update/multiaccount-update
:anon-metrics/should-send? enabled?
{:on-success #(on-opt-in-success enabled?)})))
(comment
;; read the database
(def events-in-db (atom nil))
@ -95,3 +179,4 @@
(json-rpc/call {:method "appmetrics_getAppMetrics"
:params [1000 0] ; limit, offset
:on-success #(reset! events-in-db %)}))

View File

@ -145,3 +145,6 @@
(def ^:const three-days (* one-day 3))
(def ^:const one-week (* one-day 7))
(def ^:const one-month (* one-day 31))
(def ^:const metrics-github-link
"https://github.com/status-im/status-go/blob/develop/_docs/app-metrics.md")

View File

@ -2,6 +2,7 @@
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.multiaccounts.login.core :as multiaccounts.login]
[status-im.anon-metrics.core :as anon-metrics]
[status-im.native-module.core :as status]
[status-im.network.net-info :as network]
[status-im.db :refer [app-db]]
@ -53,7 +54,8 @@
(assoc :multiaccounts/loading false))
;; NOTE: Try to dispatch later navigation because of that https://github.com/react-navigation/react-navigation/issues/6879
:dispatch-later [{:dispatch [::initialize-view {:logout? logout?}]
:ms 100}]})))
:ms 100}]
:dispatch [::anon-metrics/fetch-opt-in-screen-displayed?]})))
(fx/defn start-app
{:events [:init/app-started]}

View File

@ -3,6 +3,7 @@
[status-im.ethereum.stateofus :as stateofus]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.anon-metrics.core :as anon-metrics]
[status-im.native-module.core :as native-module]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx]
@ -138,6 +139,17 @@
:default-sync-period value
{}))
(fx/defn switch-share-anonymous-usage-data
{:events [:multiaccounts.ui/share-anonymous-usage-data-switched]}
[cofx opted-in?]
(fx/merge cofx
(multiaccounts.update/multiaccount-update
:anon-metrics/should-send? (boolean opted-in?)
{})
(if opted-in?
(anon-metrics/start-transferring)
(anon-metrics/stop-transferring))))
(fx/defn switch-preview-privacy-mode-flag
[{:keys [db]}]
(let [private? (get-in db [:multiaccount :preview-privacy?])]

View File

@ -355,7 +355,9 @@
login-only? (not (or creating?
recovered-account?
(keycard-setup? cofx)))
nodes nil]
nodes nil
should-send-metrics? (get-in db [:multiaccount :anon-metrics/should-send?])
opt-in-screen-displayed? (get db :anon-metrics/opt-in-screen-displayed?)]
(log/debug "[multiaccount] multiaccount-login-success"
"login-only?" login-only?
"recovered-account?" recovered-account?)
@ -373,7 +375,8 @@
[{:method "web3_clientVersion"
:on-success #(re-frame/dispatch [::initialize-web3-client-version %])}]}
;; Start tasks to save usage data locally
(anon-metrics/start-transferring)
(when should-send-metrics?
(anon-metrics/start-transferring))
;;FIXME
(when nodes
(fleet/set-nodes :eth.contract nodes))
@ -382,7 +385,11 @@
(wallet/set-initial-blocks-range))
(if login-only?
(login-only-events key-uid password save-password?)
(create-only-events)))))
(create-only-events))
(when (and login-only?
(not opt-in-screen-displayed?)
config/metrics-enabled?)
(navigation/navigate-to :anon-metrics-opt-in {})))))
;; FIXME(Ferossgp): We should not copy keys as we denormalize the database,
;; this create desync between actual accounts and the one on login causing broken state
@ -514,8 +521,10 @@
(fx/merge cofx
(when first-account?
(acquisition/create))
(if config/metrics-enabled?
(navigation/navigate-to :anon-metrics-opt-in {})
(navigation/navigate-reset {:index 0
:routes [{:name :tabs}]}))))
:routes [{:name :tabs}]})))))
(fx/defn multiaccount-selected
{:events [:multiaccounts.login.ui/multiaccount-selected]}

View File

@ -13,7 +13,8 @@
(fx/defn logout-method
[{:keys [db] :as cofx} {:keys [auth-method logout?]}]
(let [key-uid (get-in db [:multiaccount :key-uid])]
(let [key-uid (get-in db [:multiaccount :key-uid])
should-send-metrics? (get-in db [:multiaccount :anon-metrics/should-send?])]
(fx/merge cofx
{::logout nil
::multiaccounts/webview-debug-changed false
@ -21,7 +22,8 @@
:keychain/clear-user-password key-uid
::init/open-multiaccounts #(re-frame/dispatch [::init/initialize-multiaccounts % {:logout? logout?}])}
(notifications/logout-disable)
(anon-metrics/stop-transferring)
(when should-send-metrics?
(anon-metrics/stop-transferring))
(keychain/save-auth-method key-uid auth-method)
(transport/stop-whisper)
(wallet/clear-timeouts)

View File

@ -42,7 +42,8 @@
:theme-dark (js/require "../resources/images/ui/theme-dark.png")
:theme-light (js/require "../resources/images/ui/theme-light.png")
:theme-system (js/require "../resources/images/ui/theme-system.png")
:notifications (js/require "../resources/images/ui/notifications.png")})
:notifications (js/require "../resources/images/ui/notifications.png")
:graph (js/require "../resources/images/ui/graph.png")})
(defn get-theme-image [k]
(get ui (when (colors/dark?) (keyword (str (name k) "-dark"))) (get ui k)))

View File

@ -220,6 +220,15 @@
(reg-root-key-sub :activity.center/notifications :activity.center/notifications)
(reg-root-key-sub :activity.center/notifications-count :activity.center/notifications-count)
;; anon. metrics
(reg-root-key-sub :anon-metrics/opt-in-screen-displayed? :anon-metrics/opt-in-screen-displayed?)
(reg-root-key-sub :anon-metrics/show-thank-you? :anon-metrics/show-thank-you?)
(reg-root-key-sub :anon-metrics/events :anon-metrics/events)
(reg-root-key-sub :anon-metrics/total-count :anon-metrics/total-count)
(reg-root-key-sub :anon-metrics/fetching? :anon-metrics/fetching?)
(reg-root-key-sub :anon-metrics/data-visible? :anon-metrics/data-visible?)
(reg-root-key-sub :anon-metrics/learn-more-visible? :anon-metrics/learn-more-visible?)
(re-frame/reg-sub
:communities
:<- [:raw-communities]

View File

@ -5,31 +5,32 @@
[status-im.ui.components.react :as react]
[status-im.ui.components.icons.icons :as icons]))
(defn section
"Render collapsible section"
[_props]
(let [opened? (reagent/atom false)]
(fn [{:keys [title cnt content icon]}]
[react/view {:padding-vertical 8}
[quo/list-item
{:title title
:icon icon
:on-press #(swap! opened? not)
:accessory
(defn drop-down-icon [opened?]
[react/view {:flex-direction :row :align-items :center}
(when (pos? cnt)
[react/text {:style {:color colors/gray}} cnt])
[icons/icon (if @opened? :main-icons/dropdown-up :main-icons/dropdown)
[icons/icon (if opened? :main-icons/dropdown-up :main-icons/dropdown)
{:container-style {:align-items :center
:margin-left 8
:justify-content :center}
:resize-mode :center
:color colors/black}]]}]
:color colors/black}]])
(defn section
"Render collapsible section"
[_props]
(let [opened? (reagent/atom false)]
(fn [{:keys [title content icon]}]
[react/view {:padding-vertical 8}
(if (string? title)
[quo/list-item
{:title title
:icon icon
:on-press #(swap! opened? not)
:accessory [drop-down-icon @opened?]}]
[react/touchable-opacity {:on-press #(swap! opened? not)}
[react/view {:flex-direction :row
:justify-content :space-between}
title
[drop-down-icon @opened?]]])
(when @opened?
content)])))
(defn accordion
"List of collapseable sections"
[])
;; TODO(shivekkhurana): Extract status-im.ui.screens.wallet.recipient.views/accordion component here

View File

@ -105,7 +105,7 @@
[rn/view {:style (styles/invite-instructions)}
[rn/view {:style (styles/invite-instructions-title)}
[quo/text {:color :secondary}
(i18n/label :t/invite-instruction)]]
(i18n/label :t/how-it-works)]]
[rn/view {:style (styles/invite-warning)}
[quo/text (i18n/label :t/invite-warning)]]
[rn/view {:style (styles/invite-instructions-content)}

View File

@ -7,6 +7,10 @@
:image-preview {:type :black}}
(when platform/ios?
{:new-chat {:type :black}
:contact-toggle-list {:type :black}
:new-group {:type :black}
:anon-metrics-view-data {:type :black}
:anon-metrics-learn-more {:type :black}
:new-public-chat {:type :black}})))
;; TODO: Integrate into navigation

View File

@ -0,0 +1,301 @@
(ns status-im.ui.screens.anonymous-metrics-settings.views
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :as re-frame]
[status-im.ui.components.animation :as animation]
[status-im.react-native.resources :as resources]
[status-im.anon-metrics.core :as anon-metrics]
[status-im.ui.components.accordion :as accordion]
[status-im.ui.components.react :as react]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.icons.icons :as icons]
[status-im.i18n.i18n :as i18n]
[status-im.constants :refer [metrics-github-link]]
[quo.design-system.spacing :as spacing]
[status-im.ui.components.topbar :as topbar]
[quo.core :as quo]))
(defn graphic-and-desc [{:keys [show-title?]}]
[:<>
[react/view {:align-items :center
:margin-vertical 25}
[react/image {:source (resources/get-image :graph)}]]
(when show-title?
[quo/text {:size :x-large
:weight :bold
:align :center
:style {:margin-bottom 16}}
(i18n/label :t/help-improve-status)])
[react/touchable-highlight
{:on-press #(re-frame/dispatch [:navigate-to :anon-metrics-learn-more])
:accessibility-label :learn-more-anchor}
[react/nested-text
{:style (merge {:color colors/gray
:text-align :center}
(:large spacing/padding-horizontal))}
(i18n/label :t/anonymous-usage-data-subtitle)
[{:style {:color colors/blue
;; :font-weight key doesn't work
:fontWeight :bold}}
(str " " (i18n/label :t/learn-more))]]]])
(defn setting-switch [enabled? on-press]
[quo/list-item {:title (i18n/label :t/share-anonymous-usage-data)
:active enabled?
:accessibility-label :opt-in-switch
:accessory :switch
:subtitle-max-lines 2
:on-press on-press}])
(defn icon-list-item
([icon label]
(icon-list-item icon {} label))
([icon icon-opts label]
[react/view {:flex-direction :row
:margin-horizontal (:base spacing/spacing)
:margin-vertical (:tiny spacing/spacing)}
[icons/icon icon (into icon-opts
{:container-style {:margin-top 1.2
:margin-right (:tiny spacing/spacing)}})]
[react/view {:style {:padding-right (:xx-large spacing/spacing)}}
(if (string? label)
[react/text label]
label)]]))
(defn what-is-shared []
[:<>
[quo/list-header (i18n/label :t/what-is-shared)]
(for [label [(i18n/label :t/anon-metrics-your-interactions)
(i18n/label :t/anon-metrics-bg-activity)
(i18n/label :t/anon-metrics-settings-and-prefs)]]
^{:key label}
[icon-list-item :main-icons/info {:color colors/blue} label])])
(defn event-item [event]
[accordion/section
{:title [react/view {:flex 1
:flex-direction :row
:margin-bottom (:base spacing/spacing)}
[react/view {:style {:padding-right (:base spacing/spacing)}}
(for [label ["event" "time" "os"]]
^{:key label}
[react/text {:style {:color colors/gray}}
label])]
[react/view
[react/text (:event event)]
[react/text (:created_at event)]
[react/text (:os event)]]]
:content [react/view {:style {:background-color colors/gray-lighter
:padding (:small spacing/spacing)
:border-radius 14}}
[react/text (:value event)]]}])
(defn data-sheet-header-and-desc []
[:<>
[quo/text {:size :x-large
:weight :bold
:align :center
:style {:margin-vertical 16}}
(i18n/label :t/data-collected)]
[react/touchable-highlight
{:on-press #(.openURL ^js react/linking metrics-github-link)}
[react/nested-text
{:style (:base spacing/padding-horizontal)}
(i18n/label :t/data-collected-subtitle)
[{:style {:color colors/blue}}
(str " " (i18n/label :t/view-rules))]]]])
(defview view-data []
(letsubs [events [:anon-metrics/events]
total [:anon-metrics/total-count]
fetching? [:anon-metrics/fetching?]]
{:component-did-mount #(re-frame/dispatch [::anon-metrics/fetch-local-metrics
{:clear-existing? true
:limit 10
:offset 0}])}
[:<>
[topbar/topbar {:modal? true
:border-bottom false}]
[react/scroll-view
[data-sheet-header-and-desc]
[quo/list-header (i18n/label :t/count-metrics-collected {:count total})]
(when (pos? total)
[react/view
{:style (merge
{:border-width 1
:border-radius 8
:border-color colors/gray-lighter
:padding-top 16
:padding-bottom 20
:margin 16}
(:base spacing/padding-horizontal))}
(doall
(map-indexed
(fn [index event]
^{:key index}
[event-item event])
events))
(if fetching?
[react/activity-indicator {:size :large
:animating true}]
[quo/button {:type :primary
:disabled (= (count events) total)
:accessibility-label :show-more-button
:on-press #(re-frame/dispatch [::anon-metrics/fetch-local-metrics
{:clear-existing? false
:limit 10
:offset (count events)}])}
(i18n/label :t/show-more)])])]]))
(defn view-data-button []
[react/view {:flex 1
:align-items :center
:style {:margin-top (:x-large spacing/spacing)}}
[quo/button {:type :primary
:theme :main
:accessibility-label :view-data-button
:on-press #(re-frame/dispatch [:navigate-to :anon-metrics-view-data])}
(i18n/label :t/view-data)]])
(defn desc-point-with-link [desc link-text link-href accessibility-label]
[react/touchable-highlight {:on-press #(.openURL ^js react/linking link-href)
:accessibility-label accessibility-label}
[react/view
[react/text desc]
[react/view {:flex-direction :row}
[react/text {:style {:text-align :center
:color colors/blue}}
link-text]
[icons/tiny-icon :tiny-icons/tiny-external
{:color colors/blue
:container-style {:margin-left 4
:margin-top 4}}]]]])
(defn learn-more []
[:<>
[topbar/topbar {:modal? true
:border-bottom false}]
[react/scroll-view
[quo/text {:size :x-large
:weight :bold
:align :center
:style {:margin-top 16}}
(i18n/label :t/about-sharing-data)]
[react/text {:style (merge
(:base spacing/padding-horizontal)
(:small spacing/padding-vertical))}
(i18n/label :t/about-sharing-data-subtitle)]
[what-is-shared]
[view-data-button]
[quo/separator {:style {:margin-vertical (:base spacing/spacing)}}]
[quo/list-header (i18n/label :t/how-it-works)]
(for [label [[desc-point-with-link
(i18n/label :t/sharing-data-desc-1)
(i18n/label :t/view-rules)
metrics-github-link
:view-rules-anchor]
(i18n/label :t/sharing-data-desc-2)
(i18n/label :t/sharing-data-desc-3)
(i18n/label :t/sharing-data-desc-4)
;; TODO (shivekkhurana): Enable this link when the public
;; dashboard is live
;; [desc-point-with-link
;; (i18n/label :t/sharing-data-desc-5)
;; (i18n/label :t/view-public-dashboard)
;; "https://github.com/"
;; :view-dashboad-anchor]
(i18n/label :t/sharing-data-desc-6)]]
^{:key label}
[icon-list-item :main-icons/arrow-right {:color colors/blue} label])
[react/view {:style {:margin-bottom (:xx-large spacing/spacing)}}]]])
(defview settings []
(letsubs [{:keys [:anon-metrics/should-send?]} [:multiaccount]]
[:<>
[topbar/topbar {:title (i18n/label :t/anonymous-usage-data)}]
[react/scroll-view {:flex 1}
[graphic-and-desc]
[setting-switch
should-send?
#(re-frame/dispatch [:multiaccounts.ui/share-anonymous-usage-data-switched (not should-send?)])]
[quo/separator]
[what-is-shared]
[react/view {:padding-bottom 80}
[view-data-button]]]]))
(defn allow-or-not-actions []
[react/view {:align-items :center
:style {:padding-bottom 80}}
[quo/button {:type :primary
:theme :main
:accessibility-label :opt-in-button
:on-press #(re-frame/dispatch [::anon-metrics/opt-in true])}
(i18n/label :t/allow-and-send)]
[react/view {:style {:margin-top (:base spacing/spacing)}}]
[quo/button {:type :primary
:theme :main
:accessibility-label :opt-out-button
:on-press #(re-frame/dispatch [::anon-metrics/opt-in false])}
(i18n/label :t/no-thanks)]])
(defn thank-you-animation [overlay-opacity box-opacity]
(fn []
(animation/start
(animation/parallel
[(animation/spring
overlay-opacity
{:toValue 0.72
:useNativeDriver true})
(animation/spring
box-opacity
{:toValue 1
:useNativeDriver true})]))))
(defview floating-thank-you []
(letsubs [overlay-opacity (animation/create-value 1)
box-opacity (animation/create-value 0.2)]
{:component-did-mount (thank-you-animation overlay-opacity box-opacity)}
[:<>
[react/animated-view ; thank you container
{:style {:position :absolute
:opacity box-opacity
:z-index 2
:top "40%"
:padding (:x-large spacing/spacing)
:background-color colors/white
:align-items :center
:align-self :center}}
[react/text {:style {:font-size 32}} "\uD83C\uDF89"]
[quo/text {:size :x-large
:weight :bold}
(i18n/label :t/thank-you)]]
[react/animated-view ; translucent overlay
{:style {:position :absolute
:top 0
:bottom 0
:left 0
:right 0
:z-index 1
:background-color colors/white
:opacity overlay-opacity}}]]))
(defview new-account-opt-in []
(letsubs [show-thank-you? [:anon-metrics/show-thank-you?]]
[react/scroll-view {:flex 1
:padding-vertical (:large spacing/spacing)
:flex-direction :column}
(when show-thank-you? [floating-thank-you])
[graphic-and-desc {:show-title? true}]
[react/view {:style {:margin-bottom (:small spacing/spacing)
:margin-top (:large spacing/spacing)}}
[quo/separator]]
[what-is-shared]
[react/view {:style (:large spacing/padding-vertical)}
[quo/separator]]
[allow-or-not-actions]]))
(comment
(re-frame/dispatch [:navigate-back])
(re-frame/dispatch [:navigate-to :metrics-learn-more])
(re-frame/dispatch [:navigate-to :metrics-view-data])
(re-frame/dispatch [:navigate-to :anon-metrics-opt-in {}]))

View File

@ -61,7 +61,6 @@
[accordion/section {:title name
:icon [chat-icon.screen/contact-icon-contacts-tab
(multiaccounts/displayed-photo multiaccount)]
:count 0
:content [accordion-content]}]
[react/view {:flex 1
:flex-direction :column

View File

@ -5,6 +5,7 @@
[status-im.ui.components.colors :as colors]
[status-im.ui.components.common.common :as components.common]
[status-im.ui.components.react :as react]
[status-im.utils.config :as config]
[status-im.multiaccounts.biometric.core :as biometric]
[status-im.ui.components.topbar :as topbar]
[status-im.utils.platform :as platform])
@ -79,6 +80,12 @@
:t/anyone))
:on-press #(re-frame/dispatch [:navigate-to :messages-from-contacts-only])
:accessibility-label :accept-new-chats-from}]
(when config/metrics-enabled?
[quo/list-item {:size :small
:title (i18n/label :t/anonymous-usage-data)
:chevron true
:on-press #(re-frame/dispatch [:navigate-to :anonymous-metrics-settings])
:accessibility-label :anonymous-usage-data}])
(when platform/android?
[quo/list-item {:size :small
:title (i18n/label :t/webview-camera-permission-requests)

View File

@ -6,6 +6,7 @@
[status-im.ui.screens.stickers.views :as stickers]
[status-im.ui.screens.home.views :as home]
[status-im.ui.screens.add-new.new-chat.views :as new-chat]
[status-im.ui.screens.anonymous-metrics-settings.views :as anon-metrics-settings]
[status-im.add-new.core :as new-chat.events]
[status-im.ui.screens.routing.intro-login-stack :as intro-login-stack]
[status-im.ui.screens.routing.chat-stack :as chat-stack]
@ -80,6 +81,9 @@
{:name :welcome
:back-handler :noop
:component home/welcome}
{:name :anon-metrics-opt-in
:back-handler :noop
:component anon-metrics-settings/new-account-opt-in}
{:name :new-chat
:on-focus [::new-chat.events/new-chat-focus]
:transition :presentation-ios
@ -171,7 +175,13 @@
:component wallet.buy-crypto/website}
{:name :invite-people-community
:component communities.invite/invite
:insets {:bottom true}}]
:insets {:bottom true}}
{:name :anon-metrics-learn-more
:transition :presentation-ios
:component anon-metrics-settings/learn-more}
{:name :anon-metrics-view-data
:transition :presentation-ios
:component anon-metrics-settings/view-data}]
(when config/quo-preview-enabled?
[{:name :quo-preview

View File

@ -15,6 +15,7 @@
offline-messaging-settings]
[status-im.ui.screens.dapps-permissions.views :as dapps-permissions]
[status-im.ui.screens.link-previews-settings.views :as link-previews-settings]
[status-im.ui.screens.anonymous-metrics-settings.views :as anonymous-metrics-settings]
[status-im.ui.screens.privacy-and-security-settings.views :as privacy-and-security]
[status-im.ui.screens.privacy-and-security-settings.messages-from-contacts-only :as messages-from-contacts-only]
[status-im.ui.screens.sync-settings.views :as sync-settings]
@ -84,6 +85,8 @@
:component dapps-permissions/dapps-permissions}
{:name :link-previews-settings
:component link-previews-settings/link-previews-settings}
{:name :anonymous-metrics-settings
:component anonymous-metrics-settings/settings}
{:name :privacy-and-security
:component privacy-and-security/privacy-and-security}
{:name :messages-from-contacts-only

View File

@ -48,6 +48,7 @@
(def communities-enabled? (enabled? (get-config :COMMUNITIES_ENABLED "0")))
(def database-management-enabled? (enabled? (get-config :DATABASE_MANAGEMENT_ENABLED "0")))
(def debug-webview? (enabled? (get-config :DEBUG_WEBVIEW "0")))
(def metrics-enabled? (enabled? (get-config :METRICS_ENABLED "0")))
;; CONFIG VALUES
(def log-level
@ -80,6 +81,7 @@
:profile-pictures-visibility 1
:log-level log-level
:webview-allow-permission-requests? false
:anon-metrics/should-send? false
:link-previews-enabled-sites #{}
:link-preview-request-enabled true})

View File

@ -768,7 +768,7 @@
"invite-chat-rule": "سيؤدي القبول أيضًا إلى مكافأة صديقك بمكافأة إحالة بالعملة الرقمية",
"invite-chat-starter-pack": "حزمة المبتدئين",
"invite-friends": "دعوه الأصدقاء",
"invite-instruction": "كيف يعمل",
"how-it-works": "كيف يعمل",
"invite-instruction-fifth": "يمكنك اختيار استرداد مكافأة الإحالة الخاصة بك في أي وقت.",
"invite-instruction-first": "يمكنك إرسال رابط دعوة فريد إلى صديقك لتنزيل Status والانضمام إلينا",
"invite-instruction-fourth": "تتلقى مكافأة الإحالة الخاصة بك وصديقك حزمة المبتدئين",

View File

@ -645,7 +645,7 @@
"invite-chat-rule": "গ্রহণ করলে আপনার বন্ধুকে ক্রিপ্টো রেফারেল বোনাস প্রদান করা হবে।",
"invite-chat-starter-pack": "স্টার্টার প্যাক",
"invite-friends": "বন্ধুদের আমন্ত্রণ করুন",
"invite-instruction": "এটা কিভাবে কাজ করে",
"how-it-works": "এটা কিভাবে কাজ করে",
"invite-instruction-fifth": "আপনি যে কোন সময় আপনার রেফারেল বোনাস পরিশোধ করতে পারেন।",
"invite-instruction-first": "Status ডাউনলোড এবং যোগদান করতে আপনি আপনার বন্ধুকে একটি অনন্য আমন্ত্রণ লিংক পাঠান",
"invite-instruction-fourth": "আপনি আপনার রেফারেল বোনাস এবং আপনার বন্ধু স্টার্টার প্যাক পাবেন",

View File

@ -724,7 +724,7 @@
"invite-chat-rule": "Die Annahme belohnt Ihren Freund auch mit einem Krypto-Empfehlungsbonus",
"invite-chat-starter-pack": "Starter Pack",
"invite-friends": "Freunde einladen",
"invite-instruction": "Wie es funktioniert",
"how-it-works": "Wie es funktioniert",
"invite-instruction-fifth": "Du kannst deinen Empfehlungsbonus jederzeit einlösen.",
"invite-instruction-first": "Du sendest einem Freund einen eindeutigen Einladungslink zum Herunterladen und nutzen von Status",
"invite-instruction-fourth": "Du erhältst einen Empfehlungsbonus und dein Freund das Starter Pack",

View File

@ -655,7 +655,7 @@
"invite-chat-rule": "Η αποδοχή θα ανταμείψει επίσης το φίλο σας με ένα μπόνους παραπομπής κρυπτογράφησης",
"invite-chat-starter-pack": "Πακέτο εκκίνησης",
"invite-friends": "Πρόσκληση φίλων",
"invite-instruction": "Πώς λειτουργεί",
"how-it-works": "Πώς λειτουργεί",
"invite-instruction-fifth": "Μπορείτε να επιλέξετε να εξαργυρώσετε το μπόνους παραπομπής σας ανά πάσα στιγμή.",
"invite-instruction-first": "Στέλνετε έναν μοναδικό σύνδεσμο πρόσκλησης στον φίλο σας για λήψη και συμμετοχή στο Status",
"invite-instruction-fourth": "Λαμβάνετε το μπόνους παραπομπής και ο φίλος σας το Πακέτο Εκκίνησης",

View File

@ -661,7 +661,7 @@
"invited": "invited",
"invite-button": "Invite",
"invite-receive-account": "Account to receive your referral bonus",
"invite-instruction": "How it works",
"how-it-works": "How it works",
"invite-warning": "This promotion is only valid for users of an Android device, who aren't residents of US. Friend needs to confirm referral within 7 days",
"invite-instruction-first": "You send a unique invite link to your friend to download and join Status",
"invite-instruction-second": "Your friend downloads Status and creates an account (on Android)",
@ -1535,5 +1535,37 @@
"one-month": "One month",
"my-profile": "My profile",
"default-sync-period": "Sync history for",
"bip39-password-placeholder": "BIP39 password"
"bip39-password-placeholder": "BIP39 password",
"anonymous-usage-data": "Anonymous usage data",
"anonymous-usage-data-subtitle": "Share anonymous, end-to-end ecrypted data about how you use Status.",
"share-anonymous-usage-data": "Share anonymous usage data",
"what-is-shared": "What is shared",
"anon-metrics-your-interactions": "Your interactions with the app like clicks and screen views",
"anon-metrics-bg-activity": "Background activity and internal processes",
"anon-metrics-settings-and-prefs": "Settings and preferences",
"anon-metrics-data-is-validated": "Data is validated against public validation rules to ensure no sensitive data is sent.",
"anon-metrics-usage-data-sent": "Usage data is sent end-to-end encrypted over Status peer-to-peer network",
"anon-metrics-ephemeral-key": "Instead of your regular chat key, a single use key is used",
"anon-metrics-usage-not-linked-to-ip": "Usage data cannot be associated with your IP address",
"anon-metrics-removed-from-phone": "The data is removed from your phone after they are sent",
"anon-metrics-public-dashboard": "Cumulative data of all users is publicaly available View public dashboard",
"view-data": "View data",
"data-collected": "Data collected",
"data-collected-subtitle": "The table below shows the exact data that is stored and will be sent. Data is validated against public rules to ensure no sensitive data is sent. Dont trust, verify.",
"view-rules": "View rules",
"expand-all": "Expand all",
"about-sharing-data": "About sharing data",
"about-sharing-data-subtitle": "As open-source community project, Status asks you to share anonymous, non-invasive data to improve the app. This is strictly opt-in, and can be changed at any time in Settings.",
"sharing-data-desc-1": "Data is validated against public rules to ensure no sensitive data is sent. Dont trust, verify.",
"sharing-data-desc-2": "Usage data is sent end-to-end encrypted over Status peer-to-peer network",
"sharing-data-desc-3": "Instead of your regular chat key, a single use key is used",
"sharing-data-desc-4": "Usage data cannot be associated with your IP address",
"sharing-data-desc-5": "Cumulative data of all users is publicaly available",
"view-public-dashboard": "View public dashboard",
"sharing-data-desc-6": "The data is removed from your phone after they are sent",
"allow-and-send": "Allow and send",
"no-thanks": "No thanks",
"help-improve-status": "Help improve Status",
"thank-you": "Thank you",
"count-metrics-collected": "{{count}} metrics collected"
}

View File

@ -724,7 +724,7 @@
"invite-chat-rule": "Si aceptás también recompensarás a tu amigo con un bono de referencia criptográfica",
"invite-chat-starter-pack": "Paquete de Bienvenida",
"invite-friends": "Invitar a amigos",
"invite-instruction": "Cómo funciona",
"how-it-works": "Cómo funciona",
"invite-instruction-fifth": "Puede elegir canjear su bono de referencia en cualquier momento.",
"invite-instruction-first": "Envías un enlace de invitación único a tu amigo para descargar y unirse a Status",
"invite-instruction-fourth": "Vos recibís tu bono de referencia y tu amigo el Paquete de Bienvenida",

View File

@ -724,7 +724,7 @@
"invite-chat-rule": "Si aceptás también recompensarás a tu amigo con un bono de referencia criptográfica",
"invite-chat-starter-pack": "Paquete de Bienvenida",
"invite-friends": "Invitar a amigos",
"invite-instruction": "Cómo funciona",
"how-it-works": "Cómo funciona",
"invite-instruction-fifth": "Puede elegir canjear su bono de referencia en cualquier momento.",
"invite-instruction-first": "Envías un enlace de invitación único a tu amigo para descargar y unirse a Status",
"invite-instruction-fourth": "Vos recibís tu bono de referencia y tu amigo el Paquete de Bienvenida",

View File

@ -710,7 +710,7 @@
"invite-chat-rule": "Si aceptás también recompensarás a tu amigo con un bono de referencia criptográfica",
"invite-chat-starter-pack": "Paquete de Bienvenida",
"invite-friends": "Invitar a amigos",
"invite-instruction": "Cómo funciona",
"how-it-works": "Cómo funciona",
"invite-instruction-fifth": "Puede elegir canjear su bono de referencia en cualquier momento.",
"invite-instruction-first": "Envías un enlace de invitación único a tu amigo para descargar y unirse a Status",
"invite-instruction-fourth": "Vos recibís tu bono de referencia y tu amigo el Paquete de Bienvenida",

View File

@ -768,7 +768,7 @@
"invite-chat-rule": "Ang pagtanggap ay gagantimpalaan din ang iyong kaibigan ng isang crypto referral bonus",
"invite-chat-starter-pack": "Starter Pack",
"invite-friends": "Mag-imbita ng mga kaibigan",
"invite-instruction": "Paano ito gumagana",
"how-it-works": "Paano ito gumagana",
"invite-instruction-fifth": "Maaari kang pumili para i-redeem ang iyong referral bonus anumang oras.",
"invite-instruction-first": "Nagpadala ka ng isang natatanging link ng imbitasyon sa iyong kaibigan upang i-download at sumali sa Status",
"invite-instruction-fourth": "Ikaw ay makakatanggap ng referral bonus at ang iyong kaibigan ng Starter Pack",

View File

@ -710,7 +710,7 @@
"invite-chat-rule": "Accepter récompensera également votre ami avec un bonus de parrainage crypto",
"invite-chat-starter-pack": "Kit de départ",
"invite-friends": "Inviter des amis",
"invite-instruction": "Comment ça marche",
"how-it-works": "Comment ça marche",
"invite-instruction-fifth": "Vous pouvez utiliser votre bonus de parrainage quand vous le souhaité",
"invite-instruction-first": "Vous envoyez un lien d'invitation unique à votre ami pour télécharger et rejoindre Status",
"invite-instruction-fourth": "Vous recevez votre bonus de référence et votre ami le Pack Starter",

View File

@ -641,7 +641,7 @@
"invite-chat-rule": "Menerima juga akan memberi teman Anda bonus rujukan crypto",
"invite-chat-starter-pack": "Paket awal",
"invite-friends": "Mengundang teman-teman",
"invite-instruction": "Bagaimana itu bekerja",
"how-it-works": "Bagaimana itu bekerja",
"invite-instruction-fifth": "Anda dapat memilih untuk menebus bonus referensi Anda kapan saja.",
"invite-instruction-first": "Anda mengirim tautan undangan unik ke teman Anda untuk mengunduh dan bergabung dengan Status",
"invite-instruction-fourth": "Anda menerima bonus referensi dan teman Anda Paket Pemula",

View File

@ -710,7 +710,7 @@
"invite-chat-rule": "L'accettazione ricompenserà anche il tuo amico con un bonus in token",
"invite-chat-starter-pack": "Starter Pack",
"invite-friends": "Invita amici",
"invite-instruction": "Come funziona",
"how-it-works": "Come funziona",
"invite-instruction-fifth": "Puoi scegliere di riscattare il tuo bonus per la segnalazione in qualsiasi momento.",
"invite-instruction-first": "Invia un link univoco di invito al tuo amico per scaricare e iscriverti a Status",
"invite-instruction-fourth": "Ricevi il tuo bonus di segnalazione e il tuo amico lo Starter Pack",

View File

@ -713,7 +713,7 @@
"invite-chat-rule": "受け入れると友達にも紹介ボーナスがもらえます",
"invite-chat-starter-pack": "スターターパック",
"invite-friends": "友達を招待",
"invite-instruction": "友達招待の手順",
"how-it-works": "友達招待の手順",
"invite-instruction-fifth": "紹介ボーナスはいつでも受け取ることができます。",
"invite-instruction-first": "友達に招待リンクを送って、友達がStatusをダウンロードして参加します。",
"invite-instruction-fourth": "あなたは紹介ボーナスを受け取り、友達はスターターパックを受け取ります",

View File

@ -713,7 +713,7 @@
"invite-chat-rule": "수락하면 사용자의 친구는 초대 보너스를 받게 됩니다",
"invite-chat-starter-pack": "스타터 팩",
"invite-friends": "친구 초대",
"invite-instruction": "어떻게 시작하나요?",
"how-it-works": "어떻게 시작하나요?",
"invite-instruction-fifth": "보너스는 언제든지 환급 가능합니다.",
"invite-instruction-first": "친구가 스테이터스를 다운로드하고 사용할 수 있는 특별한 초대 링크를 보내세요",
"invite-instruction-fourth": "사용자는 초대 보너스를, 친구는 스타터 팩을 받게 됩니다",

View File

@ -634,7 +634,7 @@
"invite-chat-rule": "Penerimaan juga akan menawarkan ganjaran rujukan bonus kripto kepada rakan anda",
"invite-chat-starter-pack": "Pek permulaan",
"invite-friends": "Menjemput kawan-kawan",
"invite-instruction": "Bagaimana ia berfungsi",
"how-it-works": "Bagaimana ia berfungsi",
"invite-instruction-fifth": "Anda boleh memilih untuk menebus rujukan bonus anda pada bila-bila masa.",
"invite-instruction-first": "Anda menghantar pautan jemputan unik kepada rakan anda untuk memuat turun dan menyertai Status",
"invite-instruction-fourth": "Anda menerima bonus rujukan dan rakan anda Starter Pack",

View File

@ -724,7 +724,7 @@
"invite-chat-rule": "Als je accepteert, wordt je vriend ook beloond met een crypto-doorverwijsbonus",
"invite-chat-starter-pack": "Starterspakket",
"invite-friends": "Vrienden uitnodigen",
"invite-instruction": "Hoe het werkt",
"how-it-works": "Hoe het werkt",
"invite-instruction-fifth": "Je kunt er op ieder moment voor kiezen om je doorverwijsbonus in te wisselen.",
"invite-instruction-first": "Je stuurt een unieke uitnodigingslink naar je vriend om status te downloaden en te installeren",
"invite-instruction-fourth": "Je ontvangt je doorverwijsbonus en je vriend het starterspakket",

View File

@ -746,7 +746,7 @@
"invite-chat-rule": "Akceptacja wynagrodzi również znajomego premią w postaci bonusu kryptowalutowego",
"invite-chat-starter-pack": "Pakiet startowy",
"invite-friends": "Zaproś znajomych",
"invite-instruction": "Jak to działa?",
"how-it-works": "Jak to działa?",
"invite-instruction-fifth": "Bonus za polecenie możesz zrealizować w dowolnym momencie.",
"invite-instruction-first": "Wysyłasz znajomemu unikalny link z zaproszeniem do pobrania i dołączenia do platformy Status",
"invite-instruction-fourth": "Otrzymasz premię za polecenie, a twój znajomy pakiet startowy",

View File

@ -724,7 +724,7 @@
"invite-chat-rule": "Aceitar também recompensará o seu amigo com um bônus de indicação criptografado",
"invite-chat-starter-pack": "Pacote Inicial",
"invite-friends": "Convide amigos",
"invite-instruction": "Como funciona",
"how-it-works": "Como funciona",
"invite-instruction-fifth": "Você pode optar por resgatar seu bônus de indicação a qualquer momento.",
"invite-instruction-first": "Você envia um link de convite exclusivo para seu amigo fazer o download e entrar na Status",
"invite-instruction-fourth": "Você recebe seu bônus de indicação e seu amigo o Pacote inicial",

View File

@ -724,7 +724,7 @@
"invite-chat-rule": "Aceitar também recompensará o seu amigo com um bônus de indicação criptografado",
"invite-chat-starter-pack": "Pacote Inicial",
"invite-friends": "Convide amigos",
"invite-instruction": "Como funciona",
"how-it-works": "Como funciona",
"invite-instruction-fifth": "Você pode optar por resgatar seu bônus de indicação a qualquer momento.",
"invite-instruction-first": "Você envia um link de convite exclusivo para seu amigo fazer o download e entrar na Status",
"invite-instruction-fourth": "Você recebe seu bônus de indicação e seu amigo o Pacote inicial",

View File

@ -757,7 +757,7 @@
"invite-chat-rule": "Принятие также вознаградит вашего друга крипто-реферальным бонусом",
"invite-chat-starter-pack": "Стартовый пак",
"invite-friends": "Пригласить друзей",
"invite-instruction": "Как это работает",
"how-it-works": "Как это работает",
"invite-instruction-fifth": "Вы можете в любой момент использовать свой реферальный бонус.",
"invite-instruction-first": "Вы отправляете своему другу уникальную ссылку-приглашение на скачивание и присоединение к Status",
"invite-instruction-fourth": "Вы получите реферальный бонус, а ваш друг стартовый пак",

View File

@ -748,7 +748,7 @@
"invite-chat-rule": "Ang pagtanggap ay gagantimpalaan din ang iyong kaibigan ng isang crypto referral bonus",
"invite-chat-starter-pack": "Starter Pack",
"invite-friends": "Mag-imbita ng mga kaibigan",
"invite-instruction": "Paano ito gumagana",
"how-it-works": "Paano ito gumagana",
"invite-instruction-fifth": "Maaari kang pumili para i-redeem ang iyong referral bonus anumang oras.",
"invite-instruction-first": "Nagpadala ka ng isang natatanging link ng imbitasyon sa iyong kaibigan upang i-download at sumali sa Status",
"invite-instruction-fourth": "Ikaw ay makakatanggap ng referral bonus at ang iyong kaibigan ng Starter Pack",

View File

@ -707,7 +707,7 @@
"invite-chat-rule": "Kabul ettiğinizde,arkadaşınızı bir kripto tavsiye bonusu ile de ödüllendirilecek",
"invite-chat-starter-pack": "Başlangıç paketi",
"invite-friends": "Arkadaşlarınızı davet edin",
"invite-instruction": "Nasıl çalışır",
"how-it-works": "Nasıl çalışır",
"invite-instruction-fifth": "Tavsiye bonusunuzu istediğiniz zaman kullanmayı seçebilirsiniz.",
"invite-instruction-first": "Statusu indirmek ve katılmak için arkadaşınıza benzersiz bir davet bağlantısı gönderirsiniz",
"invite-instruction-fourth": "Tavsiye bonusu ve arkadaşınıza Başlangıç Paketini alırsınız",

View File

@ -633,7 +633,7 @@
"invite-chat-rule": "Việc chấp nhận cũng sẽ thưởng cho bạn bè của bạn một phần thưởng giới thiệu tiền điện tử",
"invite-chat-starter-pack": "Gói khởi động",
"invite-friends": "Mời bạn bè",
"invite-instruction": "Làm thế nào nó hoạt động",
"how-it-works": "Làm thế nào nó hoạt động",
"invite-instruction-fifth": "Bạn có thể chọn đổi phần thưởng giới thiệu của mình bất cứ lúc nào.",
"invite-instruction-first": "Bạn gửi một liên kết mời duy nhất đến bạn bè của mình để tải xuống và tham gia Trạng thái",
"invite-instruction-fourth": "Bạn nhận được phần thưởng giới thiệu của mình và bạn bè của bạn Gói Khởi đầu",

View File

@ -713,7 +713,7 @@
"invite-chat-rule": "接受将让您的朋友也获得推荐奖金",
"invite-chat-starter-pack": "入门包",
"invite-friends": "邀请朋友",
"invite-instruction": "如何运作",
"how-it-works": "如何运作",
"invite-instruction-fifth": "您随时都可以兑换推荐奖金。",
"invite-instruction-first": "您向您的朋友发送一个专属的邀请链接以下载并加入Status",
"invite-instruction-fourth": "您将获得推荐奖金,您的朋友将获得入门包",

View File

@ -713,7 +713,7 @@
"invite-chat-rule": "接受將讓您的朋友也獲得推薦獎勵",
"invite-chat-starter-pack": "入門包",
"invite-friends": "邀請朋友",
"invite-instruction": "如何運作",
"how-it-works": "如何運作",
"invite-instruction-fifth": "您隨時都可以來兌換推薦獎勵。",
"invite-instruction-first": "向您的朋友發送一個專屬的邀請用來下載並加入Status",
"invite-instruction-fourth": "您的朋友取得入門包時,您可以獲得推薦獎勵",