diff --git a/ci/desktop.groovy b/ci/desktop.groovy index b4c93b62d1..fa2b9df9f6 100644 --- a/ci/desktop.groovy +++ b/ci/desktop.groovy @@ -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) } diff --git a/components/src/status_im/ui/components/react.cljs b/components/src/status_im/ui/components/react.cljs index a1a42ad98c..75e94dcc04 100644 --- a/components/src/status_im/ui/components/react.cljs +++ b/components/src/status_im/ui/components/react.cljs @@ -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 diff --git a/deployment/linux/usr/share/applications/Status.desktop b/deployment/linux/usr/share/applications/Status.desktop new file mode 100644 index 0000000000..a753f7d0c0 --- /dev/null +++ b/deployment/linux/usr/share/applications/Status.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Application +Name=Status +Comment=Status Desktop +Exec=Status +Icon=Status +Categories=Network; diff --git a/deployment/linux/usr/share/applications/StatusIm.desktop b/deployment/linux/usr/share/applications/StatusIm.desktop deleted file mode 100644 index 93b6441f41..0000000000 --- a/deployment/linux/usr/share/applications/StatusIm.desktop +++ /dev/null @@ -1,7 +0,0 @@ -[Desktop Entry] -Type=Application -Name=StatusIm -Comment=StatusIm Desktop -Exec=StatusIm -Icon=StatusIm -Categories=Network; \ No newline at end of file diff --git a/deployment/linux/usr/share/icons/hicolor/1024x1024/apps/StatusIm.png b/deployment/linux/usr/share/icons/hicolor/1024x1024/apps/Status.png similarity index 100% rename from deployment/linux/usr/share/icons/hicolor/1024x1024/apps/StatusIm.png rename to deployment/linux/usr/share/icons/hicolor/1024x1024/apps/Status.png diff --git a/desktop/CMakeLists.txt b/desktop/CMakeLists.txt index 07189efbea..19a0a0db37 100644 --- a/desktop/CMakeLists.txt +++ b/desktop/CMakeLists.txt @@ -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) diff --git a/desktop/main.cpp b/desktop/main.cpp index 2a36425ded..c4f36ea3c2 100644 --- a/desktop/main.cpp +++ b/desktop/main.cpp @@ -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()); diff --git a/desktop/reportApp/main.qml b/desktop/reportApp/main.qml index 2c463a44d7..d246fa6b6e 100644 --- a/desktop/reportApp/main.qml +++ b/desktop/reportApp/main.qml @@ -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 } diff --git a/desktop_files/.re-natal b/desktop_files/.re-natal index 3bdefe44e2..a8784b59ad 100644 --- a/desktop_files/.re-natal +++ b/desktop_files/.re-natal @@ -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" diff --git a/desktop_files/package.json b/desktop_files/package.json index 19e032648d..e0792400a3 100644 --- a/desktop_files/package.json +++ b/desktop_files/package.json @@ -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": [ diff --git a/modules/react-native-desktop-notification/desktop/CMakeLists.txt b/modules/react-native-desktop-notification/desktop/CMakeLists.txt new file mode 100755 index 0000000000..a3ec5db8e2 --- /dev/null +++ b/modules/react-native-desktop-notification/desktop/CMakeLists.txt @@ -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) + diff --git a/modules/react-native-desktop-notification/desktop/desktopnotification.cpp b/modules/react-native-desktop-notification/desktop/desktopnotification.cpp new file mode 100644 index 0000000000..6b6f1c82ef --- /dev/null +++ b/modules/react-native-desktop-notification/desktop/desktopnotification.cpp @@ -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 +#include + +#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(); } +} 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 DesktopNotification::methodsToExport() { + return QList{}; +} + +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); +} diff --git a/modules/react-native-desktop-notification/desktop/desktopnotification.h b/modules/react-native-desktop-notification/desktop/desktopnotification.h new file mode 100644 index 0000000000..2bfab3e63c --- /dev/null +++ b/modules/react-native-desktop-notification/desktop/desktopnotification.h @@ -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 + +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 methodsToExport() override; + QVariantMap constantsToExport() override; + + Q_INVOKABLE void sendNotification(QString text); +private: + QScopedPointer d_ptr; + bool m_appHasFocus = false; +}; + +#endif // DESKTOPNOTIFICATION_H diff --git a/modules/react-native-desktop-notification/index.js b/modules/react-native-desktop-notification/index.js new file mode 100644 index 0000000000..fd66bbfe8a --- /dev/null +++ b/modules/react-native-desktop-notification/index.js @@ -0,0 +1,4 @@ +'use strict'; + +import { NativeModules } from 'react-native'; +module.exports = NativeModules.DesktopNotification; diff --git a/modules/react-native-desktop-notification/package.json b/modules/react-native-desktop-notification/package.json new file mode 100644 index 0000000000..5d5ea1d175 --- /dev/null +++ b/modules/react-native-desktop-notification/package.json @@ -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": "" +} \ No newline at end of file diff --git a/scripts/build-desktop.sh b/scripts/build-desktop.sh index 61536611c1..16c42cce1e 100755 --- a/scripts/build-desktop.sh +++ b/scripts/build-desktop.sh @@ -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 diff --git a/scripts/sign-macos-pkg.sh b/scripts/sign-macos-pkg.sh index fc157cb21f..44ac0c5033 100755 --- a/scripts/sign-macos-pkg.sh +++ b/scripts/sign-macos-pkg.sh @@ -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 diff --git a/src/status_im/accounts/core.cljs b/src/status_im/accounts/core.cljs index c51bf93d58..23f61434e8 100644 --- a/src/status_im/accounts/core.cljs +++ b/src/status_im/accounts/core.cljs @@ -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 diff --git a/src/status_im/accounts/create/core.cljs b/src/status_im/accounts/create/core.cljs index 99c81a9ccd..62b0a867a6 100644 --- a/src/status_im/accounts/create/core.cljs +++ b/src/status_im/accounts/create/core.cljs @@ -56,17 +56,18 @@ db] :as cofx} {:keys [pubkey address mnemonic]} password seed-backed-up] (let [normalized-address (utils.hex/normalize-hex address) - account {:public-key pubkey - :installation-id (random-guid-generator) - :address normalized-address - :name (gfycat/generate-gfy pubkey) - :status status - :signed-up? true - :photo-path (identicon/identicon pubkey) - :signing-phrase signing-phrase - :seed-backed-up? seed-backed-up - :mnemonic mnemonic - :settings (constants/default-account-settings)}] + account {:public-key pubkey + :installation-id (random-guid-generator) + :address normalized-address + :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 + :mnemonic mnemonic + :settings (constants/default-account-settings)}] (log/debug "account-created") (when-not (string/blank? pubkey) (fx/merge cofx diff --git a/src/status_im/accounts/db.cljs b/src/status_im/accounts/db.cljs index 3c574c1e86..244d6e3018 100644 --- a/src/status_im/accounts/db.cljs +++ b/src/status_im/accounts/db.cljs @@ -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?])) diff --git a/src/status_im/chat/models/message.cljs b/src/status_im/chat/models/message.cljs index 74542e1198..956e22b8aa 100644 --- a/src/status_im/chat/models/message.cljs +++ b/src/status_im/chat/models/message.cljs @@ -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) diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index f1d417d6c9..b843bbd33e 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -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") diff --git a/src/status_im/data_store/realm/schemas/base/account.cljs b/src/status_im/data_store/realm/schemas/base/account.cljs index 479aa25239..5fbc81c97f 100644 --- a/src/status_im/data_store/realm/schemas/base/account.cljs +++ b/src/status_im/data_store/realm/schemas/base/account.cljs @@ -202,4 +202,8 @@ (def v12 (assoc-in v11 [:properties :extensions] {:type :list - :objectType :extension})) \ No newline at end of file + :objectType :extension})) + +(def v13 (assoc-in v12 + [:properties :desktop-notifications?] + {:type :bool :default false})) \ No newline at end of file diff --git a/src/status_im/data_store/realm/schemas/base/core.cljs b/src/status_im/data_store/realm/schemas/base/core.cljs index 6ef9f5d24e..3534ff4abf 100644 --- a/src/status_im/data_store/realm/schemas/base/core.cljs +++ b/src/status_im/data_store/realm/schemas/base/core.cljs @@ -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}]) diff --git a/src/status_im/data_store/realm/schemas/base/migrations.cljs b/src/status_im/data_store/realm/schemas/base/migrations.cljs index efdffb442e..4af5080bbf 100644 --- a/src/status_im/data_store/realm/schemas/base/migrations.cljs +++ b/src/status_im/data_store/realm/schemas/base/migrations.cljs @@ -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)) diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 1c7cee825f..2ffe8e3f69 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -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]] diff --git a/src/status_im/ui/screens/desktop/main/tabs/profile/views.cljs b/src/status_im/ui/screens/desktop/main/tabs/profile/views.cljs index 13878a9165..6d4e0c0627 100644 --- a/src/status_im/ui/screens/desktop/main/tabs/profile/views.cljs +++ b/src/status_im/ui/screens/desktop/main/tabs/profile/views.cljs @@ -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} diff --git a/src/status_im/utils/datetime.cljs b/src/status_im/utils/datetime.cljs index bb8457489f..da2c2191a5 100644 --- a/src/status_im/utils/datetime.cljs +++ b/src/status_im/utils/datetime.cljs @@ -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 %))