[#5038] desktop deep links
Add support for status-im://chat/public/status type of links Signed-off-by: Dmitry Novotochinov <dmitry.novot@gmail.com>
This commit is contained in:
parent
299c44afef
commit
248e60e1d3
|
@ -58,6 +58,7 @@
|
|||
"rn-snoopy/stream/buffer",
|
||||
"react-native/Libraries/vendor/emitter/EventEmitter",
|
||||
"react-native-fetch-polyfill",
|
||||
"react-native-desktop-linking",
|
||||
"text-encoding",
|
||||
"js-sha3",
|
||||
"web3-utils"
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
"node_modules/react-native-keychain/desktop",
|
||||
"node_modules/react-native-securerandom/desktop",
|
||||
"modules/react-native-status/desktop",
|
||||
"modules/react-native-desktop-linking/desktop",
|
||||
"node_modules/google-breakpad"
|
||||
],
|
||||
"desktopFonts": [
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
set(REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_TYPE_NAMES ${REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_TYPE_NAMES}
|
||||
\"DesktopLinking\" PARENT_SCOPE)
|
||||
|
||||
set(REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_SRC ${REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_SRC}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/desktoplinking.cpp PARENT_SCOPE)
|
||||
|
||||
include(${CMAKE_ROOT}/Modules/ExternalProject.cmake)
|
|
@ -0,0 +1,72 @@
|
|||
#include "desktoplinking.h"
|
||||
#include "bridge.h"
|
||||
#include "eventdispatcher.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QFileOpenEvent>
|
||||
|
||||
namespace {
|
||||
struct RegisterQMLMetaType {
|
||||
RegisterQMLMetaType() { qRegisterMetaType<DesktopLinking *>(); }
|
||||
} registerMetaType;
|
||||
} // namespace
|
||||
|
||||
class DesktopLinkingPrivate {
|
||||
public:
|
||||
Bridge *bridge = nullptr;
|
||||
};
|
||||
|
||||
DesktopLinking::DesktopLinking(QObject *parent)
|
||||
: QObject(parent), d_ptr(new DesktopLinkingPrivate) {
|
||||
|
||||
QCoreApplication::instance()->installEventFilter(this);
|
||||
connect(this, &DesktopLinking::urlOpened, this, &DesktopLinking::handleURL);
|
||||
}
|
||||
|
||||
DesktopLinking::~DesktopLinking() {
|
||||
}
|
||||
|
||||
void DesktopLinking::setBridge(Bridge *bridge) {
|
||||
Q_D(DesktopLinking);
|
||||
d->bridge = bridge;
|
||||
}
|
||||
|
||||
QString DesktopLinking::moduleName() { return "DesktopLinking"; }
|
||||
|
||||
QList<ModuleMethod *> DesktopLinking::methodsToExport() {
|
||||
return QList<ModuleMethod *>{};
|
||||
}
|
||||
|
||||
QVariantMap DesktopLinking::constantsToExport() { return QVariantMap(); }
|
||||
|
||||
void DesktopLinking::handleURL(const QString url) {
|
||||
Q_D(DesktopLinking);
|
||||
qDebug() << "call of DesktopLinking::handleURL with param path: " << url;
|
||||
d->bridge->eventDispatcher()->sendDeviceEvent("urlOpened", QVariantMap{{"url", url}});
|
||||
}
|
||||
|
||||
bool DesktopLinking::eventFilter(QObject* obj, QEvent* event) {
|
||||
if (event->type() == QEvent::FileOpen)
|
||||
{
|
||||
QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
|
||||
if (!fileEvent->url().isEmpty())
|
||||
{
|
||||
auto m_lastUrl = fileEvent->url().toString();
|
||||
emit urlOpened(m_lastUrl);
|
||||
}
|
||||
else if (!fileEvent->file().isEmpty())
|
||||
{
|
||||
emit fileOpened(fileEvent->file());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// standard event processing
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef DESKTOPLINKING_H
|
||||
#define DESKTOPLINKING_H
|
||||
|
||||
#include "moduleinterface.h"
|
||||
|
||||
#include <QVariantMap>
|
||||
|
||||
class DesktopLinkingPrivate;
|
||||
class DesktopLinking : public QObject, public ModuleInterface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(ModuleInterface)
|
||||
|
||||
Q_DECLARE_PRIVATE(DesktopLinking)
|
||||
|
||||
public:
|
||||
Q_INVOKABLE DesktopLinking(QObject* parent = 0);
|
||||
~DesktopLinking();
|
||||
|
||||
void setBridge(Bridge* bridge) override;
|
||||
|
||||
QString moduleName() override;
|
||||
QList<ModuleMethod*> methodsToExport() override;
|
||||
QVariantMap constantsToExport() override;
|
||||
|
||||
signals:
|
||||
void urlOpened(QString path);
|
||||
void fileOpened(QString path);
|
||||
|
||||
public slots:
|
||||
void handleURL(const QString url);
|
||||
|
||||
private:
|
||||
QScopedPointer<DesktopLinkingPrivate> d_ptr;
|
||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
|
||||
};
|
||||
|
||||
#endif // DESKTOPLINKING_H
|
|
@ -0,0 +1,4 @@
|
|||
'use strict';
|
||||
|
||||
const NativeModules = require('NativeModules');
|
||||
module.exports = NativeModules.DesktopLinking;
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"private": true,
|
||||
"nativePackage": true,
|
||||
"name": "react-native-desktop-linking",
|
||||
"version": "1.0.0",
|
||||
"description": "Handle status-im:// links",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": ""
|
||||
}
|
|
@ -12,6 +12,8 @@
|
|||
(def EventEmmiter (js/require "react-native/Libraries/vendor/emitter/EventEmitter"))
|
||||
(def fetch (.-default (js/require "react-native-fetch-polyfill")))
|
||||
(def i18n (js/require "react-native-i18n"))
|
||||
(def desktop-linking (.-DesktopLinking (.-NativeModules react-native)))
|
||||
|
||||
(def react-native-firebase #js {})
|
||||
(def nfc-manager #js {})
|
||||
(def camera #js {:default #js {:constants {:Aspect "Portrait"}}})
|
||||
|
|
|
@ -27,3 +27,4 @@
|
|||
(def snoopy-buffer (js/require "rn-snoopy/stream/buffer"))
|
||||
(def background-timer (.-default (js/require "react-native-background-timer")))
|
||||
(def react-navigation (js/require "react-navigation"))
|
||||
(def desktop-linking #js {:addEventListener (fn [])})
|
||||
|
|
|
@ -21,6 +21,7 @@ external_modules_dir=( \
|
|||
'node_modules/react-native-securerandom/desktop' \
|
||||
'modules/react-native-status/desktop' \
|
||||
'node_modules/google-breakpad' \
|
||||
'modules/react-native-desktop-linking/desktop' \
|
||||
)
|
||||
|
||||
external_fonts=( \
|
||||
|
|
|
@ -8,11 +8,13 @@
|
|||
[status-im.transport.message.protocol :as protocol]
|
||||
[status-im.transport.message.public-chat :as public-chat]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.desktop.events :as desktop.events]
|
||||
[status-im.ui.screens.navigation :as navigation]
|
||||
[status-im.utils.clocks :as utils.clocks]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.utils.gfycat.core :as gfycat]
|
||||
[status-im.utils.utils :as utils]))
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(defn multi-user-chat? [cofx chat-id]
|
||||
(get-in cofx [:db :chats chat-id :group-chat]))
|
||||
|
@ -200,7 +202,9 @@
|
|||
(add-public-chat topic)
|
||||
(navigate-to-chat topic {:modal? modal?
|
||||
:navigation-reset? true})
|
||||
(public-chat/join-public-chat topic)))
|
||||
(public-chat/join-public-chat topic)
|
||||
(when platform/desktop?
|
||||
(desktop.events/change-tab :home))))
|
||||
|
||||
(fx/defn disable-chat-cooldown
|
||||
"Turns off chat cooldown (protection against message spamming)"
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
status-im.data-store.core
|
||||
[status-im.ui.screens.desktop.views :as views]
|
||||
[status-im.core :as core]
|
||||
[status-im.ui.components.react :as react]))
|
||||
[status-im.desktop.deep-links :as deep-links]))
|
||||
|
||||
(defn app-root []
|
||||
(reagent/create-class
|
||||
{:reagent-render views/main}))
|
||||
{:component-did-mount deep-links/add-event-listener
|
||||
:reagent-render views/main}))
|
||||
|
||||
(defn init []
|
||||
(core/init app-root))
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
(ns status-im.desktop.deep-links
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.react-native.js-dependencies :as js-dependencies]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn add-event-listener []
|
||||
(let [event-emitter (new (.-NativeEventEmitter js-dependencies/react-native)
|
||||
js-dependencies/desktop-linking)]
|
||||
(.addListener event-emitter
|
||||
"urlOpened"
|
||||
(fn [data]
|
||||
(log/debug "urlOpened event with data:" data)
|
||||
(let [url (get (js->clj data) "url")]
|
||||
(re-frame/dispatch [:handle-universal-link url]))))))
|
|
@ -1,14 +1,23 @@
|
|||
(ns status-im.ui.components.desktop.events
|
||||
(:require [status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.ui.screens.navigation :as navigation]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:show-desktop-tab
|
||||
(fn [{:keys [db] :as cofx} [_ tab-name]]
|
||||
(merge {:db (assoc-in db [:desktop/desktop :tab-view-id] tab-name)
|
||||
:dispatch [:navigate-to (if (and (= tab-name :home) (:current-chat-id db))
|
||||
(fx/defn change-tab
|
||||
[{:keys [db]} tab-name]
|
||||
{:db (assoc-in db [:desktop/desktop :tab-view-id] tab-name)})
|
||||
|
||||
(fx/defn navigate-to
|
||||
[{:keys [db] :as cofx} tab-name]
|
||||
(navigation/navigate-to-cofx cofx
|
||||
(if (and (= tab-name :home) (:current-chat-id db))
|
||||
:chat
|
||||
:home)]}
|
||||
:home)
|
||||
nil))
|
||||
|
||||
(fx/defn fetch-desktop-version
|
||||
[_ tab-name]
|
||||
(when (and platform/isMacOs?
|
||||
(= tab-name :profile))
|
||||
{:http-get
|
||||
|
@ -16,4 +25,16 @@
|
|||
"https://raw.githubusercontent.com/status-im/status-im.github.io/develop/env.sh"
|
||||
:success-event-creator
|
||||
(fn [o]
|
||||
[:fetch-desktop-version-success o])}}))))
|
||||
[:fetch-desktop-version-success o])}}))
|
||||
|
||||
(fx/defn show-desktop-tab
|
||||
[cofx tab-name]
|
||||
(fx/merge cofx
|
||||
(change-tab tab-name)
|
||||
(navigate-to tab-name)
|
||||
(fetch-desktop-version tab-name)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:show-desktop-tab
|
||||
(fn [cofx [_ tab-name]]
|
||||
(show-desktop-tab cofx tab-name)))
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
[status-im.ui.components.list-selection :as list-selection]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.add-new.new-chat.db :as new-chat.db]
|
||||
[status-im.ui.screens.desktop.main.chat.events :as desktop.events]
|
||||
[status-im.ui.screens.navigation :as navigation]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.utils.fx :as fx]
|
||||
[taoensso.timbre :as log]))
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
;; TODO(yenda) investigate why `handle-universal-link` event is
|
||||
;; dispatched 7 times for the same link
|
||||
|
@ -63,7 +65,9 @@
|
|||
(log/info "universal-links: handling view profile" profile-id)
|
||||
(if (new-chat.db/own-whisper-identity? db profile-id)
|
||||
(navigation/navigate-to-cofx cofx :my-profile nil)
|
||||
(navigation/navigate-to-cofx (assoc-in cofx [:db :contacts/identity] profile-id) :profile nil)))
|
||||
(if platform/desktop?
|
||||
(desktop.events/show-profile-desktop profile-id cofx)
|
||||
(navigation/navigate-to-cofx (assoc-in cofx [:db :contacts/identity] profile-id) :profile nil))))
|
||||
|
||||
(fx/defn handle-extension [cofx url]
|
||||
(log/info "universal-links: handling url profile" url)
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
(defrecord Notification [])
|
||||
(def react-native-firebase #js {:default #js {:notifications #js {:Notification Notification}}})
|
||||
|
||||
(def desktop-linking #js {:addEventListener (fn [])})
|
||||
|
||||
(def snoopy #js {:default #js {}})
|
||||
(def snoopy-filter #js {:default #js {}})
|
||||
(def snoopy-bars #js {:default #js {}})
|
||||
|
|
Loading…
Reference in New Issue