add api & architecture section

This commit is contained in:
Iuri Matias 2021-05-21 12:27:39 -04:00
parent a40d2b1e74
commit 64b4db1940
9 changed files with 356 additions and 5 deletions

View File

@ -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>"

View File

@ -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
--- ---

View File

@ -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
---

View File

@ -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.

View File

@ -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`

View File

@ -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

View File

@ -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

View File

@ -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..

View File

@ -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.