add api & architecture section
This commit is contained in:
parent
a40d2b1e74
commit
64b4db1940
|
@ -105,10 +105,28 @@
|
||||||
weight = 11
|
weight = 11
|
||||||
|
|
||||||
[[main]]
|
[[main]]
|
||||||
name = "APIs"
|
name = "Architecture & APIs"
|
||||||
url = "/api/"
|
url = "/api/intro/intro"
|
||||||
weight = 20
|
weight = 20
|
||||||
|
|
||||||
|
[[api]]
|
||||||
|
name = "Intro"
|
||||||
|
identifier = "intro"
|
||||||
|
url = "/api/qml"
|
||||||
|
weight = 10
|
||||||
|
|
||||||
|
[[api]]
|
||||||
|
name = "Architecture & Development"
|
||||||
|
identifier = "architecture_development"
|
||||||
|
url = "/api/architecture_development"
|
||||||
|
weight = 20
|
||||||
|
|
||||||
|
[[api]]
|
||||||
|
name = "QML"
|
||||||
|
identifier = "qml"
|
||||||
|
url = "/api/qml"
|
||||||
|
weight = 30
|
||||||
|
|
||||||
[[social]]
|
[[social]]
|
||||||
name = "Twitter"
|
name = "Twitter"
|
||||||
pre = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-twitter\"><path d=\"M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z\"></path></svg>"
|
pre = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-twitter\"><path d=\"M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z\"></path></svg>"
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
---
|
---
|
||||||
title : "APIs"
|
title : "Architecture & APIs"
|
||||||
description: "Docs Doks."
|
description: "Docs Doks."
|
||||||
lead: ""
|
lead: ""
|
||||||
date: 2020-10-06T08:48:23+00:00
|
date: 2020-10-06T08:48:23+00:00
|
||||||
lastmod: 2020-10-06T08:48:23+00:00
|
lastmod: 2020-10-06T08:48:23+00:00
|
||||||
draft: false
|
draft: false
|
||||||
images: []
|
images: []
|
||||||
|
weight: 30
|
||||||
---
|
---
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
title : "Architecture & Development"
|
||||||
|
description: "Architecture & Development"
|
||||||
|
lead: ""
|
||||||
|
date: 2020-10-06T08:48:23+00:00
|
||||||
|
lastmod: 2020-10-06T08:48:23+00:00
|
||||||
|
draft: false
|
||||||
|
images: []
|
||||||
|
toc: true
|
||||||
|
---
|
|
@ -0,0 +1,105 @@
|
||||||
|
---
|
||||||
|
title : "Common issues"
|
||||||
|
description: "Common issues"
|
||||||
|
lead: ""
|
||||||
|
date: 2020-10-06T08:48:23+00:00
|
||||||
|
lastmod: 2020-10-06T08:48:23+00:00
|
||||||
|
draft: false
|
||||||
|
images: []
|
||||||
|
menu:
|
||||||
|
api:
|
||||||
|
parent: "architecture_development"
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common errors and how to solve them
|
||||||
|
|
||||||
|
### SIGSEGV: Illegal storage access. (Attempt to read from nil?)
|
||||||
|
|
||||||
|
This happens due to using a null pointer, it can be caused by several situations:
|
||||||
|
|
||||||
|
**calling status-go with invalid parameters**
|
||||||
|
|
||||||
|
Calling status-go with a json that is missing a field somewhere can cause status-go to crash somewhere or throw an exception that is not being caught
|
||||||
|
|
||||||
|
**listening for non existing events**
|
||||||
|
|
||||||
|
If an event in which a corresponding `emit` does not exist, it can cause this error
|
||||||
|
|
||||||
|
```nimrod=
|
||||||
|
events.on("event-does-not-exist") do(a: Args):
|
||||||
|
appState.addChannel("test")
|
||||||
|
appState.addChannel("test2")
|
||||||
|
```
|
||||||
|
|
||||||
|
**parsing json**
|
||||||
|
|
||||||
|
when working with json, this error could be triggered for several reasons
|
||||||
|
* accessing a property that doesn't exist
|
||||||
|
* get the value type that doesn't match the value in the json
|
||||||
|
* `if payload["contentType"].str == 2:` will crash because the value of contentType is `2` not `"2"`
|
||||||
|
* something extracting a string with `value.str` instead of `$value` (sometimes `.getStr`)
|
||||||
|
|
||||||
|
### Error: attempting to call undeclared routine
|
||||||
|
|
||||||
|
this happens due something missing in the QTObject, it's caused for when a proc is not marked as a slot, not being public, not part of a variant, missing the self attribute or not mapped in a qproperty if it is an accesor
|
||||||
|
|
||||||
|
*TODO: add practical examples*
|
||||||
|
|
||||||
|
### Unsupported conversion of X to metatype
|
||||||
|
|
||||||
|
this can happen due to a method being exposed to QT as a slot but using an object (like a model X) that is not a QtObject.
|
||||||
|
possible solutions:
|
||||||
|
- make the object a QtObject (usually only recommended if it's in the view only)
|
||||||
|
- remove the {.slot.} pragma if it's not being called from QML anyway
|
||||||
|
- change the method to receive params individually and then build the model inside the method
|
||||||
|
|
||||||
|
### typeless parameters are obsolete
|
||||||
|
|
||||||
|
typically means types are missing for a method parameters
|
||||||
|
|
||||||
|
### attempting to call undeclared routine
|
||||||
|
|
||||||
|
routine is likely not public or is being declared after the method calling it
|
||||||
|
|
||||||
|
### QML Invalid component body specification
|
||||||
|
|
||||||
|
This error happens when a `Component` has multiple children, it must only contain one child, to fix it, put the component children inside a `Item {}`
|
||||||
|
|
||||||
|
### QML TypeError: Property 'setFunctionName' of object SomeView(0x7fa4bf55b240) is not a function
|
||||||
|
|
||||||
|
Likely the function is missing a `{.slot.}` pragma
|
||||||
|
|
||||||
|
### QML input text value not being updated
|
||||||
|
|
||||||
|
If you are using an `Input` QML prop, to get the current value use `idName.TextField.text` instead of `idName.text`
|
||||||
|
|
||||||
|
### QMutex: destroying locked mutex
|
||||||
|
|
||||||
|
a common scenario this error can happen is when trying to immediatly access something in status-go when the app starts before the node is ready. it can also happen due to 2 threads attempting to call & change something from status-go at the same time
|
||||||
|
|
||||||
|
## Warnings
|
||||||
|
|
||||||
|
### QML anchor warnings
|
||||||
|
|
||||||
|
Those look like
|
||||||
|
```
|
||||||
|
Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column. Column will not function.
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```
|
||||||
|
Detected anchors on an item that is managed by a layout. This is undefined behavior; use Layout.alignment instead.
|
||||||
|
```
|
||||||
|
|
||||||
|
Those mean that you used anchors on an element that is manged by a Layout. Those are ColumnLayouts, StackLayouts, etc.
|
||||||
|
|
||||||
|
The first child of anything in a "Something"Layout will not have access to anchors (they will throw warnings).
|
||||||
|
|
||||||
|
First thing to ask yourself, do you really need a Layout? That's the easiest way to fix it. Unless you really need your block to be a row or a column that needs to go next/under another, use an Item or similar. Usually, you can still do the same effect anyway with anchors on the siblings
|
||||||
|
|
||||||
|
If you really need the Layout, then one way to fix is to set the first child of the Layout an `Item` and then every other child inside the `Item`. That way, all the children can use anchors. You can set
|
||||||
|
```
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
```
|
||||||
|
on the `Item` to make it fill the whole parent so that nothing else needs to be changed.
|
|
@ -0,0 +1,118 @@
|
||||||
|
---
|
||||||
|
title : "Folder Structure"
|
||||||
|
description: "Folder Structure"
|
||||||
|
lead: ""
|
||||||
|
date: 2020-10-06T08:48:23+00:00
|
||||||
|
lastmod: 2020-10-06T08:48:23+00:00
|
||||||
|
draft: false
|
||||||
|
images: []
|
||||||
|
menu:
|
||||||
|
api:
|
||||||
|
parent: "architecture_development"
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
|
||||||
|
* 1. status-go (`src/status/libstatus`)
|
||||||
|
* 2. nim-status / business logic & persistence (`src/status`)
|
||||||
|
* 3. initializer wrapper (`src/app/<module>/core.nim`)
|
||||||
|
* currently contains signals which should be moved into layer 2.
|
||||||
|
* 4. views & view logic (`src/app/<module>/view.nim` & `ui/*.qml`)
|
||||||
|
|
||||||
|
## Folder structure
|
||||||
|
|
||||||
|
`src/` - where most of the source is
|
||||||
|
|
||||||
|
`src/app` - Where the Application is
|
||||||
|
|
||||||
|
`src/app/<module>` - module e.g 'chat', 'profile'
|
||||||
|
|
||||||
|
`src/app/<module>/core.nim` - wrapper for this module
|
||||||
|
|
||||||
|
`src/app/<module>/view.nim` - view, exposed data and some view specific logic
|
||||||
|
|
||||||
|
`src/app/<module>/views/*` - views
|
||||||
|
|
||||||
|
`src/signals` - signals (should be refactored & moved into src/status)
|
||||||
|
|
||||||
|
`src/status` - business logic
|
||||||
|
|
||||||
|
`src/status/libstatus` - integration with status-go
|
||||||
|
|
||||||
|
`nim_status_client.nim` - the main file
|
||||||
|
|
||||||
|
`ui/` - QML files
|
||||||
|
|
||||||
|
### **`src/status`**
|
||||||
|
|
||||||
|
This folder contains the library that abstracts the status app business logic, it's how the app can interact with status-go as well as how they can obtain data, do actions etc..
|
||||||
|
|
||||||
|
* this folder can only import / call files from `src/status/libstatus` (exception for libraries ofc)
|
||||||
|
* only files in `app/` should be able to import from `src/status` (but never `src/status/libstatus`)
|
||||||
|
|
||||||
|
### **`src/status/libstatus`**
|
||||||
|
|
||||||
|
This folder abstracts the interactions with status-go
|
||||||
|
|
||||||
|
* generally this folder should only contain code related to interacting with status-go
|
||||||
|
* it should not import code from anywhere else (including `src/status`)
|
||||||
|
* nothing should call libstatus directly
|
||||||
|
* only the code in `status/` should be able to import / call files in `src/status/libstatus`
|
||||||
|
|
||||||
|
### **`src/app`**
|
||||||
|
|
||||||
|
This folder contains the code related to each section of the app, generally it should be kept to a minimum amount of logic, *it knows what to do, but not how to do it*
|
||||||
|
|
||||||
|
### **`src/app/<module>/`**
|
||||||
|
|
||||||
|
* each `<module>` folder inside `app/` should correspond to a section in the app (exception for the `onboarding/` and `login/` currently)
|
||||||
|
* there should be no new folders here unless we are adding a brand new section to the sidebar
|
||||||
|
* files inside a `<module>` should not import files from another `<module>`
|
||||||
|
* while the code here can react to events emited by nim-status (`src/status`) it should not be able to emit events
|
||||||
|
|
||||||
|
### **`src/app/<module>/core.nim`**
|
||||||
|
|
||||||
|
This file is the controller of this module, the general structure of controller is typically predictable and always the same
|
||||||
|
|
||||||
|
* it imports a view
|
||||||
|
* it imports the nim-status lib
|
||||||
|
* it contains an `init` method
|
||||||
|
* it exposes a QVariant
|
||||||
|
|
||||||
|
the constructor has typically the following structure
|
||||||
|
|
||||||
|
```nimrod=
|
||||||
|
type NodeController* = ref object of SignalSubscriber
|
||||||
|
status*: Status
|
||||||
|
view*: NodeView
|
||||||
|
variant*: QVariant
|
||||||
|
|
||||||
|
proc newController*(status: Status): NodeController =
|
||||||
|
result = NodeController()
|
||||||
|
result.status = status
|
||||||
|
result.view = newNodeView(status)
|
||||||
|
result.variant = newQVariant(result.view)
|
||||||
|
|
||||||
|
method onSignal(self: NodeController, data: Signal) =
|
||||||
|
var msg = cast[WalletSignal](data)
|
||||||
|
# Do something with the signal...
|
||||||
|
```
|
||||||
|
|
||||||
|
* with the exception of `src/status/` and its own files within `src/app/<module>` (i.e the views), a controller should **not** import files from anywhere else (including other files inside `app/`)
|
||||||
|
|
||||||
|
### **`src/app/<module>/view.nim`**
|
||||||
|
|
||||||
|
This file contains the main QtObject for this `<module>` and exposes methods to interact with the views for the controller and QML.
|
||||||
|
|
||||||
|
* this file cannot import any other file except:
|
||||||
|
* other views within this `<module>`
|
||||||
|
* `src/status/` to use their types
|
||||||
|
* if there are multiple subviews, then they should go into the `views/` folder and initialized in this file.
|
||||||
|
|
||||||
|
## Future directions
|
||||||
|
|
||||||
|
* signals will be refactored/moved from core.nim files and `signals/` into `src/status/` and instead handle as events
|
||||||
|
* instead of importing `src/status/libstatus` in `src/status` files, we will do dependency injection, this allow us to more easily do unit tests, as well as transition from status-go to nimstatus
|
||||||
|
* `src/status` should be reanamed to `src/nim-status`
|
||||||
|
* `src/status/libstatus` should be renamed to `src/nim-status/status-go`
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
title : "Threads & Concurrency"
|
||||||
|
description: "Threads"
|
||||||
|
lead: ""
|
||||||
|
date: 2020-10-06T08:48:23+00:00
|
||||||
|
lastmod: 2020-10-06T08:48:23+00:00
|
||||||
|
draft: false
|
||||||
|
images: []
|
||||||
|
menu:
|
||||||
|
api:
|
||||||
|
parent: "architecture_development"
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
// TODO
|
|
@ -0,0 +1,71 @@
|
||||||
|
---
|
||||||
|
title : "Translation Scripts"
|
||||||
|
description: "How to use the translation scripts"
|
||||||
|
lead: ""
|
||||||
|
date: 2020-10-06T08:48:23+00:00
|
||||||
|
lastmod: 2020-10-06T08:48:23+00:00
|
||||||
|
draft: false
|
||||||
|
images: []
|
||||||
|
menu:
|
||||||
|
api:
|
||||||
|
parent: "architecture_development"
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
These scripts are used to translate the app automatically by reusing the existing translation found in the Status-React repo: https://github.com/status-im/status-react/tree/develop/translations
|
||||||
|
|
||||||
|
## TLDR
|
||||||
|
|
||||||
|
1. Copy the translation files from https://github.com/status-im/status-react/tree/develop/translations to `/nim-status-client/scripts/translationScripts/status-react-translations`
|
||||||
|
2. `cd scripts/translationScripts`
|
||||||
|
3. Run `npm install`
|
||||||
|
4. Run `node qstrConverter.js`
|
||||||
|
5. Open another terminal and `cd ui`
|
||||||
|
6. In that second terminal, run `lupdate nim-status-client.pro`
|
||||||
|
7. Back in the first terminal, run `node xmlTranslator.js`
|
||||||
|
7. [Optional] Manually translate the remaining strings in QT Linguist
|
||||||
|
9. In the second terminal, run `lrelease -idbased i18n/*.ts` in the `ui/` directory
|
||||||
|
|
||||||
|
:tada: You're files are converted to use `qsTrId` and the translation files are updated.
|
||||||
|
|
||||||
|
## Changing strings to IDs
|
||||||
|
|
||||||
|
One major step is to change the literal strings we use in the code base to the IDs that are used in the translation JSON files.
|
||||||
|
|
||||||
|
For example, in our QML files, we would use `qsTr("Public chat")`, but in Status-React, that string in only represented as `public-chat`.
|
||||||
|
|
||||||
|
Thankfully, QML supports using string IDs instead of literral strings. The trick is to use `qsTrId` instead of `qsTr` and then use a comment to show the context/original string.
|
||||||
|
|
||||||
|
The script to do the change from `qsTr` to `qsTrId` is `qstrConverter.js`.
|
||||||
|
|
||||||
|
First, copy the translation files from https://github.com/status-im/status-react/tree/develop/translations to `/nim-status-client/scripts/translationScripts/status-react-translations`. Those are gitignored to show that we do not maintain those ourselves.
|
||||||
|
|
||||||
|
Then, run `node qstrConverter.js` in the `translationScripts/` directory.
|
||||||
|
|
||||||
|
## Updating translation files
|
||||||
|
|
||||||
|
Updating the QML translation files is then very easy, as it comes with QT directly. It will scan all files in the projects (those listed in the `SOURCE` section of the `.pro` file) and then add or modify them in the XML-like `.ts` files.
|
||||||
|
|
||||||
|
Just run `lupdate nim-status-client.pro` in the `ui/` directory.
|
||||||
|
|
||||||
|
## Run XML translator script
|
||||||
|
|
||||||
|
Most translations are already done in Status-React. To add those translations to the right `.ts` file, run `node xmlTranslator.js` in the `translationScripts/` directory.
|
||||||
|
|
||||||
|
It will check all the TS files and get the good translation from the JSON file and set the translation as done.
|
||||||
|
|
||||||
|
Some translations will not be done, check the next section to know how to translate.
|
||||||
|
|
||||||
|
## Manually translate remaining strings
|
||||||
|
|
||||||
|
Since not all strings used in the desktop app are also used in Status-React, the remaining will need to be translated manually.
|
||||||
|
|
||||||
|
If the strings are not translated, it is not the end of the world, the English strings will be shown instead.
|
||||||
|
|
||||||
|
To do so, you can use QT Linguist to help with the process. Check here to see the Linguist docs: https://doc.qt.io/qt-5/linguist-translators.html
|
||||||
|
|
||||||
|
To open a TS file in QT Linguist, either open the software and use the `Open` feature it has, or go in the `ui/i18n` directory and run `linguist nameOfFile.ts`
|
||||||
|
|
||||||
|
## Generating binary translation files
|
||||||
|
|
||||||
|
To have the final translation files that will be used by the app, just run `lrelease -idbased i18n/*.ts` in the `ui/` directory
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
title : "Intro"
|
||||||
|
description: "Intro"
|
||||||
|
lead: ""
|
||||||
|
date: 2020-10-06T08:48:23+00:00
|
||||||
|
lastmod: 2020-10-06T08:48:23+00:00
|
||||||
|
draft: false
|
||||||
|
images: []
|
||||||
|
menu:
|
||||||
|
api:
|
||||||
|
parent: "intro"
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
This section describes the Architecture & stack, documents APIs & describes how to implement specific things such as functionality that might need to be in a threadpool, adding new sections to the app, etc..
|
|
@ -18,8 +18,6 @@ The wallet model (exposed as `chatsModel`) is used for functions pertaining to c
|
||||||
|
|
||||||
Methods can be invoked by calling them directly on the `chatsModel`, ie `chatsModel.getOldestMessageTimestamp()`.
|
Methods can be invoked by calling them directly on the `chatsModel`, ie `chatsModel.getOldestMessageTimestamp()`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### `getOldestMessageTimestamp()` : `QVariant<int64>`
|
#### `getOldestMessageTimestamp()` : `QVariant<int64>`
|
||||||
|
|
||||||
Returns the last set UNIX timestamp of the oldest message. See `setLastMessageTimestamp` for logic on how this is determined.
|
Returns the last set UNIX timestamp of the oldest message. See `setLastMessageTimestamp` for logic on how this is determined.
|
||||||
|
|
Loading…
Reference in New Issue