From beb5f1520fad669fe66ecc44dc2a8cb8b3e93feb Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Mon, 18 May 2020 11:07:30 -0400 Subject: [PATCH] feat: signal handling --- src/app/application/applicationView.nim | 38 --------------- src/app/signals/core.nim | 65 +++++++++++++++++++++++++ src/app/signals/signalSubscriber.nim | 5 ++ src/app/wallet/core.nim | 7 ++- src/nim_status_client.nim | 19 ++++---- ui/main.qml | 52 +++++++++++++++----- 6 files changed, 126 insertions(+), 60 deletions(-) delete mode 100644 src/app/application/applicationView.nim create mode 100644 src/app/signals/core.nim create mode 100644 src/app/signals/signalSubscriber.nim diff --git a/src/app/application/applicationView.nim b/src/app/application/applicationView.nim deleted file mode 100644 index 580e7889b8..0000000000 --- a/src/app/application/applicationView.nim +++ /dev/null @@ -1,38 +0,0 @@ -import NimQml - -# Probably all QT classes will look like this: -QtObject: - type ApplicationView* = ref object of QObject - app: QApplication - lastMessage: string - - # Constructor - proc newApplicationView*(app: QApplication): ApplicationView = - new(result) - result.app = app - result.lastMessage = "" - result.setup() - - proc setup(self: ApplicationView) = - self.QObject.setup - - proc delete*(self: ApplicationView) = - self.QObject.delete - - proc onExitTriggered(self: ApplicationView) {.slot.} = - echo "exiting..." - self.app.quit - - proc lastMessage*(self: ApplicationView): string {.slot.} = - result = self.lastMessage - - proc receivedMessage*(self: ApplicationView, lastMessage: string) {.signal.} - - proc setLastMessage(self: ApplicationView, lastMessage: string) {.slot.} = - self.lastMessage = lastMessage - self.receivedMessage(lastMessage) - - QtProperty[string] lastMessage: - read = lastMessage - write = setLastMessage - notify = receivedMessage diff --git a/src/app/signals/core.nim b/src/app/signals/core.nim new file mode 100644 index 0000000000..48298aae74 --- /dev/null +++ b/src/app/signals/core.nim @@ -0,0 +1,65 @@ +import NimQml +import ../../status/types as types +import tables +import json +import signalSubscriber + +QtObject: + type SignalsController* = ref object of QObject + app: QApplication + statusSignal: string + signalSubscribers*: Table[SignalType, SignalSubscriber] + variant*: QVariant + + # Constructor + proc newController*(app: QApplication): SignalsController = + new(result) + result.app = app + result.statusSignal = "" + result.signalSubscribers = initTable[SignalType, SignalSubscriber]() + result.setup() + result.variant = newQVariant(result) + + + proc setup(self: SignalsController) = + self.QObject.setup + + proc init*(self: SignalsController) = + discard + + proc delete*(self: SignalsController) = + self.QObject.delete + + proc addSubscriber*(self: SignalsController, signalType: SignalType, subscriber: SignalSubscriber) = + self.signalSubscribers[signalType] = subscriber + + proc processSignal(self: SignalsController) = + let jsonSignal = (self.statusSignal).parseJson + let signalType = $jsonSignal["type"].getStr + + # TODO: ideally the signal would receive an object + # formatted for easier usage so the controllers dont + # have to parse the signal themselves + case signalType: + of "messages.new": + self.signalSubscribers[SignalType.Message].onSignal($jsonSignal) + of "wallet": + self.signalSubscribers[SignalType.Wallet].onSignal($jsonSignal) + else: + # TODO: log error? + discard + + proc statusSignal*(self: SignalsController): string {.slot.} = + result = self.statusSignal + + proc signalReceived*(self: SignalsController, signal: string) {.signal.} + + proc receiveSignal(self: SignalsController, signal: string) {.slot.} = + self.statusSignal = signal + self.processSignal() + self.signalReceived(signal) + + QtProperty[string] statusSignal: + read = statusSignal + write = receiveSignal + notify = signalReceived \ No newline at end of file diff --git a/src/app/signals/signalSubscriber.nim b/src/app/signals/signalSubscriber.nim new file mode 100644 index 0000000000..edeff2235f --- /dev/null +++ b/src/app/signals/signalSubscriber.nim @@ -0,0 +1,5 @@ +type SignalSubscriber* = ref object of RootObj + +# Override this method +method onSignal*(self: SignalSubscriber, signal: string) {.base.} = + echo "Received a signal: ", signal # TODO: log signal received \ No newline at end of file diff --git a/src/app/wallet/core.nim b/src/app/wallet/core.nim index e9aad143e1..ae364be217 100644 --- a/src/app/wallet/core.nim +++ b/src/app/wallet/core.nim @@ -4,8 +4,9 @@ import strutils import walletView import ../../status/wallet as status_wallet +import ../signals/signalSubscriber -type WalletController* = ref object +type WalletController* = ref object of SignalSubscriber view*: WalletView variant*: QVariant @@ -38,3 +39,7 @@ proc init*(self: WalletController) = let symbol = "ETH" self.view.addAssetToList("Ethereum", symbol, fmt"{eth_value:.6}", "$" & fmt"{usd_balance:.6}", fmt"../../img/token-icons/{toLowerAscii(symbol)}.svg") + +method onSignal(self: WalletController, signal: string) = + echo "Received a signal in the wallet module: ", signal + # TODO: do something with the signal \ No newline at end of file diff --git a/src/nim_status_client.nim b/src/nim_status_client.nim index 73346fa09d..c5811fcb4e 100644 --- a/src/nim_status_client.nim +++ b/src/nim_status_client.nim @@ -1,8 +1,8 @@ import NimQml -import app/application/applicationView import app/chat/core as chat import app/wallet/core as wallet import app/node/core as node +import app/signals/core as signals import state import strformat import strutils @@ -24,8 +24,9 @@ import state # Global variables required due to issue described on line 75 var app = newQApplication() -var logic = newApplicationView(app) -var logicQObjPointer = cast[pointer](logic.vptr) + +var signalController = signals.newController(app) +var signalsQObjPointer = cast[pointer](signalController.vptr) proc mainProc() = defer: app.delete() # Defer will run this just before mainProc() function ends @@ -41,11 +42,6 @@ proc mainProc() = status_test.setupNewAccount() - let logicVariant = newQVariant(logic) - defer: logic.delete - defer: logicVariant.delete - engine.setRootContextProperty("logic", logicVariant) - var wallet = wallet.newController() wallet.init() engine.setRootContextProperty("assetsModel", wallet.variant) @@ -58,6 +54,11 @@ proc mainProc() = node.init() engine.setRootContextProperty("nodeModel", node.variant) + + signalController.init() + signalController.addSubscriber(SignalType.Wallet, wallet) + engine.setRootContextProperty("signals", signalController.variant) + appState.subscribe(proc () = # chatsModel.names = @[] for channel in appState.channels: @@ -84,7 +85,7 @@ proc mainProc() = # using global variables var callback:SignalCallback = proc(p0: cstring) {.cdecl.} = setupForeignThreadGc() - signal_handler(logicQObjPointer, p0, "setLastMessage") + signal_handler(signalsQObjPointer, p0, "receiveSignal") tearDownForeignThreadGc() libstatus.setSignalEventCallback(callback) diff --git a/ui/main.qml b/ui/main.qml index 9254d52342..02781aeee8 100644 --- a/ui/main.qml +++ b/ui/main.qml @@ -5,7 +5,6 @@ import Qt.labs.platform 1.1 import "./onboarding" import "./app" - ApplicationWindow { id: applicationWindow width: 1232 @@ -13,17 +12,46 @@ ApplicationWindow { title: "Nim Status Client" visible: true font.family: "Inter" - - - Text { - id: element - x: 772 - text: logic.lastMessage - anchors.top: parent.top - anchors.topMargin: 17 - font.bold: true - anchors.horizontalCenter: parent.horizontalCenter - font.pixelSize: 17 + + SystemTrayIcon { + visible: true + icon.source: "shared/img/status-logo.png" + menu: Menu { + MenuItem { + text: qsTr("Quit") + onTriggered: Qt.quit() + } + } + + onActivated: { + applicationWindow.show() + applicationWindow.raise() + applicationWindow.requestActivate() + } + } + + Rectangle { + id: rctAppBg + color: "#FFFFFF" + Layout.fillHeight: true + Layout.fillWidth: true + anchors.fill: parent + border.width: 0 + + Intro { + id: onboarding + visible: !app.visible + anchors.fill: parent + } + + AppMain { + id: app + // TODO: Set this to a logic result determining when we need to show the onboarding screens + // Set to true to hide the onboarding screens manually + // Set to false to show the onboarding screens manually + visible: false // logic.accountResult !== "" + anchors.fill: parent + } } }