Add universal links for android
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
parent
9df15ffc78
commit
b17d9bab37
|
@ -20,3 +20,4 @@ GROUP_CHATS_ENABLED=0
|
|||
USE_SYM_KEY=0
|
||||
MAINNET_WARNING_ENABLED=1
|
||||
SPAM_BUTTON_DETECTION_ENABLED=1
|
||||
UNIVERSAL_LINKS_ENABLED=0
|
||||
|
|
|
@ -54,6 +54,14 @@
|
|||
<data android:scheme="app-settings"
|
||||
android:host="notification" />
|
||||
</intent-filter>
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="http" android:host="get.status.im" />
|
||||
<data android:scheme="https" android:host="get.status.im" />
|
||||
<data android:scheme="app" android:host="get.status.im" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service
|
||||
android:name=".module.StatusService"
|
||||
|
|
|
@ -96,6 +96,7 @@ public class MainActivity extends ReactActivity
|
|||
|
||||
@Override
|
||||
public void onNewIntent(final Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
if (intent.getDataString() != null && intent.getData().getScheme().startsWith("app-settings")) {
|
||||
startActivity(createNotificationSettingsIntent());
|
||||
}
|
||||
|
|
|
@ -374,15 +374,18 @@
|
|||
:confirm-button-text (i18n/label :t/clear)
|
||||
:on-accept #(re-frame/dispatch [:clear-history])}}))
|
||||
|
||||
(defn create-new-public-chat [topic {:keys [db now] :as cofx}]
|
||||
(handlers-macro/merge-fx cofx
|
||||
(models/add-public-chat topic)
|
||||
(navigation/navigate-to-clean :home)
|
||||
(navigate-to-chat topic {})
|
||||
(public-chat/join-public-chat topic)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:create-new-public-chat
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db now] :as cofx} [topic]]
|
||||
(handlers-macro/merge-fx cofx
|
||||
(models/add-public-chat topic)
|
||||
(navigation/navigate-to-clean :home)
|
||||
(navigate-to-chat topic {})
|
||||
(public-chat/join-public-chat topic))))
|
||||
(fn [cofx [topic]]
|
||||
(create-new-public-chat topic cofx)))
|
||||
|
||||
(defn- group-name-from-contacts [selected-contacts all-contacts username]
|
||||
(->> selected-contacts
|
||||
|
@ -407,13 +410,16 @@
|
|||
(navigate-to-chat random-id {})
|
||||
(transport.message/send (group-chat/GroupAdminUpdate. chat-name selected-contacts) random-id)))))
|
||||
|
||||
(defn show-profile [identity {:keys [db] :as cofx}]
|
||||
(handlers-macro/merge-fx cofx
|
||||
{:db (assoc db :contacts/identity identity)}
|
||||
(navigation/navigate-forget :profile)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:show-profile
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db] :as cofx} [identity]]
|
||||
(handlers-macro/merge-fx cofx
|
||||
{:db (assoc db :contacts/identity identity)}
|
||||
(navigation/navigate-forget :profile))))
|
||||
(fn [cofx [identity]]
|
||||
(show-profile identity cofx)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:resend-message
|
||||
|
|
|
@ -150,6 +150,10 @@
|
|||
|
||||
(spec/def ::device-UUID (spec/nilable string?))
|
||||
|
||||
;;;;UNIVERSAL LINKS
|
||||
|
||||
(spec/def :universal-links/url (spec/nilable string?))
|
||||
|
||||
(spec/def ::db (allowed-keys
|
||||
:opt
|
||||
[:contacts/contacts
|
||||
|
@ -187,6 +191,7 @@
|
|||
:inbox/last-received
|
||||
:inbox/current-id
|
||||
:inbox/fetching?
|
||||
:universal-links/url
|
||||
:browser/browsers
|
||||
:browser/options
|
||||
:new/open-dapp
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
status-im.ui.screens.group.chat-settings.events
|
||||
status-im.ui.screens.group.events
|
||||
[status-im.ui.screens.navigation :as navigation]
|
||||
[status-im.utils.universal-links.core :as universal-links]
|
||||
|
||||
status-im.utils.universal-links.events
|
||||
status-im.ui.screens.add-new.new-chat.navigation
|
||||
status-im.ui.screens.network-settings.events
|
||||
status-im.ui.screens.profile.events
|
||||
|
@ -315,7 +318,7 @@
|
|||
|
||||
(handlers/register-handler-fx
|
||||
:initialize-account
|
||||
(fn [_ [_ address events-after]]
|
||||
(fn [cofx [_ address events-after]]
|
||||
{:dispatch-n (cond-> [[:initialize-account-db address]
|
||||
[:initialize-protocol address]
|
||||
[:fetch-web3-node-version]
|
||||
|
@ -329,7 +332,8 @@
|
|||
[:update-transactions]
|
||||
[:get-fcm-token]
|
||||
[:update-sign-in-time]
|
||||
[:show-mainnet-is-default-alert]]
|
||||
[:show-mainnet-is-default-alert]
|
||||
(universal-links/stored-url-event cofx)]
|
||||
(seq events-after) (into events-after))}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
(:require-macros [status-im.utils.views :refer [defview letsubs] :as views])
|
||||
(:require [re-frame.core :refer [dispatch]]
|
||||
[status-im.utils.platform :refer [android?]]
|
||||
[status-im.utils.universal-links.core :as utils.universal-links]
|
||||
[status-im.ui.components.react :refer [view modal create-main-screen-view] :as react]
|
||||
[status-im.ui.components.styles :as common-styles]
|
||||
[status-im.ui.screens.main-tabs.views :refer [main-tabs]]
|
||||
|
@ -134,7 +135,9 @@
|
|||
(defview main []
|
||||
(letsubs [signed-up? [:signed-up?]
|
||||
view-id [:get :view-id]]
|
||||
{:component-will-update (fn [] (react/dismiss-keyboard!))}
|
||||
{:component-did-mount utils.universal-links/initialize
|
||||
:component-will-unmount utils.universal-links/finalize
|
||||
:component-will-update (fn [] (react/dismiss-keyboard!))}
|
||||
(when view-id
|
||||
(let [component (get-main-component view-id)
|
||||
main-screen-view (create-main-screen-view view-id)]
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
(def stub-status-go? (enabled? (get-config :STUB_STATUS_GO 0)))
|
||||
(def offline-inbox-enabled? (enabled? (get-config :OFFLINE_INBOX_ENABLED "1")))
|
||||
(def bootnodes-settings-enabled? (enabled? (get-config :BOOTNODES_SETTINGS_ENABLED "1")))
|
||||
(def universal-links-enabled? (enabled? (get-config :UNIVERSAL_LINK_ENABLED "1")))
|
||||
(def log-level
|
||||
(-> (get-config :LOG_LEVEL "error")
|
||||
string/lower-case
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
(ns status-im.utils.universal-links.core
|
||||
(:require
|
||||
[taoensso.timbre :as log]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.chat.events :as chat.events]
|
||||
[status-im.models.account :as models.account]
|
||||
[status-im.ui.components.react :as react]))
|
||||
|
||||
(def public-chat-regex #".*/chat/public/(.*)$")
|
||||
(def profile-regex #".*/user/(.*)$")
|
||||
|
||||
(defn handle-public-chat [public-chat cofx]
|
||||
(log/info "universal-links: handling public chat " public-chat)
|
||||
(chat.events/create-new-public-chat public-chat cofx))
|
||||
|
||||
(defn handle-view-profile [profile-id cofx]
|
||||
(log/info "universal links: handling view profile" profile-id)
|
||||
(chat.events/show-profile profile-id cofx))
|
||||
|
||||
(defn handle-not-found [full-url]
|
||||
(log/info "universal links: no handler for " full-url))
|
||||
|
||||
(defn match-url [url regex]
|
||||
(some->> url
|
||||
(re-matches regex)
|
||||
peek))
|
||||
|
||||
(defn stored-url-event
|
||||
"Return an event description for processing a url if in the database"
|
||||
[{:keys [db]}]
|
||||
(when-let [url (:universal-links/url db)]
|
||||
[:handle-universal-link url]))
|
||||
|
||||
(defn dispatch-url
|
||||
"Dispatch url so we can get access to re-frame/db"
|
||||
[url]
|
||||
(if-not (nil? url)
|
||||
(re-frame/dispatch [:handle-universal-link url])
|
||||
(log/debug "universal links: no url")))
|
||||
|
||||
(defn store-url-for-later
|
||||
"Store the url in the db to be processed on login"
|
||||
[url {:keys [db]}]
|
||||
(assoc-in {:db db} [:db :universal-links/url] url))
|
||||
|
||||
(defn clear-url
|
||||
"Remove a url from the db"
|
||||
[{:keys [db]}]
|
||||
(update {:db db} :db dissoc :universal-links/url))
|
||||
|
||||
(defn route-url
|
||||
"Match a url against a list of routes and handle accordingly"
|
||||
[url cofx]
|
||||
(cond
|
||||
(match-url url public-chat-regex)
|
||||
(handle-public-chat (match-url url public-chat-regex) cofx)
|
||||
|
||||
(match-url url profile-regex)
|
||||
(handle-view-profile (match-url url profile-regex) cofx)
|
||||
|
||||
:else (handle-not-found url)))
|
||||
|
||||
(defn handle-url
|
||||
"Store url in the database if the user is not logged in, to be processed
|
||||
on login, otherwise just handle it"
|
||||
[url cofx]
|
||||
(if (models.account/logged-in? cofx)
|
||||
(do
|
||||
(clear-url cofx)
|
||||
(route-url url cofx))
|
||||
(store-url-for-later url cofx)))
|
||||
|
||||
(defn unwrap-js-url [e]
|
||||
(-> e
|
||||
(js->clj :keywordize-keys true)
|
||||
:url))
|
||||
|
||||
(def url-event-listener
|
||||
(comp dispatch-url unwrap-js-url))
|
||||
|
||||
(defn initialize
|
||||
"Add an event listener for handling background->foreground transition
|
||||
and handles incoming url if the app has been started by clicking on a link"
|
||||
[]
|
||||
(when config/universal-links-enabled?
|
||||
(log/debug "universal-links: initializing")
|
||||
(.. react/linking
|
||||
(getInitialURL)
|
||||
(then dispatch-url))
|
||||
(.. react/linking
|
||||
(addEventListener "url" url-event-listener))))
|
||||
|
||||
(defn finalize
|
||||
"Remove event listener for url"
|
||||
[]
|
||||
(when config/universal-links-enabled?
|
||||
(log/debug "universal-links: finalizing")
|
||||
(.. react/linking
|
||||
(removeEventListener "url" url-event-listener))))
|
|
@ -0,0 +1,14 @@
|
|||
(ns status-im.utils.universal-links.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.handlers-macro :as handlers-macro]
|
||||
[status-im.utils.universal-links.core :as universal-links]))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:handle-universal-link
|
||||
(fn [cofx [_ url]]
|
||||
(log/debug "universal links: event received for " url)
|
||||
(when config/universal-links-enabled?
|
||||
(universal-links/handle-url url cofx))))
|
|
@ -42,6 +42,7 @@
|
|||
[status-im.test.utils.mixpanel]
|
||||
[status-im.test.utils.prices]
|
||||
[status-im.test.utils.keychain.core]
|
||||
[status-im.test.utils.universal-links.core]
|
||||
[status-im.test.ui.screens.accounts.login.events]))
|
||||
|
||||
(enable-console-print!)
|
||||
|
@ -95,4 +96,5 @@
|
|||
'status-im.test.utils.mixpanel
|
||||
'status-im.test.utils.prices
|
||||
'status-im.test.utils.keychain.core
|
||||
'status-im.test.utils.universal-links.core
|
||||
'status-im.test.ui.screens.accounts.login.events)
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
(ns status-im.test.utils.universal-links.core
|
||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.utils.universal-links.core :as links]))
|
||||
|
||||
(deftest handle-url-test
|
||||
(testing "the user is not logged in"
|
||||
(testing "it stores the url for later processing"
|
||||
(is (= {:db {:universal-links/url "some-url"}}
|
||||
(links/handle-url "some-url" {:db {}})))))
|
||||
(testing "the user is logged in"
|
||||
(let [db {:account/account {:public-key "pk"}
|
||||
:universal-links/url "some-url"}]
|
||||
(testing "it clears the url"
|
||||
(is (nil? (get-in (links/handle-url "some-url"
|
||||
{:db db})
|
||||
[:db :universal-links/url]))))
|
||||
(testing "a public chat link"
|
||||
(testing "it joins the chat"
|
||||
(is (get-in (links/handle-url "app://get.status.im/chat/public/status"
|
||||
{:db db})
|
||||
[:db :chats "status"]))))
|
||||
(testing "a user profile link"
|
||||
(testing "it loads the profile"
|
||||
(let [actual (links/handle-url "app://get.status.im/user/profile-id"
|
||||
{:db db})]
|
||||
(is (= "profile-id" (get-in actual [:db :contacts/identity])))
|
||||
(is (= :profile (get-in actual [:db :view-id]))))))
|
||||
(testing "a not found url"
|
||||
(testing "it does nothing"
|
||||
(is (nil? (links/handle-url "app://get.status.im/not-existing"
|
||||
{:db db}))))))))
|
||||
|
||||
(deftest url-event-listener
|
||||
(testing "the url is not nil"
|
||||
(testing "it dispatches the url"
|
||||
(let [actual (atom nil)]
|
||||
(with-redefs [re-frame/dispatch #(reset! actual %)]
|
||||
(links/url-event-listener #js {:url "some-url"})
|
||||
(is (= [:handle-universal-link "some-url"] @actual))))))
|
||||
(testing "the url is nil"
|
||||
(testing "it does not dispatches the url"
|
||||
(let [actual (atom nil)]
|
||||
(with-redefs [re-frame/dispatch #(reset! actual %)]
|
||||
(links/url-event-listener #js {})
|
||||
(is (= nil @actual)))))))
|
||||
|
||||
(deftest stored-url-event
|
||||
(testing "the url is in the database"
|
||||
(testing "it returns the event"
|
||||
(= [:handle-universal-link "some-url"]
|
||||
(links/stored-url-event {:db {:universal-links/url "some-url"}}))))
|
||||
(testing "the url is not in the database"
|
||||
(testing "it returns nil"
|
||||
(= nil
|
||||
(links/stored-url-event {:db {}})))))
|
||||
|
Loading…
Reference in New Issue