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 APN_TOPIC=im.status.ethereum.pr
COMMUNITIES_ENABLED=1 COMMUNITIES_ENABLED=1
DATABASE_MANAGEMENT_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 VERIFY_TRANSACTION_CHAIN_ID=3
COMMUNITIES_ENABLED=1 COMMUNITIES_ENABLED=1
COMMUNITIES_MANAGEMENT_ENABLED=1 COMMUNITIES_MANAGEMENT_ENABLED=1
METRICS_ENABLED=0

View File

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

View File

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

View File

@ -18,3 +18,4 @@ PARTITIONED_TOPIC=0
ENABLE_ROOT_ALERT=1 ENABLE_ROOT_ALERT=1
MAX_IMAGES_BATCH=1 MAX_IMAGES_BATCH=1
ENABLE_REFERRAL_INVITE=0 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 (ns status-im.anon-metrics.core
(:require [status-im.ethereum.json-rpc :as json-rpc] (:require [taoensso.timbre :as log]
[taoensso.timbre :as log]
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
[re-frame.interceptor :refer [->interceptor]] [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.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.platform :as platform]
[status-im.utils.build :as build] [status-im.utils.build :as build]
[status-im.utils.fx :as fx] [status-im.utils.fx :as fx]
[status-im.utils.config :as config]
[status-im.anon-metrics.transformers :as txf])) [status-im.anon-metrics.transformers :as txf]))
(defonce events-foyer (atom [])) (defonce events-foyer (atom []))
@ -26,7 +29,7 @@
:on-error (fn [err] :on-error (fn [err]
(log/error {:error err (log/error {:error err
:events outstanding-events}) :events outstanding-events})
(log/warn "All outstanding events will be rejected"))})))) (log/warn "The logged events will be rejected"))}))))
(re-frame/reg-fx (re-frame/reg-fx
::transfer-data ::transfer-data
@ -42,11 +45,10 @@
(async-periodic-exec onboard-events 4000 5000))) (async-periodic-exec onboard-events 4000 5000)))
(do (do
(log/info "[anon-metrics] Stop collection service") (log/info "[anon-metrics] Stop collection service")
(when @periodic-tasks-chan
(async-periodic-stop! @periodic-tasks-chan) (async-periodic-stop! @periodic-tasks-chan)
(reset! periodic-tasks-chan nil) (onboard-events) ; final onboard, will save and clear any pending events
(reset! periodic-tasks-chan nil))))))
;; final onboard, will save and clear any pending events
(onboard-events)))))
(fx/defn start-transferring (fx/defn start-transferring
[_] [_]
@ -57,14 +59,25 @@
{::transfer-data false}) {::transfer-data false})
(defn transform-and-log [context] (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! (swap!
events-foyer events-foyer
conj conj
{:event (-> context :coeffects :event first) {:event (-> context :coeffects :event first)
:value transformed-payload :value transformed-payload
:app_version build/version :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] (defn catch-events-before [context]
(transform-and-log context) (transform-and-log context)
@ -75,8 +88,6 @@
:id :catch-events :id :catch-events
:before catch-events-before)) :before catch-events-before))
(re-frame/reg-fx ::transform-and-log transform-and-log)
(fx/defn hoax-capture-event (fx/defn hoax-capture-event
"Due to usage of fx/defn with fx/merge, it might not be able to "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, intercept some events (like navigate-to-cofx). In cases like that,
@ -86,6 +97,79 @@
;; re-shape event to look like a context object ;; re-shape event to look like a context object
{::transform-and-log {:coeffects {:event og-event}}}) {::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 (comment
;; read the database ;; read the database
(def events-in-db (atom nil)) (def events-in-db (atom nil))
@ -95,3 +179,4 @@
(json-rpc/call {:method "appmetrics_getAppMetrics" (json-rpc/call {:method "appmetrics_getAppMetrics"
:params [1000 0] ; limit, offset :params [1000 0] ; limit, offset
:on-success #(reset! events-in-db %)})) :on-success #(reset! events-in-db %)}))

View File

@ -145,3 +145,6 @@
(def ^:const three-days (* one-day 3)) (def ^:const three-days (* one-day 3))
(def ^:const one-week (* one-day 7)) (def ^:const one-week (* one-day 7))
(def ^:const one-month (* one-day 31)) (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] (:require [clojure.string :as string]
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
[status-im.multiaccounts.login.core :as multiaccounts.login] [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.native-module.core :as status]
[status-im.network.net-info :as network] [status-im.network.net-info :as network]
[status-im.db :refer [app-db]] [status-im.db :refer [app-db]]
@ -53,7 +54,8 @@
(assoc :multiaccounts/loading false)) (assoc :multiaccounts/loading false))
;; NOTE: Try to dispatch later navigation because of that https://github.com/react-navigation/react-navigation/issues/6879 ;; 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?}] :dispatch-later [{:dispatch [::initialize-view {:logout? logout?}]
:ms 100}]}))) :ms 100}]
:dispatch [::anon-metrics/fetch-opt-in-screen-displayed?]})))
(fx/defn start-app (fx/defn start-app
{:events [:init/app-started]} {:events [:init/app-started]}

View File

@ -3,6 +3,7 @@
[status-im.ethereum.stateofus :as stateofus] [status-im.ethereum.stateofus :as stateofus]
[status-im.multiaccounts.update.core :as multiaccounts.update] [status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.bottom-sheet.core :as bottom-sheet] [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.native-module.core :as native-module]
[status-im.ethereum.json-rpc :as json-rpc] [status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx] [status-im.utils.fx :as fx]
@ -138,6 +139,17 @@
:default-sync-period value :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 (fx/defn switch-preview-privacy-mode-flag
[{:keys [db]}] [{:keys [db]}]
(let [private? (get-in db [:multiaccount :preview-privacy?])] (let [private? (get-in db [:multiaccount :preview-privacy?])]

View File

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

View File

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

View File

@ -42,7 +42,8 @@
:theme-dark (js/require "../resources/images/ui/theme-dark.png") :theme-dark (js/require "../resources/images/ui/theme-dark.png")
:theme-light (js/require "../resources/images/ui/theme-light.png") :theme-light (js/require "../resources/images/ui/theme-light.png")
:theme-system (js/require "../resources/images/ui/theme-system.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] (defn get-theme-image [k]
(get ui (when (colors/dark?) (keyword (str (name k) "-dark"))) (get ui 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 :activity.center/notifications)
(reg-root-key-sub :activity.center/notifications-count :activity.center/notifications-count) (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 (re-frame/reg-sub
:communities :communities
:<- [:raw-communities] :<- [:raw-communities]

View File

@ -5,31 +5,32 @@
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.ui.components.icons.icons :as icons])) [status-im.ui.components.icons.icons :as icons]))
(defn section (defn drop-down-icon [opened?]
"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
[react/view {:flex-direction :row :align-items :center} [react/view {:flex-direction :row :align-items :center}
(when (pos? cnt) [icons/icon (if opened? :main-icons/dropdown-up :main-icons/dropdown)
[react/text {:style {:color colors/gray}} cnt])
[icons/icon (if @opened? :main-icons/dropdown-up :main-icons/dropdown)
{:container-style {:align-items :center {:container-style {:align-items :center
:margin-left 8 :margin-left 8
:justify-content :center} :justify-content :center}
:resize-mode :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? (when @opened?
content)]))) 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)}
[rn/view {:style (styles/invite-instructions-title)} [rn/view {:style (styles/invite-instructions-title)}
[quo/text {:color :secondary} [quo/text {:color :secondary}
(i18n/label :t/invite-instruction)]] (i18n/label :t/how-it-works)]]
[rn/view {:style (styles/invite-warning)} [rn/view {:style (styles/invite-warning)}
[quo/text (i18n/label :t/invite-warning)]] [quo/text (i18n/label :t/invite-warning)]]
[rn/view {:style (styles/invite-instructions-content)} [rn/view {:style (styles/invite-instructions-content)}

View File

@ -7,6 +7,10 @@
:image-preview {:type :black}} :image-preview {:type :black}}
(when platform/ios? (when platform/ios?
{:new-chat {:type :black} {: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}}))) :new-public-chat {:type :black}})))
;; TODO: Integrate into navigation ;; 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 [accordion/section {:title name
:icon [chat-icon.screen/contact-icon-contacts-tab :icon [chat-icon.screen/contact-icon-contacts-tab
(multiaccounts/displayed-photo multiaccount)] (multiaccounts/displayed-photo multiaccount)]
:count 0
:content [accordion-content]}] :content [accordion-content]}]
[react/view {:flex 1 [react/view {:flex 1
:flex-direction :column :flex-direction :column

View File

@ -5,6 +5,7 @@
[status-im.ui.components.colors :as colors] [status-im.ui.components.colors :as colors]
[status-im.ui.components.common.common :as components.common] [status-im.ui.components.common.common :as components.common]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.utils.config :as config]
[status-im.multiaccounts.biometric.core :as biometric] [status-im.multiaccounts.biometric.core :as biometric]
[status-im.ui.components.topbar :as topbar] [status-im.ui.components.topbar :as topbar]
[status-im.utils.platform :as platform]) [status-im.utils.platform :as platform])
@ -79,6 +80,12 @@
:t/anyone)) :t/anyone))
:on-press #(re-frame/dispatch [:navigate-to :messages-from-contacts-only]) :on-press #(re-frame/dispatch [:navigate-to :messages-from-contacts-only])
:accessibility-label :accept-new-chats-from}] :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? (when platform/android?
[quo/list-item {:size :small [quo/list-item {:size :small
:title (i18n/label :t/webview-camera-permission-requests) :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.stickers.views :as stickers]
[status-im.ui.screens.home.views :as home] [status-im.ui.screens.home.views :as home]
[status-im.ui.screens.add-new.new-chat.views :as new-chat] [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.add-new.core :as new-chat.events]
[status-im.ui.screens.routing.intro-login-stack :as intro-login-stack] [status-im.ui.screens.routing.intro-login-stack :as intro-login-stack]
[status-im.ui.screens.routing.chat-stack :as chat-stack] [status-im.ui.screens.routing.chat-stack :as chat-stack]
@ -80,6 +81,9 @@
{:name :welcome {:name :welcome
:back-handler :noop :back-handler :noop
:component home/welcome} :component home/welcome}
{:name :anon-metrics-opt-in
:back-handler :noop
:component anon-metrics-settings/new-account-opt-in}
{:name :new-chat {:name :new-chat
:on-focus [::new-chat.events/new-chat-focus] :on-focus [::new-chat.events/new-chat-focus]
:transition :presentation-ios :transition :presentation-ios
@ -171,7 +175,13 @@
:component wallet.buy-crypto/website} :component wallet.buy-crypto/website}
{:name :invite-people-community {:name :invite-people-community
:component communities.invite/invite :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? (when config/quo-preview-enabled?
[{:name :quo-preview [{:name :quo-preview

View File

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

View File

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

View File

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

View File

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

View File

@ -724,7 +724,7 @@
"invite-chat-rule": "Die Annahme belohnt Ihren Freund auch mit einem Krypto-Empfehlungsbonus", "invite-chat-rule": "Die Annahme belohnt Ihren Freund auch mit einem Krypto-Empfehlungsbonus",
"invite-chat-starter-pack": "Starter Pack", "invite-chat-starter-pack": "Starter Pack",
"invite-friends": "Freunde einladen", "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-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-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", "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-rule": "Η αποδοχή θα ανταμείψει επίσης το φίλο σας με ένα μπόνους παραπομπής κρυπτογράφησης",
"invite-chat-starter-pack": "Πακέτο εκκίνησης", "invite-chat-starter-pack": "Πακέτο εκκίνησης",
"invite-friends": "Πρόσκληση φίλων", "invite-friends": "Πρόσκληση φίλων",
"invite-instruction": "Πώς λειτουργεί", "how-it-works": "Πώς λειτουργεί",
"invite-instruction-fifth": "Μπορείτε να επιλέξετε να εξαργυρώσετε το μπόνους παραπομπής σας ανά πάσα στιγμή.", "invite-instruction-fifth": "Μπορείτε να επιλέξετε να εξαργυρώσετε το μπόνους παραπομπής σας ανά πάσα στιγμή.",
"invite-instruction-first": "Στέλνετε έναν μοναδικό σύνδεσμο πρόσκλησης στον φίλο σας για λήψη και συμμετοχή στο Status", "invite-instruction-first": "Στέλνετε έναν μοναδικό σύνδεσμο πρόσκλησης στον φίλο σας για λήψη και συμμετοχή στο Status",
"invite-instruction-fourth": "Λαμβάνετε το μπόνους παραπομπής και ο φίλος σας το Πακέτο Εκκίνησης", "invite-instruction-fourth": "Λαμβάνετε το μπόνους παραπομπής και ο φίλος σας το Πακέτο Εκκίνησης",

View File

@ -661,7 +661,7 @@
"invited": "invited", "invited": "invited",
"invite-button": "Invite", "invite-button": "Invite",
"invite-receive-account": "Account to receive your referral bonus", "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-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-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)", "invite-instruction-second": "Your friend downloads Status and creates an account (on Android)",
@ -1535,5 +1535,37 @@
"one-month": "One month", "one-month": "One month",
"my-profile": "My profile", "my-profile": "My profile",
"default-sync-period": "Sync history for", "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-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-chat-starter-pack": "Paquete de Bienvenida",
"invite-friends": "Invitar a amigos", "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-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-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", "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-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-chat-starter-pack": "Paquete de Bienvenida",
"invite-friends": "Invitar a amigos", "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-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-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", "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-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-chat-starter-pack": "Paquete de Bienvenida",
"invite-friends": "Invitar a amigos", "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-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-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", "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-rule": "Ang pagtanggap ay gagantimpalaan din ang iyong kaibigan ng isang crypto referral bonus",
"invite-chat-starter-pack": "Starter Pack", "invite-chat-starter-pack": "Starter Pack",
"invite-friends": "Mag-imbita ng mga kaibigan", "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-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-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", "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-rule": "Accepter récompensera également votre ami avec un bonus de parrainage crypto",
"invite-chat-starter-pack": "Kit de départ", "invite-chat-starter-pack": "Kit de départ",
"invite-friends": "Inviter des amis", "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-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-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", "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-rule": "Menerima juga akan memberi teman Anda bonus rujukan crypto",
"invite-chat-starter-pack": "Paket awal", "invite-chat-starter-pack": "Paket awal",
"invite-friends": "Mengundang teman-teman", "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-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-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", "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-rule": "L'accettazione ricompenserà anche il tuo amico con un bonus in token",
"invite-chat-starter-pack": "Starter Pack", "invite-chat-starter-pack": "Starter Pack",
"invite-friends": "Invita amici", "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-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-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", "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-rule": "受け入れると友達にも紹介ボーナスがもらえます",
"invite-chat-starter-pack": "スターターパック", "invite-chat-starter-pack": "スターターパック",
"invite-friends": "友達を招待", "invite-friends": "友達を招待",
"invite-instruction": "友達招待の手順", "how-it-works": "友達招待の手順",
"invite-instruction-fifth": "紹介ボーナスはいつでも受け取ることができます。", "invite-instruction-fifth": "紹介ボーナスはいつでも受け取ることができます。",
"invite-instruction-first": "友達に招待リンクを送って、友達がStatusをダウンロードして参加します。", "invite-instruction-first": "友達に招待リンクを送って、友達がStatusをダウンロードして参加します。",
"invite-instruction-fourth": "あなたは紹介ボーナスを受け取り、友達はスターターパックを受け取ります", "invite-instruction-fourth": "あなたは紹介ボーナスを受け取り、友達はスターターパックを受け取ります",

View File

@ -713,7 +713,7 @@
"invite-chat-rule": "수락하면 사용자의 친구는 초대 보너스를 받게 됩니다", "invite-chat-rule": "수락하면 사용자의 친구는 초대 보너스를 받게 됩니다",
"invite-chat-starter-pack": "스타터 팩", "invite-chat-starter-pack": "스타터 팩",
"invite-friends": "친구 초대", "invite-friends": "친구 초대",
"invite-instruction": "어떻게 시작하나요?", "how-it-works": "어떻게 시작하나요?",
"invite-instruction-fifth": "보너스는 언제든지 환급 가능합니다.", "invite-instruction-fifth": "보너스는 언제든지 환급 가능합니다.",
"invite-instruction-first": "친구가 스테이터스를 다운로드하고 사용할 수 있는 특별한 초대 링크를 보내세요", "invite-instruction-first": "친구가 스테이터스를 다운로드하고 사용할 수 있는 특별한 초대 링크를 보내세요",
"invite-instruction-fourth": "사용자는 초대 보너스를, 친구는 스타터 팩을 받게 됩니다", "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-rule": "Penerimaan juga akan menawarkan ganjaran rujukan bonus kripto kepada rakan anda",
"invite-chat-starter-pack": "Pek permulaan", "invite-chat-starter-pack": "Pek permulaan",
"invite-friends": "Menjemput kawan-kawan", "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-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-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", "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-rule": "Als je accepteert, wordt je vriend ook beloond met een crypto-doorverwijsbonus",
"invite-chat-starter-pack": "Starterspakket", "invite-chat-starter-pack": "Starterspakket",
"invite-friends": "Vrienden uitnodigen", "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-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-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", "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-rule": "Akceptacja wynagrodzi również znajomego premią w postaci bonusu kryptowalutowego",
"invite-chat-starter-pack": "Pakiet startowy", "invite-chat-starter-pack": "Pakiet startowy",
"invite-friends": "Zaproś znajomych", "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-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-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", "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-rule": "Aceitar também recompensará o seu amigo com um bônus de indicação criptografado",
"invite-chat-starter-pack": "Pacote Inicial", "invite-chat-starter-pack": "Pacote Inicial",
"invite-friends": "Convide amigos", "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-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-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", "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-rule": "Aceitar também recompensará o seu amigo com um bônus de indicação criptografado",
"invite-chat-starter-pack": "Pacote Inicial", "invite-chat-starter-pack": "Pacote Inicial",
"invite-friends": "Convide amigos", "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-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-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", "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-rule": "Принятие также вознаградит вашего друга крипто-реферальным бонусом",
"invite-chat-starter-pack": "Стартовый пак", "invite-chat-starter-pack": "Стартовый пак",
"invite-friends": "Пригласить друзей", "invite-friends": "Пригласить друзей",
"invite-instruction": "Как это работает", "how-it-works": "Как это работает",
"invite-instruction-fifth": "Вы можете в любой момент использовать свой реферальный бонус.", "invite-instruction-fifth": "Вы можете в любой момент использовать свой реферальный бонус.",
"invite-instruction-first": "Вы отправляете своему другу уникальную ссылку-приглашение на скачивание и присоединение к Status", "invite-instruction-first": "Вы отправляете своему другу уникальную ссылку-приглашение на скачивание и присоединение к Status",
"invite-instruction-fourth": "Вы получите реферальный бонус, а ваш друг стартовый пак", "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-rule": "Ang pagtanggap ay gagantimpalaan din ang iyong kaibigan ng isang crypto referral bonus",
"invite-chat-starter-pack": "Starter Pack", "invite-chat-starter-pack": "Starter Pack",
"invite-friends": "Mag-imbita ng mga kaibigan", "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-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-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", "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-rule": "Kabul ettiğinizde,arkadaşınızı bir kripto tavsiye bonusu ile de ödüllendirilecek",
"invite-chat-starter-pack": "Başlangıç paketi", "invite-chat-starter-pack": "Başlangıç paketi",
"invite-friends": "Arkadaşlarınızı davet edin", "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-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-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", "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-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-chat-starter-pack": "Gói khởi động",
"invite-friends": "Mời bạn bè", "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-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-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", "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-rule": "接受将让您的朋友也获得推荐奖金",
"invite-chat-starter-pack": "入门包", "invite-chat-starter-pack": "入门包",
"invite-friends": "邀请朋友", "invite-friends": "邀请朋友",
"invite-instruction": "如何运作", "how-it-works": "如何运作",
"invite-instruction-fifth": "您随时都可以兑换推荐奖金。", "invite-instruction-fifth": "您随时都可以兑换推荐奖金。",
"invite-instruction-first": "您向您的朋友发送一个专属的邀请链接以下载并加入Status", "invite-instruction-first": "您向您的朋友发送一个专属的邀请链接以下载并加入Status",
"invite-instruction-fourth": "您将获得推荐奖金,您的朋友将获得入门包", "invite-instruction-fourth": "您将获得推荐奖金,您的朋友将获得入门包",

View File

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