Push notifications support #4432; Rename app to Status globally.

Signed-off-by: Max Risuhin <risuhin.max@gmail.com>
This commit is contained in:
Max Risuhin 2018-10-19 18:50:35 +03:00
parent 2c65077270
commit 5986761210
No known key found for this signature in database
GPG Key ID: BF733F5ACA0B4448
28 changed files with 333 additions and 54 deletions

View File

@ -66,7 +66,7 @@ def bundleLinux(type = 'nightly') {
sh './scripts/build-desktop.sh bundle'
dir(packageFolder) {
pkg = common.pkgFilename(type, 'AppImage')
sh "mv ../StatusIm-x86_64.AppImage ${pkg}"
sh "mv ../Status-x86_64.AppImage ${pkg}"
}
return "${packageFolder}/${pkg}".drop(2)
}

View File

@ -77,6 +77,7 @@
(def dimensions (.-Dimensions js-dependencies/react-native))
(def keyboard (.-Keyboard js-dependencies/react-native))
(def linking (.-Linking js-dependencies/react-native))
(def desktop-notification (.-DesktopNotification (.-NativeModules js-dependencies/react-native)))
(def slider (get-class "Slider"))
;; Accessor methods for React Components

View File

@ -0,0 +1,7 @@
[Desktop Entry]
Type=Application
Name=Status
Comment=Status Desktop
Exec=Status
Icon=Status
Categories=Network;

View File

@ -1,7 +0,0 @@
[Desktop Entry]
Type=Application
Name=StatusIm
Comment=StatusIm Desktop
Exec=StatusIm
Icon=StatusIm
Categories=Network;

View File

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

View File

@ -8,7 +8,7 @@
cmake_minimum_required(VERSION 2.8.11)
set(APP_NAME StatusIm)
set(APP_NAME Status)
set(JS_APP_NAME StatusIm)
set(REACT_BUILD_STATIC_LIB ON)

View File

@ -185,7 +185,7 @@ int main(int argc, char **argv) {
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
app.setApplicationName("StatusIm");
app.setApplicationName("Status");
QString appPath = QCoreApplication::applicationDirPath();
#ifndef BUILD_FOR_BUNDLE
@ -258,7 +258,7 @@ int main(int argc, char **argv) {
void writeLogsToFile() {
QMutexLocker locker(&consoleOutputMutex);
QFile logFile(getDataStoragePath() + "/StatusIm.log");
QFile logFile(getDataStoragePath() + "/Status.log");
if (logFile.open(QIODevice::WriteOnly | QIODevice::Append)) {
for (QString message : consoleOutputStrings) {
logFile.write(message.toStdString().c_str());

View File

@ -21,7 +21,7 @@ Rectangle {
anchors.centerIn: parent
Text {
Layout.alignment: Qt.AlignCenter
text: "Oh, no! StatusIm application just crashed!"
text: "Oh, no! Status application just crashed!"
font.bold: true
font.pointSize: 25
}

View File

@ -55,6 +55,7 @@
"react-native/Libraries/vendor/emitter/EventEmitter",
"react-native-fetch-polyfill",
"react-native-desktop-linking",
"react-native-desktop-notification",
"text-encoding",
"js-sha3",
"web3-utils"

View File

@ -16,6 +16,7 @@
"node_modules/react-native-securerandom/desktop",
"modules/react-native-status/desktop",
"modules/react-native-desktop-linking/desktop",
"modules/react-native-desktop-notification/desktop",
"node_modules/google-breakpad"
],
"desktopFonts": [

View File

@ -0,0 +1,54 @@
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_TYPE_NAMES ${REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_TYPE_NAMES}
\"DesktopNotification\" PARENT_SCOPE)
set(REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_SRC ${REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_SRC}
${CMAKE_CURRENT_SOURCE_DIR}/desktopnotification.cpp PARENT_SCOPE)
include(${CMAKE_ROOT}/Modules/ExternalProject.cmake)
set(SN_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/SnoreNotify_ep-prefix/src/SnoreNotify_ep)
if (UNIX AND NOT APPLE)
set(SN_LIBPATHSUFFIX /${CMAKE_LIBRARY_ARCHITECTURE})
set(SnoreNotifyFreedesktop_STATIC_LIB ${SN_PREFIX}/lib${SN_LIBPATHSUFFIX}/${CMAKE_STATIC_LIBRARY_PREFIX}snore_backend_freedesktop${CMAKE_STATIC_LIBRARY_SUFFIX})
set(SnoreNotify_LIBS ${SnoreNotifyFreedesktop_STATIC_LIB})
set(SnoreNotify_CMAKE_ARGS -DBUILD_osxnotificationcenter=OFF -DBUILD_sound=OFF -DBUILD_speech=OFF -DBUILD_toasty=OFF
-DBUILD_snarl=OFF -DBUILD_growl=OFF -DBUILD_trayicon=OFF -DBUILD_pushover_backend=OFF)
endif()
if (APPLE)
set(SnoreNotifyOSXNotificationCenter_STATIC_LIB ${SN_PREFIX}/lib${SN_LIBPATHSUFFIX}/${CMAKE_STATIC_LIBRARY_PREFIX}snore_backend_osxnotificationcenter${CMAKE_STATIC_LIBRARY_SUFFIX})
set(SnoreNotify_LIBS ${SnoreNotifyOSXNotificationCenter_STATIC_LIB})
set(SnoreNotify_CMAKE_ARGS -DBUILD_sound=OFF -DBUILD_speech=OFF -DBUILD_toasty=OFF -DBUILD_snarl=OFF -DBUILD_growl=OFF
-DBUILD_freedesktop_backend=OFF -DBUILD_trayicon=OFF -DBUILD_pushover_backend=OFF)
endif()
set(SnoreNotify_INCLUDE_DIR ${SN_PREFIX}/include)
set(SnoreNotify_STATIC_LIB ${SN_PREFIX}/lib${SN_LIBPATHSUFFIX}/${CMAKE_STATIC_LIBRARY_PREFIX}snore-qt5${CMAKE_STATIC_LIBRARY_SUFFIX})
set(SnoreNotifyBackend_STATIC_LIB ${SN_PREFIX}/lib${SN_LIBPATHSUFFIX}/${CMAKE_STATIC_LIBRARY_PREFIX}snore_backend_snore${CMAKE_STATIC_LIBRARY_SUFFIX})
set(SnoreNotifyBackendSettings_STATIC_LIB ${SN_PREFIX}/lib${SN_LIBPATHSUFFIX}/${CMAKE_STATIC_LIBRARY_PREFIX}snore_settings_backend_snore${CMAKE_STATIC_LIBRARY_SUFFIX})
set(SnoreNotifySettings_STATIC_LIB ${SN_PREFIX}/lib${SN_LIBPATHSUFFIX}/${CMAKE_STATIC_LIBRARY_PREFIX}snoresettings-qt5${CMAKE_STATIC_LIBRARY_SUFFIX})
set(SnoreNotify_CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${SN_PREFIX} -DSNORE_STATIC=ON -DBUILD_daemon=OFF -DBUILD_settings=OFF
-DBUILD_snoresend=OFF ${SnoreNotify_CMAKE_ARGS})
ExternalProject_Add(SnoreNotify_ep
GIT_REPOSITORY https://github.com/status-im/snorenotify.git
CMAKE_ARGS ${SnoreNotify_CMAKE_ARGS}
BUILD_BYPRODUCTS ${SnoreNotify_STATIC_LIB} ${SnoreNotify_LIBS} ${SnoreNotifyBackend_STATIC_LIB}
${SnoreNotifyBackendSettings_STATIC_LIB} ${SnoreNotifySettings_STATIC_LIB}
LOG_DOWNLOAD 1
)
set(REACT_NATIVE_DESKTOP_EXTERNAL_PROJECT_DEPS ${REACT_NATIVE_DESKTOP_EXTERNAL_PROJECT_DEPS} SnoreNotify_ep PARENT_SCOPE)
set(REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_LIBS ${REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_LIBS}
${SnoreNotify_LIBS} ${SnoreNotify_STATIC_LIB} ${SnoreNotifyBackend_STATIC_LIB}
${SnoreNotifyBackendSettings_STATIC_LIB} ${SnoreNotifySettings_STATIC_LIB} PARENT_SCOPE)
set(REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_INCLUDE_DIRS ${REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_INCLUDE_DIRS}
${SnoreNotify_INCLUDE_DIR} PARENT_SCOPE)

View File

@ -0,0 +1,115 @@
/**
* Copyright (c) 2017-present, Status Research and Development GmbH.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#include "desktopnotification.h"
#include "bridge.h"
#include "eventdispatcher.h"
#include "libsnore/application.h"
#include "libsnore/snore.h"
#ifdef Q_OS_MAC
#include "libsnore/snore_static_plugins.h"
#endif
#include <QGuiApplication>
#include <QDebug>
#ifdef Q_OS_LINUX
namespace SnorePlugin {}
using namespace SnorePlugin;
Q_IMPORT_PLUGIN(Freedesktop)
Q_IMPORT_PLUGIN(Snore)
static void loadSnoreResources()
{
// prevent multiple symbols
static const auto load = []() {
Q_INIT_RESOURCE(snore);
Q_INIT_RESOURCE(snore_notification);
};
load();
}
Q_COREAPP_STARTUP_FUNCTION(loadSnoreResources)
#endif // Q_OS_LINUX
namespace {
struct RegisterQMLMetaType {
RegisterQMLMetaType() { qRegisterMetaType<DesktopNotification *>(); }
} registerMetaType;
const QString NewMessageAlert = QStringLiteral("NewMessage");
} // namespace
class DesktopNotificationPrivate {
public:
Bridge *bridge = nullptr;
Snore::Application snoreApp;
};
DesktopNotification::DesktopNotification(QObject *parent)
: QObject(parent), d_ptr(new DesktopNotificationPrivate) {
connect(qApp, &QGuiApplication::focusWindowChanged, this, [=](QWindow *focusWindow){
m_appHasFocus = (focusWindow != nullptr);
});
d_ptr->snoreApp = Snore::Application(QCoreApplication::applicationName(),
Snore::Icon::defaultIcon());
d_ptr->snoreApp.addAlert(
Snore::Alert(NewMessageAlert, Snore::Icon::defaultIcon()));
if (Snore::SnoreCore::instance().pluginNames().isEmpty()) {
Snore::SnoreCore::instance().loadPlugins(Snore::SnorePlugin::Backend);
}
qDebug() << "DesktopNotification::DesktopNotification List of all loaded Snore plugins: "
<< Snore::SnoreCore::instance().pluginNames();
Snore::SnoreCore::instance().registerApplication(d_ptr->snoreApp);
Snore::SnoreCore::instance().setDefaultApplication(d_ptr->snoreApp);
qDebug() << "DesktopNotification::DesktopNotification Current notification backend: "
<< Snore::SnoreCore::instance().primaryNotificationBackend();
}
DesktopNotification::~DesktopNotification() {
Snore::SnoreCore::instance().deregisterApplication(d_ptr->snoreApp);
}
void DesktopNotification::setBridge(Bridge *bridge) {
Q_D(DesktopNotification);
d->bridge = bridge;
}
QString DesktopNotification::moduleName() { return "DesktopNotification"; }
QList<ModuleMethod *> DesktopNotification::methodsToExport() {
return QList<ModuleMethod *>{};
}
QVariantMap DesktopNotification::constantsToExport() { return QVariantMap(); }
void DesktopNotification::sendNotification(QString text) {
Q_D(DesktopNotification);
qDebug() << "call of DesktopNotification::sendNotification";
if (m_appHasFocus) {
qDebug() << "Don't send notification since some application window is active";
return;
}
Snore::Notification notification(
d_ptr->snoreApp, d_ptr->snoreApp.alerts()[NewMessageAlert], "New message",
text, Snore::Icon::defaultIcon());
Snore::SnoreCore::instance().broadcastNotification(notification);
}

View File

@ -0,0 +1,41 @@
/**
* Copyright (c) 2017-present, Status Research and Development GmbH.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#ifndef DESKTOPNOTIFICATION_H
#define DESKTOPNOTIFICATION_H
#include "moduleinterface.h"
#include <QVariantMap>
class DesktopNotificationPrivate;
class DesktopNotification : public QObject, public ModuleInterface {
Q_OBJECT
Q_INTERFACES(ModuleInterface)
Q_DECLARE_PRIVATE(DesktopNotification)
public:
Q_INVOKABLE DesktopNotification(QObject* parent = 0);
~DesktopNotification();
void setBridge(Bridge* bridge) override;
QString moduleName() override;
QList<ModuleMethod*> methodsToExport() override;
QVariantMap constantsToExport() override;
Q_INVOKABLE void sendNotification(QString text);
private:
QScopedPointer<DesktopNotificationPrivate> d_ptr;
bool m_appHasFocus = false;
};
#endif // DESKTOPNOTIFICATION_H

View File

@ -0,0 +1,4 @@
'use strict';
import { NativeModules } from 'react-native';
module.exports = NativeModules.DesktopNotification;

View File

@ -0,0 +1,13 @@
{
"private": true,
"nativePackage": true,
"name": "react-native-desktop-notification",
"version": "1.0.0",
"description": "Send desktop notifications",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": ""
}

View File

@ -22,6 +22,7 @@ external_modules_dir=( \
'modules/react-native-status/desktop' \
'node_modules/google-breakpad' \
'modules/react-native-desktop-linking/desktop' \
'modules/react-native-desktop-notification/desktop' \
)
external_fonts=( \
@ -59,9 +60,10 @@ function joinExistingPath() {
fi
}
STATUSREACTPATH="$(joinExistingPath "$SCRIPTPATH" '..')"
STATUSREACTPATH="$(cd "$SCRIPTPATH" && cd '..' && pwd)"
WORKFOLDER="$(joinExistingPath "$STATUSREACTPATH" 'StatusImPackage')"
DEPLOYQT="$(joinPath . 'linuxdeployqt-continuous-x86_64.AppImage')"
APPIMAGETOOL="$(joinPath . 'appimagetool-x86_64.AppImage')"
function init() {
if [ -z $QT_PATH ]; then
@ -101,14 +103,14 @@ function buildClojureScript() {
echo ""
# from index.desktop.js create javascript bundle and resources folder
echo "Generating StatusIm.jsbundle and assets folder..."
react-native bundle --entry-file index.desktop.js --bundle-output "$WORKFOLDER/StatusIm.jsbundle" \
echo "Generating Status.jsbundle and assets folder..."
react-native bundle --entry-file index.desktop.js --bundle-output "$WORKFOLDER/Status.jsbundle" \
--dev false --platform desktop --assets-dest "$WORKFOLDER/assets"
echo -e "${GREEN}Generating done.${NC}"
echo ""
# Add path to javascript bundle to package.json
jsBundleLine="\"desktopJSBundlePath\": \"$WORKFOLDER/StatusIm.jsbundle\""
jsBundleLine="\"desktopJSBundlePath\": \"$WORKFOLDER/Status.jsbundle\""
jsPackagePath=$(joinExistingPath "$STATUSREACTPATH" 'desktop_files/package.json')
if grep -Fq "$jsBundleLine" "$jsPackagePath"; then
echo -e "${GREEN}Found line in package.json.${NC}"
@ -127,14 +129,14 @@ function buildClojureScript() {
function compile() {
pushd desktop
rm -rf CMakeFiles CMakeCache.txt cmake_install.cmake Makefile
rm -rf CMakeFiles CMakeCache.txt cmake_install.cmake Makefile modules
cmake -Wno-dev \
-DCMAKE_BUILD_TYPE=Release \
-DEXTERNAL_MODULES_DIR="$(joinStrings ${external_modules_dir[@]})" \
-DDESKTOP_FONTS="$(joinStrings ${external_fonts[@]})" \
-DJS_BUNDLE_PATH="$WORKFOLDER/StatusIm.jsbundle" \
-DJS_BUNDLE_PATH="$WORKFOLDER/Status.jsbundle" \
-DCMAKE_CXX_FLAGS:='-DBUILD_FOR_BUNDLE=1 -std=c++11'
make
make -j5
popd
}
@ -145,7 +147,7 @@ function bundleLinux() {
QTBIN=$(joinExistingPath "$QT_PATH" 'bin')
fi
# invoke linuxdeployqt to create StatusIm.AppImage
# invoke linuxdeployqt to create Status.AppImage
echo "Creating AppImage..."
pushd $WORKFOLDER
@ -164,23 +166,29 @@ function bundleLinux() {
usrBinPath=$(joinPath "$WORKFOLDER" "AppDir/usr/bin")
cp -r ./deployment/linux/usr $WORKFOLDER/AppDir
cp ./.env $usrBinPath
cp ./desktop/bin/StatusIm $usrBinPath
cp ./desktop/bin/Status $usrBinPath
cp ./desktop/reportApp/reportApp $usrBinPath
if [ ! -f $DEPLOYQT ]; then
wget --output-document="$DEPLOYQT" --show-progress -q https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage
chmod a+x $DEPLOYQT
fi
rm -f Application-x86_64.AppImage
rm -f StatusIm-x86_64.AppImage
if [ ! -f $APPIMAGETOOL ]; then
wget --output-document="$APPIMAGETOOL" --show-progress -q https://github.com/AppImage/AppImageKit/releases/download/10/appimagetool-x86_64.AppImage
chmod a+x $APPIMAGETOOL
fi
[ $VERBOSE_LEVEL -ge 1 ] && ldd $(joinExistingPath "$usrBinPath" 'StatusIm')
rm -f Application-x86_64.AppImage
rm -f Status-x86_64.AppImage
[ $VERBOSE_LEVEL -ge 1 ] && ldd $(joinExistingPath "$usrBinPath" 'Status')
$DEPLOYQT \
$(joinExistingPath "$usrBinPath" 'reportApp') \
-verbose=$VERBOSE_LEVEL -always-overwrite -no-strip -no-translations -qmake="$(joinExistingPath "${QTBIN}" 'qmake')" \
-qmldir="$STATUSREACTPATH/desktop/reportApp"
desktopFilePath="$(joinExistingPath "$WORKFOLDER" 'AppDir/usr/share/applications/StatusIm.desktop')"
desktopFilePath="$(joinExistingPath "$WORKFOLDER" 'AppDir/usr/share/applications/Status.desktop')"
$DEPLOYQT \
$desktopFilePath \
-verbose=$VERBOSE_LEVEL -always-overwrite -no-strip \
@ -190,30 +198,29 @@ function bundleLinux() {
-qmldir="$(joinExistingPath "$STATUSREACTPATH" 'node_modules/react-native')"
pushd $WORKFOLDER
[ $VERBOSE_LEVEL -ge 1 ] && ldd AppDir/usr/bin/StatusIm
[ $VERBOSE_LEVEL -ge 1 ] && ldd AppDir/usr/bin/Status
cp -r assets/share/assets AppDir/usr/bin
cp -rf StatusImAppImage/* AppDir/usr/bin
rm -f AppDir/usr/bin/StatusIm.AppImage
rm -f AppDir/usr/bin/Status.AppImage
popd
$DEPLOYQT \
$desktopFilePath \
-verbose=$VERBOSE_LEVEL -appimage -qmake="$qmakePath"
pushd $WORKFOLDER
[ $VERBOSE_LEVEL -ge 1 ] && ldd AppDir/usr/bin/StatusIm
[ $VERBOSE_LEVEL -ge 1 ] && ldd AppDir/usr/bin/Status
cp -r assets/share/assets AppDir/usr/bin
cp -rf StatusImAppImage/* AppDir/usr/bin
rm -f AppDir/usr/bin/StatusIm.AppImage
rm -f AppDir/usr/bin/Status.AppImage
popd
$DEPLOYQT \
"$desktopFilePath" \
-verbose=$VERBOSE_LEVEL -appimage -qmake="$qmakePath"
$APPIMAGETOOL \
"$WORKFOLDER/AppDir"
pushd $WORKFOLDER
[ $VERBOSE_LEVEL -ge 1 ] && ldd AppDir/usr/bin/StatusIm
rm -rf StatusIm.AppImage
[ $VERBOSE_LEVEL -ge 1 ] && ldd AppDir/usr/bin/Status
rm -rf Status.AppImage
popd
echo -e "${GREEN}Package ready in ./StatusIm-x86_64.AppImage!${NC}"
echo -e "${GREEN}Package ready in ./Status-x86_64.AppImage!${NC}"
echo ""
}
@ -231,7 +238,7 @@ function bundleMacOS() {
cp -r assets/share/assets Status.app/Contents/Resources
ln -sf ../Resources/assets ../Resources/ubuntu-server ../Resources/node_modules Status.app/Contents/MacOS
chmod +x Status.app/Contents/Resources/ubuntu-server
cp ../desktop/bin/StatusIm Status.app/Contents/MacOS/Status
cp ../desktop/bin/Status Status.app/Contents/MacOS/Status
cp ../desktop/reportApp/reportApp Status.app/Contents/MacOS
cp ../.env Status.app/Contents/Resources
ln -sf ../Resources/.env Status.app/Contents/MacOS/.env

View File

@ -105,7 +105,7 @@ else
fi
echo -e "\n### Verifying signature..."
codesign --verify --strict=all --deep --verbose "$OBJECT"
codesign --verify --strict=all --deep --verbose=4 "$OBJECT"
echo -e "\n### Assessing Gatekeeper validation..."
if [ -d "$OBJECT" ]; then

View File

@ -62,6 +62,11 @@
(accounts.update/account-update {:dev-mode? dev-mode?}
{})))
(fx/defn enable-notifications [cofx desktop-notifications?]
(accounts.update/account-update cofx
{:desktop-notifications? desktop-notifications?}
{}))
(fx/defn switch-web3-opt-in-mode [{:keys [db] :as cofx} opt-in]
(let [settings (get-in db [:account/account :settings])]
(accounts.update/update-settings cofx

View File

@ -62,6 +62,7 @@
:name (gfycat/generate-gfy pubkey)
:status status
:signed-up? true
:desktop-notifications? false
:photo-path (identicon/identicon pubkey)
:signing-phrase signing-phrase
:seed-backed-up? seed-backed-up

View File

@ -46,6 +46,7 @@
(spec/def :account/signing-phrase :global/not-empty-string)
(spec/def :account/mnemonic (spec/nilable string?))
(spec/def :account/sharing-usage-data? (spec/nilable boolean?))
(spec/def :account/desktop-notifications? (spec/nilable boolean?))
(spec/def :account/dev-mode? (spec/nilable boolean?))
(spec/def :account/seed-backed-up? (spec/nilable boolean?))
(spec/def :account/installation-id :global/not-empty-string)
@ -60,7 +61,7 @@
:account/email :account/signed-up? :account/network
:account/networks :account/settings :account/wnode
:account/last-sign-in :account/sharing-usage-data? :account/dev-mode?
:account/seed-backed-up? :account/mnemonic
:account/seed-backed-up? :account/mnemonic :account/desktop-notifications?
:account/wallet-set-up-passed? :account/last-request
:account/bootnodes :account/extensions
:account/mainnet-warning-shown?]))

View File

@ -21,6 +21,8 @@
[status-im.transport.message.protocol :as protocol]
[status-im.data-store.messages :as messages-store]
[status-im.data-store.user-statuses :as user-statuses-store]
[status-im.utils.platform :as platform]
[status-im.ui.components.react :as react]
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]))
@ -68,10 +70,15 @@
(assoc message :outgoing (= from (:current-public-key db))))
(fx/defn add-message
[{:keys [db] :as cofx} batch? {:keys [chat-id message-id clock-value] :as message} current-chat?]
[{:keys [db] :as cofx} batch? {:keys [chat-id message-id clock-value timestamp content from] :as message} current-chat?]
(let [prepared-message (-> message
(prepare-message chat-id current-chat?)
(add-outgoing-status cofx))]
(when (and platform/desktop?
(not= from (:current-public-key db))
(get-in db [:account/account :desktop-notifications?])
(< (time/seconds-ago (time/to-date timestamp)) constants/one-earth-day))
(.sendNotification react/desktop-notification (:text content)))
(let [fx {:db (cond->
(-> db
(update-in [:chats chat-id :messages] assoc message-id prepared-message)

View File

@ -20,6 +20,7 @@
(def response-suggesstion-resize-duration 100)
(def default-number-of-messages 20)
(def blocks-per-hour 120)
(def one-earth-day 86400)
(def inbox-password "status-offline-inbox")

View File

@ -203,3 +203,7 @@
[:properties :extensions]
{:type :list
:objectType :extension}))
(def v13 (assoc-in v12
[:properties :desktop-notifications?]
{:type :bool :default false}))

View File

@ -43,9 +43,13 @@
account/v11])
(def v12 [network/v1
bootnode/v4
extension/v12])
(def v13 [network/v1
bootnode/v4
extension/v12
account/v12])
account/v13])
;; put schemas ordered by version
(def schemas [{:schema v1
@ -83,4 +87,7 @@
:migration migrations/v11}
{:schema v12
:schemaVersion 12
:migration migrations/v12}])
:migration migrations/v12}
{:schema v13
:schemaVersion 13
:migration migrations/v13}])

View File

@ -90,3 +90,6 @@
(defn v12 [old-realm new-realm]
(log/debug "migrating base database v12: " old-realm new-realm))
(defn v13 [old-realm new-realm]
(log/debug "migrating base database v13: " old-realm new-realm))

View File

@ -123,6 +123,11 @@
(fn [cofx [_ dev-mode?]]
(accounts/switch-dev-mode cofx dev-mode?)))
(handlers/register-handler-fx
:accounts.ui/notifications-enabled
(fn [cofx [_ desktop-notifications?]]
(accounts/enable-notifications cofx desktop-notifications?)))
(handlers/register-handler-fx
:accounts.ui/web3-opt-in-mode-switched
(fn [cofx [_ opt-in]]

View File

@ -110,6 +110,7 @@
(let [{:keys [url commit]} nightly-version
adv-settings-open? (= current-view-id :advanced-settings)
backup-recovery-phrase-open? (= current-view-id :backup-recovery-phrase)
notifications? (get-in user [:desktop-notifications?])
show-backup-seed? (and (not seed-backed-up?) (not (string/blank? mnemonic)))]
[react/view
[react/view {:style styles/profile-edit}
@ -121,6 +122,11 @@
[react/view styles/profile-view
[profile-badge user editing?]
[share-contact-code]
[react/view {:style (styles/profile-row false)}
[react/text {:style (styles/profile-row-text colors/black)} (i18n/label :notifications)]
[react/switch {:on-tint-color colors/blue
:value notifications?
:on-value-change #(re-frame/dispatch [:accounts.ui/notifications-enabled (not notifications?)])}]]
[react/touchable-highlight {:style (styles/profile-row adv-settings-open?)
:on-press #(re-frame/dispatch [:navigate-to (if adv-settings-open? :home :advanced-settings)])}
[react/view {:style styles/adv-settings}

View File

@ -124,9 +124,11 @@
(label :t/datetime-ago-format {:ago (label :t/datetime-ago)
:number diff
:time-intervals name})))
(defn seconds-ago [time]
(t/in-seconds (t/interval time (t/now))))
(defn time-ago [time]
(let [diff (t/in-seconds (t/interval time (t/now)))]
(let [diff (seconds-ago time)]
(if (< diff 60)
(label :t/active-online)
(let [unit (first (drop-while #(and (>= diff (:limit %))