diff --git a/.gitmodules b/.gitmodules index 328917fc6a..b5454b7e5c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,6 @@ -[submodule "vendor/DOtherSide"] - path = vendor/DOtherSide - url = https://github.com/filcuc/DOtherSide [submodule "vendor/nim-stint"] path = vendor/nim-stint url = https://github.com/status-im/nim-stint -[submodule "vendor/nimqml"] - path = vendor/nimqml - url = https://github.com/filcuc/nimqml/ [submodule "vendor/nimbus-build-system"] path = vendor/nimbus-build-system url = https://github.com/status-im/nimbus-build-system @@ -19,3 +13,9 @@ [submodule "vendor/status-go"] path = vendor/status-go url = https://github.com/status-im/status-go +[submodule "vendor/DOtherSide"] + path = vendor/DOtherSide + url = https://github.com/status-im/DOtherSide +[submodule "vendor/nimqml"] + path = vendor/nimqml + url = https://github.com/status-im/nimqml diff --git a/src/app/application/applicationView.nim b/src/app/application/applicationView.nim index f13222ab68..580e7889b8 100644 --- a/src/app/application/applicationView.nim +++ b/src/app/application/applicationView.nim @@ -4,11 +4,13 @@ import NimQml 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) = @@ -20,3 +22,17 @@ QtObject: 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/nim_status_client.nim b/src/nim_status_client.nim index f56630e3e0..73346fa09d 100644 --- a/src/nim_status_client.nim +++ b/src/nim_status_client.nim @@ -4,19 +4,30 @@ import app/chat/core as chat import app/wallet/core as wallet import app/node/core as node import state - +import strformat +import strutils import status/core as status -# import status/chat as status_chat +import status/chat as status_chat import status/test as status_test -import status/types +import status/types as types +import status/wallet as status_wallet +import status/libstatus +import state + + + +# From QT docs: +# For any GUI application using Qt, there is precisely one QApplication object, +# no matter whether the application has 0, 1, 2 or more windows at any given time. +# For non-QWidget based Qt applications, use QGuiApplication instead, as it does +# not depend on the QtWidgets library. Use QCoreApplication for non GUI apps + +# Global variables required due to issue described on line 75 +var app = newQApplication() +var logic = newApplicationView(app) +var logicQObjPointer = cast[pointer](logic.vptr) proc mainProc() = - # From QT docs: - # For any GUI application using Qt, there is precisely one QApplication object, - # no matter whether the application has 0, 1, 2 or more windows at any given time. - # For non-QWidget based Qt applications, use QGuiApplication instead, as it does - # not depend on the QtWidgets library. Use QCoreApplication for non GUI apps - var app = newQApplication() defer: app.delete() # Defer will run this just before mainProc() function ends var engine = newQQmlApplicationEngine() @@ -25,16 +36,15 @@ proc mainProc() = var appState = state.newAppState() echo appState.title - status.init(appState) + # TODO: @RR: commented until I'm able to fix the global variable issue described below + #status.init(appState) status_test.setupNewAccount() - discard status_test.addPeer("enode://2c8de3cbb27a3d30cbb5b3e003bc722b126f5aef82e2052aaef032ca94e0c7ad219e533ba88c70585ebd802de206693255335b100307645ab5170e88620d2a81@47.244.221.14:443") - echo status.callPrivateRPC("{\"jsonrpc\":\"2.0\", \"method\":\"wakuext_requestMessages\", \"params\":[{\"topics\": [\"0x7998f3c8\"]}], \"id\": 1}") - let applicationView = newApplicationView(app) - defer: applicationView.delete - - status.startMessenger() + let logicVariant = newQVariant(logic) + defer: logic.delete + defer: logicVariant.delete + engine.setRootContextProperty("logic", logicVariant) var wallet = wallet.newController() wallet.init() @@ -48,8 +58,6 @@ proc mainProc() = node.init() engine.setRootContextProperty("nodeModel", node.variant) - engine.load("../ui/main.qml") - appState.subscribe(proc () = # chatsModel.names = @[] for channel in appState.channels: @@ -60,16 +68,27 @@ proc mainProc() = appState.addChannel("test") appState.addChannel("test2") + + engine.load("../ui/main.qml") + - # EXAMPLE: this will be triggered once a message is received - appState.onSignal(SignalType.Message, proc(myMessage: string): void = - echo "I received a message: ", myMessage - ); + # In order for status-go to be able to trigger QT events + # the signal handler must work with the same pointers + # and use the cdecl pragma. If I remove this pragma and use + # a normal closure and the `logic` object, the pointer to + # this `logic` changes each time the callback is executed + # I also had to use a global variable, because Nim complains + # "illegal capture 'logicQObjPointer' because ':anonymous' + # has the calling convention: " + # TODO: ask nimbus team how to work with raw pointers to avoid + # using global variables + var callback:SignalCallback = proc(p0: cstring) {.cdecl.} = + setupForeignThreadGc() + signal_handler(logicQObjPointer, p0, "setLastMessage") + tearDownForeignThreadGc() - # Handle signals as part of the state - var signalWorker: Thread[AppState] - signalWorker.createThread(proc(s:AppState) = s.processSignals, appState) - defer: signalWorker.joinThread() + libstatus.setSignalEventCallback(callback) + # Qt main event loop is entered here # The termination of the loop will be performed when exit() or quit() is called diff --git a/src/state.nim b/src/state.nim index 7c68ce277b..f214129b0e 100644 --- a/src/state.nim +++ b/src/state.nim @@ -11,27 +11,13 @@ type Subscriber* = proc () - SignalSubscriber* = proc(p0: string) - - Signal = object - signalType*: SignalType - content*: string - -var signalChannel: Channel[Signal] - type AppState* = ref object title*: string channels*: seq[ChatChannel] subscribers*: seq[Subscriber] - signalSubscribers*: Table[SignalType, seq[SignalSubscriber]] - proc newAppState*(): AppState = - result = AppState( - title: "hello", - signalSubscribers: initTable[SignalType, seq[SignalSubscriber]]() - ) - signalChannel.open() + result = AppState(title: "hello") proc subscribe*(self: AppState, subscriber: Subscriber) = self.subscribers.add(subscriber) @@ -43,35 +29,3 @@ proc dispatch*(self: AppState) = proc addChannel*(self: AppState, name: string) = self.channels.add(ChatChannel(name: name)) self.dispatch() - -##################### -# Signal Handling - -proc processSignals*(self: AppState) = - ## Polls the signal channel and push the message to each subscriber - {.gcsafe.}: - while(true): - let tried = signalChannel.tryRecv() - if tried.dataAvailable and self.signalSubscribers.hasKey(tried.msg.signalType): - for subscriber in self.signalSubscribers[tried.msg.signalType]: - subscriber(tried.msg.content) - defer: - signalChannel.close() - -proc addToChannel(s: Signal) {.thread.} = - signalChannel.send(s) - -proc nextSignal*(self: AppState, signalType: SignalType, jsonMessage: string) = - ## This is called by the signal handler for each signal received and - ## adds it to the signal channel for being consumed by the SignalSubscribers - let signal: Signal = Signal(signalType: signalType, content: jsonMessage) - var worker: Thread[Signal] - createThread(worker, addToChannel, signal) - worker.joinThread() - -proc onSignal*(self: AppState, signalType: SignalType, subscriber: SignalSubscriber) = - ## Register a callback that will be executed once - ## a signal is received from status-go - if not self.signalSubscribers.hasKey(signalType): - self.signalSubscribers[signalType] = @[] - self.signalSubscribers[signalType].add(subscriber) \ No newline at end of file diff --git a/src/status/core.nim b/src/status/core.nim index c4953ba669..85ec2689e8 100644 --- a/src/status/core.nim +++ b/src/status/core.nim @@ -1,14 +1,9 @@ import libstatus -import signals -import types import chat -import "../state" -proc setSignalHandler(signalHandler: SignalCallback) = - libstatus.setSignalEventCallback(signalHandler) - -proc init*(state: AppState) = - setSignalHandler(onSignal(state)) +# TODO: move signal handler from nim_status_client.nim +# proc init*(state: AppState) = +# setSignalHandler(onSignal(state)) proc startMessenger*() = chat.startMessenger() diff --git a/src/status/signals.nim b/src/status/signals.nim deleted file mode 100644 index 16191d3918..0000000000 --- a/src/status/signals.nim +++ /dev/null @@ -1,21 +0,0 @@ -import types -import json -import "../state" as state - -proc onSignal*(state: AppState): SignalCallback = - result = proc(p0: cstring): void = - setupForeignThreadGc() - let jsonSignal = ($p0).parseJson - let signalType = $jsonSignal["type"].getStr - - # TODO: ideally the signal would receive an object - # formatted for easier usage - case signalType: - of "messages.new": - state.nextSignal(SignalType.Message, $jsonSignal) - else: - state.nextSignal(SignalType.Unknown, $jsonSignal) - - - tearDownForeignThreadGc() - diff --git a/src/status/types.nim b/src/status/types.nim index a8d9eb4a5a..2c52fd35d9 100644 --- a/src/status/types.nim +++ b/src/status/types.nim @@ -1,4 +1,4 @@ -type SignalCallback* = proc(eventMessage: cstring): void +type SignalCallback* = proc(eventMessage: cstring): void {.cdecl.} type SignalType* {.pure.} = enum Message = "messages.new" diff --git a/ui/main.qml b/ui/main.qml index 02781aeee8..9254d52342 100644 --- a/ui/main.qml +++ b/ui/main.qml @@ -5,6 +5,7 @@ import Qt.labs.platform 1.1 import "./onboarding" import "./app" + ApplicationWindow { id: applicationWindow width: 1232 @@ -12,46 +13,17 @@ ApplicationWindow { title: "Nim Status Client" visible: true font.family: "Inter" - - 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 - } + + + 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 } } diff --git a/vendor/DOtherSide b/vendor/DOtherSide index 4d0d6a353c..c520b8e969 160000 --- a/vendor/DOtherSide +++ b/vendor/DOtherSide @@ -1 +1 @@ -Subproject commit 4d0d6a353c33ff2227b83562a127b3514a7e2169 +Subproject commit c520b8e969fd3b9a960c27b73c05cf8eb511ae04 diff --git a/vendor/nimqml b/vendor/nimqml index 5c42890e5b..79025e4687 160000 --- a/vendor/nimqml +++ b/vendor/nimqml @@ -1 +1 @@ -Subproject commit 5c42890e5b14b7d84a2345b060d1b54bfb7aed1b +Subproject commit 79025e4687692bdda8c2364b212c4bd539c4156e