feat: Onboarding carousel
Onboarding carousel completed Redo folder restructuring NOTES: 1. nim_status_client binary is output to `./bin/nim_status_client`, so you'll need to update your workflow to run this file. README has been updated to reflect this. Also, if you're running VSCode, instructions for code reload were added. 2. All `ui` files now live in `ui/` 3. All lib files (ie `libstatus`) now live in `lib/` 4. Removed the Qt Creater user project file as this is unique to each user 5. Moved the project file to `ui/`, so just open up the `ui` folder in Qt creator and it should locate the project file 6. `-d:release` removed from compilation as it wasn't needed 7. Broke up main.qml in to the main app and onboarding components, however this should be broken down further into more reusable components 8. Click "Get started" to show chat Format some files using nimpretty
|
@ -6,3 +6,6 @@ data/
|
|||
noBackup/
|
||||
.idea
|
||||
*.pro.user
|
||||
*.pro.autosave
|
||||
.vscode
|
||||
bin/
|
4
Makefile
|
@ -1,7 +1,7 @@
|
|||
SHELL := bash
|
||||
|
||||
build:
|
||||
nim c -d:release -L:libstatus.a -L:-lm --outdir:. src/nim_status_client.nim
|
||||
nim c -L:lib/libstatus.a -L:-lm --outdir:./bin src/nim_status_client.nim
|
||||
|
||||
build-osx:
|
||||
nim c -d:release -L:libstatus.dylib -L:-lm -L:"-framework Foundation -framework Security -framework IOKit -framework CoreServices" --outdir:. src/nim_status_client.nim
|
||||
nim c -L:lib/libstatus.dylib -L:-lm -L:"-framework Foundation -framework Security -framework IOKit -framework CoreServices" --outdir:./bin src/nim_status_client.nim
|
||||
|
|
67
README.md
|
@ -25,6 +25,7 @@ export PATH=$PATH:/path/to/Qt/5.14.2/clang_64/bin
|
|||
### 3. Clone and build DOtherside
|
||||
|
||||
For Linux:
|
||||
|
||||
```
|
||||
sudo apt-get install build-essential libgl1-mesa-dev
|
||||
sudo apt-get install doxygen
|
||||
|
@ -70,5 +71,69 @@ make build-osx
|
|||
### 8. Run the app
|
||||
|
||||
```
|
||||
./nim_status_client
|
||||
./bin/nim_status_client
|
||||
```
|
||||
|
||||
### 9. "Cold" reload using VSCode
|
||||
|
||||
We can setup a "cold" reload, whereby the app will be rebuilt and restarted when changes in the source are saved. This will not save state, as the app will be restarted, but it will save us some time from manually restarting the app. We can handily force an app rebuild/relaunch with the shortcut `Cmd+Shift+b` (execute the default build task, which we'll setup below).
|
||||
|
||||
To enable a meagre app reload during development, first creates a task in `.vscode/tasks.json`. This task sets up the default build task for the workspace, and depends on the task that compiles our nim:
|
||||
|
||||
```json
|
||||
({
|
||||
"label": "Build Nim Status Client",
|
||||
"type": "shell",
|
||||
"command": "nim",
|
||||
"args": [
|
||||
"c",
|
||||
"-L:lib/libstatus.dylib",
|
||||
"-L:-lm",
|
||||
"-L:\"-framework Foundation -framework Security -framework IOKit -framework CoreServices\"",
|
||||
"--outdir:./bin",
|
||||
"src/nim_status_client.nim"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceRoot}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Run nim_status_client",
|
||||
"type": "shell",
|
||||
"command": "bash",
|
||||
"args": ["./run.sh"],
|
||||
"options": {
|
||||
"cwd": "${workspaceRoot}/.vscode"
|
||||
},
|
||||
"dependsOn": ["Build Nim Status Client"],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Next, add a `.vscode/run.sh` file, changing the `DOtherSide` lib path to be specific to your environment:
|
||||
|
||||
```bash
|
||||
export LD_LIBRARY_PATH="/Users/emizzle/repos/github.com/filcuc/DOtherSide/build/lib"
|
||||
../bin/nim_status_client
|
||||
```
|
||||
|
||||
# Auto build on save (for the "cold" reload effect)
|
||||
|
||||
Finally, to get trigger this default build task when our files our saved, we need to enable a task to be run while `.nim` files are saved, and when `.qml` files are saved.
|
||||
|
||||
### Build on save
|
||||
|
||||
To build on save of our source files, first install the "Trigger Task on Save" VS Code extension to detect changes to our changable files, which will trigger a build/run. Once installed, update `settings.json` like so:
|
||||
|
||||
```json
|
||||
"files.autoSave": "afterDelay",
|
||||
"triggerTaskOnSave.tasks": {
|
||||
"Run nim_status_client": ["ui/**/*", "src/*.nim"]
|
||||
},
|
||||
"triggerTaskOnSave.restart": true,
|
||||
"triggerTaskOnSave.showStatusBarToggle": true
|
||||
|
||||
```
|
||||
|
|
602
main.qml
|
@ -1,602 +0,0 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.3
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
import Qt.labs.platform 1.1
|
||||
import "./imports"
|
||||
|
||||
ApplicationWindow {
|
||||
id: applicationWindow
|
||||
width: 1024
|
||||
height: 768
|
||||
title: "Nim Status Client"
|
||||
visible: true
|
||||
font.family: "Inter"
|
||||
|
||||
SystemTrayIcon {
|
||||
visible: true
|
||||
icon.source: "status-logo.png"
|
||||
|
||||
onActivated: {
|
||||
applicationWindow.show()
|
||||
applicationWindow.raise()
|
||||
applicationWindow.requestActivate()
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.fill: parent
|
||||
// spacing: 50
|
||||
|
||||
TabBar {
|
||||
id: tabBar
|
||||
y: 0
|
||||
width: 50
|
||||
height: width *2 + spacing
|
||||
Layout.preferredHeight: 0
|
||||
currentIndex: 0
|
||||
topPadding: 57
|
||||
rightPadding: 19
|
||||
leftPadding: 19
|
||||
transformOrigin: Item.Top
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillHeight: true
|
||||
anchors.top: parent.top
|
||||
spacing: 5
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: 80
|
||||
Layout.preferredWidth: 80
|
||||
Layout.maximumWidth: 80
|
||||
Layout.minimumHeight: 0
|
||||
background: Rectangle {
|
||||
color: "#00000000"
|
||||
border.color: Theme.grey
|
||||
}
|
||||
|
||||
TabButton {
|
||||
id: chatBtn
|
||||
x: 0
|
||||
width: 40
|
||||
height: 40
|
||||
text: ""
|
||||
padding: 0
|
||||
transformOrigin: Item.Center
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
background: Rectangle {
|
||||
color: Theme.lightBlue
|
||||
opacity: parent.checked ? 1 : 0
|
||||
radius: 50
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: parent.checked ? "img/messageActive.svg" : "img/message.svg"
|
||||
}
|
||||
}
|
||||
|
||||
TabButton {
|
||||
id: walletBtn
|
||||
width: 40
|
||||
height: 40
|
||||
text: ""
|
||||
anchors.topMargin: 50
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: chatBtn.top
|
||||
background: Rectangle {
|
||||
color: Theme.lightBlue
|
||||
opacity: parent.checked ? 1 : 0
|
||||
radius: 50
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image1
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: parent.checked ? "img/walletActive.svg" : "img/wallet.svg"
|
||||
}
|
||||
}
|
||||
|
||||
TabButton {
|
||||
id: browserBtn
|
||||
width: 40
|
||||
height: 40
|
||||
text: ""
|
||||
anchors.topMargin: 50
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: walletBtn.top
|
||||
background: Rectangle {
|
||||
color: Theme.lightBlue
|
||||
opacity: parent.checked ? 1 : 0
|
||||
radius: 50
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: parent.checked ? "img/compassActive.svg" : "img/compass.svg"
|
||||
}
|
||||
}
|
||||
|
||||
TabButton {
|
||||
id: profileBtn
|
||||
width: 40
|
||||
height: 40
|
||||
text: ""
|
||||
anchors.topMargin: 50
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: browserBtn.top
|
||||
background: Rectangle {
|
||||
color: Theme.lightBlue
|
||||
opacity: parent.checked ? 1 : 0
|
||||
radius: 50
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image3
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: parent.checked ? "img/profileActive.svg" : "img/profile.svg"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
width: parent.width
|
||||
Layout.fillWidth: true
|
||||
currentIndex: tabBar.currentIndex
|
||||
|
||||
SplitView {
|
||||
id: splitView
|
||||
x: 9
|
||||
y: 0
|
||||
Layout.fillHeight: true
|
||||
// anchors.fill: parent
|
||||
// width: parent.width
|
||||
Layout.leftMargin: 0
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: 100
|
||||
Layout.preferredWidth: 200
|
||||
// Layout.preferredHeight: 100
|
||||
|
||||
Item {
|
||||
id: element1
|
||||
width: 300
|
||||
height: parent.height
|
||||
Layout.minimumWidth: 200
|
||||
|
||||
ColumnLayout {
|
||||
anchors.rightMargin: 0
|
||||
anchors.fill: parent
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: 100
|
||||
Layout.fillHeight: false
|
||||
Layout.fillWidth: true
|
||||
|
||||
Text {
|
||||
id: element
|
||||
x: 772
|
||||
text: qsTr("Chat")
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 17
|
||||
font.bold: true
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.pixelSize: 17
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: searchBox
|
||||
height: 36
|
||||
color: Theme.grey
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 59
|
||||
radius: 8
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 65
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.padding
|
||||
|
||||
TextField {
|
||||
id: searchText
|
||||
placeholderText: qsTr("Search")
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 32
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: 12
|
||||
background: {
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image4
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.smallPadding
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "img/search.svg"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
onClicked : {
|
||||
searchText.forceActiveFocus(Qt.MouseFocusReason)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: addChat
|
||||
width: 36
|
||||
height: 36
|
||||
color: Theme.blue
|
||||
radius: 50
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.padding
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 59
|
||||
|
||||
Text {
|
||||
id: element3
|
||||
color: "#ffffff"
|
||||
text: qsTr("+")
|
||||
anchors.verticalCenterOffset: -1
|
||||
anchors.horizontalCenterOffset: 1
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
lineHeight: 1
|
||||
fontSizeMode: Text.FixedSize
|
||||
font.bold: true
|
||||
font.pixelSize: 28
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
Component {
|
||||
id: chatViewDelegate
|
||||
|
||||
Rectangle {
|
||||
id: wrapper
|
||||
height: 64
|
||||
color: ListView.isCurrentItem ? Theme.lightBlue : Theme.transparent
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.padding
|
||||
anchors.top: applicationWindow.top
|
||||
anchors.topMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.padding
|
||||
radius: 8
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: listView.currentIndex = index
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: contactImage
|
||||
width: 40
|
||||
color: Theme.darkGrey
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.padding
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 12
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 12
|
||||
radius: 50
|
||||
}
|
||||
|
||||
Text {
|
||||
id: contactInfo
|
||||
text: "Name:" + name
|
||||
font.weight: Font.Medium
|
||||
font.pixelSize: 15
|
||||
anchors.left: contactImage.right
|
||||
anchors.leftMargin: Theme.padding
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Theme.smallPadding
|
||||
color: "black"
|
||||
}
|
||||
Text {
|
||||
id: lastChatMessage
|
||||
text: "Chatting blah blah..."
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: Theme.smallPadding
|
||||
font.pixelSize: 15
|
||||
anchors.left: contactImage.right
|
||||
anchors.leftMargin: Theme.padding
|
||||
color: Theme.darkGrey
|
||||
}
|
||||
Text {
|
||||
id: contactTime
|
||||
text: "12:22 AM"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.padding
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Theme.smallPadding
|
||||
font.pixelSize: 11
|
||||
color: Theme.darkGrey
|
||||
}
|
||||
Rectangle {
|
||||
id: contactNumberChatsCircle
|
||||
width: 22
|
||||
height: 22
|
||||
radius: 50
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: Theme.smallPadding
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.padding
|
||||
color: Theme.blue
|
||||
Text {
|
||||
id: contactNumberChats
|
||||
text: qsTr("1")
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: "white"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
anchors.topMargin: 24
|
||||
anchors.fill: parent
|
||||
model: chatsModel
|
||||
delegate: chatViewDelegate
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width/2
|
||||
height: parent.height
|
||||
|
||||
ColumnLayout {
|
||||
anchors.rightMargin: 0
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout {
|
||||
id: chatContainer
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
|
||||
Rectangle {
|
||||
id: chatBox
|
||||
height: 140
|
||||
color: "#00000000"
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
border.color: "#00000000"
|
||||
|
||||
Image {
|
||||
id: chatImage
|
||||
width: 30
|
||||
height: 30
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 16
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 16
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "img/placeholder-profile.png"
|
||||
}
|
||||
|
||||
TextEdit {
|
||||
id: chatName
|
||||
text: qsTr("Slushy Welltodo Woodborer")
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 22
|
||||
anchors.left: chatImage.right
|
||||
anchors.leftMargin: 16
|
||||
font.bold: true
|
||||
font.pixelSize: 14
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
}
|
||||
|
||||
TextEdit {
|
||||
id: chatText
|
||||
text: qsTr("I’m generally against putting too many rules on social interaction because it makes interaction anything but social, but technical specifics on how to get on board or participate in a team are I think generally useful, especially if they prevent maintainers from pasting the same response to every PR / issue.")
|
||||
font.family: "Inter"
|
||||
wrapMode: Text.WordWrap
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 60
|
||||
anchors.left: chatName.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.top: chatName.bottom
|
||||
anchors.topMargin: 16
|
||||
font.pixelSize: 14
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
}
|
||||
|
||||
TextEdit {
|
||||
id: chatTime
|
||||
color: Theme.darkGrey
|
||||
font.family: "Inter"
|
||||
text: qsTr("7:30 AM")
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 16
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 16
|
||||
font.pixelSize: 10
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: separator
|
||||
height: 16
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
anchors.top: chatContainer.bottom
|
||||
anchors.topMargin: Theme.padding
|
||||
|
||||
Item {
|
||||
id: separatorContent
|
||||
width: 200
|
||||
height: 16
|
||||
Layout.fillHeight: false
|
||||
Layout.fillWidth: true
|
||||
|
||||
Rectangle {
|
||||
id: lineSeparator1
|
||||
height: 1
|
||||
color: "#00000000"
|
||||
border.color: "#eef2f5"
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 8
|
||||
anchors.right: separatorText.left
|
||||
anchors.rightMargin: 14
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 16
|
||||
}
|
||||
|
||||
Text {
|
||||
id: separatorText
|
||||
color: Theme.darkGrey
|
||||
text: qsTr("Yesterday")
|
||||
font.pixelSize: 12
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: lineSeparator2
|
||||
height: 1
|
||||
color: "#00000000"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 16
|
||||
anchors.left: separatorText.right
|
||||
border.color: "#eef2f5"
|
||||
anchors.top: parent.top
|
||||
anchors.leftMargin: 14
|
||||
anchors.topMargin: 8
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: resultContainer
|
||||
Layout.fillHeight: true
|
||||
TextArea { id: callResult; Layout.fillWidth: true; text: logic.callResult; readOnly: true }
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: chatInputContainer
|
||||
height: 70
|
||||
Layout.bottomMargin: 20
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignBottom
|
||||
transformOrigin: Item.Bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
|
||||
Item {
|
||||
id: element2
|
||||
width: 200
|
||||
height: 70
|
||||
Layout.fillWidth: true
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
color: "#00000000"
|
||||
border.color: Theme.grey
|
||||
anchors.fill: parent
|
||||
|
||||
Button {
|
||||
id: chatSendBtn
|
||||
x: 100
|
||||
width: 30
|
||||
height: 30
|
||||
text: "\u2191"
|
||||
font.bold: true
|
||||
font.pointSize: 12
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 20
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 16
|
||||
onClicked: logic.onSend(txtData.text)
|
||||
enabled: txtData.text !== ""
|
||||
background: Rectangle {
|
||||
color: parent.enabled ? Theme.blue : Theme.grey
|
||||
radius: 50
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: txtData
|
||||
text: ""
|
||||
leftPadding: 0
|
||||
padding: 0
|
||||
font.pixelSize: 14
|
||||
placeholderText: qsTr("Type a message...")
|
||||
anchors.right: chatSendBtn.left
|
||||
anchors.rightMargin: 16
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 24
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 24
|
||||
background: {}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea1
|
||||
anchors.rightMargin: 50
|
||||
anchors.fill: parent
|
||||
onClicked : {
|
||||
txtData.forceActiveFocus(Qt.MouseFocusReason)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout {
|
||||
Layout.fillHeight: true
|
||||
TextArea { id: accountResult; Layout.fillWidth: true; text: logic.accountResult; readOnly: true }
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;formeditorZoom:0.8999999761581421}D{i:61;anchors_height:100;anchors_width:100}
|
||||
}
|
||||
##^##*/
|
|
@ -3,17 +3,15 @@ import applicationView
|
|||
import chats
|
||||
import state
|
||||
import status
|
||||
import libstatus
|
||||
import json
|
||||
|
||||
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
|
||||
# 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
|
||||
defer: app.delete() # Defer will run this just before mainProc() function ends
|
||||
|
||||
var chatsModel = newChatsModel();
|
||||
defer: chatsModel.delete
|
||||
|
@ -32,7 +30,7 @@ proc mainProc() =
|
|||
|
||||
let logic = newApplicationView(app, status.callPrivateRPC)
|
||||
defer: logic.delete
|
||||
|
||||
|
||||
let logicVariant = newQVariant(logic)
|
||||
defer: logicVariant.delete
|
||||
|
||||
|
@ -54,8 +52,8 @@ proc mainProc() =
|
|||
|
||||
engine.setRootContextProperty("logic", logicVariant)
|
||||
engine.setRootContextProperty("chatsModel", chatsVariant)
|
||||
engine.load("main.qml")
|
||||
|
||||
engine.load("../ui/main.qml")
|
||||
|
||||
# Qt main event loop is entered here
|
||||
# The termination of the loop will be performed when exit() or quit() is called
|
||||
app.exec()
|
||||
|
|
220
src/status.nim
|
@ -39,50 +39,50 @@ proc subscribeToTest*() =
|
|||
var result = ""
|
||||
|
||||
var payload = %* {
|
||||
"jsonrpc": "2.0",
|
||||
"jsonrpc": "2.0",
|
||||
"id": 3,
|
||||
"method": "wakuext_startMessenger",
|
||||
"method": "wakuext_startMessenger",
|
||||
"params": []
|
||||
}
|
||||
result = $libstatus.callPrivateRPC($payload)
|
||||
|
||||
payload = %* {
|
||||
"jsonrpc": "2.0",
|
||||
"jsonrpc": "2.0",
|
||||
"id": 3,
|
||||
"method": "wakuext_loadFilters",
|
||||
"method": "wakuext_loadFilters",
|
||||
"params": [
|
||||
[{
|
||||
"ChatID":"test",
|
||||
"OneToOne":false
|
||||
"ChatID": "test",
|
||||
"OneToOne": false
|
||||
}]
|
||||
]
|
||||
}
|
||||
result = $libstatus.callPrivateRPC($payload)
|
||||
|
||||
payload = %* {
|
||||
"jsonrpc": "2.0",
|
||||
"jsonrpc": "2.0",
|
||||
"id": 4,
|
||||
"method": "wakuext_saveChat",
|
||||
"method": "wakuext_saveChat",
|
||||
"params": [
|
||||
{
|
||||
"lastClockValue":0,
|
||||
"color":"#51d0f0",
|
||||
"name":"test",
|
||||
"lastMessage":nil,
|
||||
"active":true,
|
||||
"id":"test",
|
||||
"unviewedMessagesCount":0,
|
||||
"chatType":2,
|
||||
"timestamp":1588940692659
|
||||
"lastClockValue": 0,
|
||||
"color": "#51d0f0",
|
||||
"name": "test",
|
||||
"lastMessage": nil,
|
||||
"active": true,
|
||||
"id": "test",
|
||||
"unviewedMessagesCount": 0,
|
||||
"chatType": 2,
|
||||
"timestamp": 1588940692659
|
||||
}
|
||||
]
|
||||
}
|
||||
result = $libstatus.callPrivateRPC($payload)
|
||||
|
||||
payload = %* {
|
||||
"jsonrpc": "2.0",
|
||||
"jsonrpc": "2.0",
|
||||
"id": 3,
|
||||
"method": "wakuext_chatMessages",
|
||||
"method": "wakuext_chatMessages",
|
||||
"params": [
|
||||
"test", nil, 20
|
||||
]
|
||||
|
@ -100,17 +100,18 @@ proc setupNewAccount*() =
|
|||
# 1
|
||||
result = $libstatus.initKeystore(keystoredir);
|
||||
|
||||
# 2
|
||||
# 2
|
||||
result = $libstatus.openAccounts(datadir);
|
||||
|
||||
|
||||
# 3
|
||||
let multiAccountConfig = %* {
|
||||
"n": 5,
|
||||
"mnemonicPhraseLength": 12,
|
||||
"bip39Passphrase": "",
|
||||
"bip39Passphrase": "",
|
||||
"paths": ["m/43'/60'/1581'/0'/0", "m/44'/60'/0'/0/0"]
|
||||
}
|
||||
result = $libstatus.multiAccountGenerateAndDeriveAddresses($multiAccountConfig);
|
||||
result = $libstatus.multiAccountGenerateAndDeriveAddresses(
|
||||
$multiAccountConfig);
|
||||
let generatedAddresses = result.parseJson
|
||||
let account0 = generatedAddresses[0]
|
||||
|
||||
|
@ -118,7 +119,8 @@ proc setupNewAccount*() =
|
|||
let password = "0x2cd9bf92c5e20b1b410f5ace94d963a96e89156fbe65b70365e8596b37f1f165" #qwerty
|
||||
let multiAccount = %* {
|
||||
"accountID": account0["id"].getStr,
|
||||
"paths": ["m/44'/60'/0'/0", "m/43'/60'/1581'", "m/43'/60'/1581'/0'/0", "m/44'/60'/0'/0/0"],
|
||||
"paths": ["m/44'/60'/0'/0", "m/43'/60'/1581'", "m/43'/60'/1581'/0'/0",
|
||||
"m/44'/60'/0'/0/0"],
|
||||
"password": password
|
||||
}
|
||||
result = $libstatus.multiAccountStoreDerivedAccounts($multiAccount);
|
||||
|
@ -138,92 +140,103 @@ proc setupNewAccount*() =
|
|||
"mnemonic": account0["mnemonic"].getStr,
|
||||
"public-key": multiAccounts["m/43'/60'/1581'/0'/0"]["publicKey"].getStr,
|
||||
"name": accountData["name"].getStr,
|
||||
"address": account0["address"].getStr,
|
||||
"address": account0["address"].getStr,
|
||||
"eip1581-address": multiAccounts["m/43'/60'/1581'"]["address"].getStr,
|
||||
"dapps-address": multiAccounts["m/44'/60'/0'/0/0"]["address"].getStr,
|
||||
"wallet-root-address": multiAccounts["m/44'/60'/0'/0"]["address"].getStr,
|
||||
"wallet-root-address": multiAccounts["m/44'/60'/0'/0"]["address"].getStr,
|
||||
"preview-privacy?": true,
|
||||
"signing-phrase": "dust gear boss",
|
||||
"log-level": "INFO",
|
||||
"latest-derived-path": 0,
|
||||
"networks/networks": [
|
||||
{
|
||||
"id": "testnet_rpc",
|
||||
"etherscan-link": "https://ropsten.etherscan.io/address/",
|
||||
"name": "Ropsten with upstream RPC",
|
||||
"config":
|
||||
{
|
||||
"id": "testnet_rpc",
|
||||
"etherscan-link": "https://ropsten.etherscan.io/address/",
|
||||
"name": "Ropsten with upstream RPC",
|
||||
"config": {
|
||||
"NetworkId": 3,
|
||||
"DataDir": "/ethereum/testnet_rpc",
|
||||
"UpstreamConfig": {
|
||||
"Enabled": true,
|
||||
"URL": "https://ropsten.infura.io/v3/f315575765b14720b32382a61a89341a",
|
||||
},
|
||||
"NetworkId": 3,
|
||||
"DataDir": "/ethereum/testnet_rpc",
|
||||
"UpstreamConfig":
|
||||
{
|
||||
"Enabled": true,
|
||||
"URL": "https://ropsten.infura.io/v3/f315575765b14720b32382a61a89341a",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "rinkeby_rpc",
|
||||
"etherscan-link": "https://rinkeby.etherscan.io/address/",
|
||||
"name": "Rinkeby with upstream RPC",
|
||||
"config":
|
||||
{
|
||||
"id": "rinkeby_rpc",
|
||||
"etherscan-link": "https://rinkeby.etherscan.io/address/",
|
||||
"name": "Rinkeby with upstream RPC",
|
||||
"config": {
|
||||
"NetworkId": 4,
|
||||
"DataDir": "/ethereum/rinkeby_rpc",
|
||||
"UpstreamConfig": {
|
||||
"Enabled": true,
|
||||
"URL": "https://rinkeby.infura.io/v3/f315575765b14720b32382a61a89341a",
|
||||
},
|
||||
"NetworkId": 4,
|
||||
"DataDir": "/ethereum/rinkeby_rpc",
|
||||
"UpstreamConfig":
|
||||
{
|
||||
"Enabled": true,
|
||||
"URL": "https://rinkeby.infura.io/v3/f315575765b14720b32382a61a89341a",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "goerli_rpc",
|
||||
"etherscan-link": "https://goerli.etherscan.io/address/",
|
||||
"name": "Goerli with upstream RPC",
|
||||
"config":
|
||||
{
|
||||
"id": "goerli_rpc",
|
||||
"etherscan-link": "https://goerli.etherscan.io/address/",
|
||||
"name": "Goerli with upstream RPC",
|
||||
"config": {
|
||||
"NetworkId": 5,
|
||||
"DataDir": "/ethereum/goerli_rpc",
|
||||
"UpstreamConfig": {
|
||||
"Enabled": true,
|
||||
"URL": "https://goerli.blockscout.com/",
|
||||
},
|
||||
"NetworkId": 5,
|
||||
"DataDir": "/ethereum/goerli_rpc",
|
||||
"UpstreamConfig":
|
||||
{
|
||||
"Enabled": true,
|
||||
"URL": "https://goerli.blockscout.com/",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "mainnet_rpc",
|
||||
"etherscan-link": "https://etherscan.io/address/",
|
||||
"name": "Mainnet with upstream RPC",
|
||||
"config":
|
||||
{
|
||||
"id": "mainnet_rpc",
|
||||
"etherscan-link": "https://etherscan.io/address/",
|
||||
"name": "Mainnet with upstream RPC",
|
||||
"config": {
|
||||
"NetworkId": 1,
|
||||
"DataDir": "/ethereum/mainnet_rpc",
|
||||
"UpstreamConfig": {
|
||||
"Enabled": true,
|
||||
"URL": "https://mainnet.infura.io/v3/f315575765b14720b32382a61a89341a",
|
||||
},
|
||||
"NetworkId": 1,
|
||||
"DataDir": "/ethereum/mainnet_rpc",
|
||||
"UpstreamConfig":
|
||||
{
|
||||
"Enabled": true,
|
||||
"URL": "https://mainnet.infura.io/v3/f315575765b14720b32382a61a89341a",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "xdai_rpc",
|
||||
"name": "xDai Chain",
|
||||
"config":
|
||||
{
|
||||
"id": "xdai_rpc",
|
||||
"name": "xDai Chain",
|
||||
"config": {
|
||||
"NetworkId": 100,
|
||||
"DataDir": "/ethereum/xdai_rpc",
|
||||
"UpstreamConfig": {
|
||||
"Enabled": true,
|
||||
"URL": "https://dai.poa.network"
|
||||
},
|
||||
"NetworkId": 100,
|
||||
"DataDir": "/ethereum/xdai_rpc",
|
||||
"UpstreamConfig":
|
||||
{
|
||||
"Enabled": true,
|
||||
"URL": "https://dai.poa.network"
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "poa_rpc",
|
||||
"name": "POA Network",
|
||||
"config":
|
||||
{
|
||||
"id": "poa_rpc",
|
||||
"name": "POA Network",
|
||||
"config": {
|
||||
"NetworkId": 99,
|
||||
"DataDir": "/ethereum/poa_rpc",
|
||||
"UpstreamConfig": {
|
||||
"Enabled": true,
|
||||
"URL": "https://core.poa.network"
|
||||
},
|
||||
"NetworkId": 99,
|
||||
"DataDir": "/ethereum/poa_rpc",
|
||||
"UpstreamConfig":
|
||||
{
|
||||
"Enabled": true,
|
||||
"URL": "https://core.poa.network"
|
||||
},
|
||||
},
|
||||
],
|
||||
}],
|
||||
"currency": "usd",
|
||||
"photo-path": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAmElEQVR4nOzX4QmAIBBA4Yp2aY52aox2ao6mqf+SoajwON73M0J4HBy6TEEYQmMIjSE0htCECVlbDziv+/n6fuzb3OP/UmEmYgiNITRNm+LPqO2UE2YihtAYQlN818ptoZzau1btOakwEzGExhCa5hdi7d2p1zZLhZmIITSG0PhCpDGExhANEmYihtAYQmMIjSE0bwAAAP//kHQdRIWYzToAAAAASUVORK5CYII=",
|
||||
"waku-enabled": true,
|
||||
|
@ -234,9 +247,9 @@ proc setupNewAccount*() =
|
|||
"networks/current-network": "mainnet_rpc",
|
||||
"installation-id": "5d6bc316-a97e-5b89-9541-ad01f8eb7397",
|
||||
}
|
||||
|
||||
|
||||
let configJSON = %* {
|
||||
"BrowsersConfig": {
|
||||
"BrowsersConfig": {
|
||||
"Enabled": true
|
||||
},
|
||||
"ClusterConfig": {
|
||||
|
@ -318,41 +331,42 @@ proc setupNewAccount*() =
|
|||
"Enabled": true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let subaccountData = %* [
|
||||
{
|
||||
"public-key": multiAccounts["m/44'/60'/0'/0/0"]["publicKey"],
|
||||
"address": multiAccounts["m/44'/60'/0'/0/0"]["address"],
|
||||
"color":"#4360df",
|
||||
"wallet":true,
|
||||
"path":"m/44'/60'/0'/0/0",
|
||||
"name":"Status account"
|
||||
"color": "#4360df",
|
||||
"wallet": true,
|
||||
"path": "m/44'/60'/0'/0/0",
|
||||
"name": "Status account"
|
||||
},
|
||||
{
|
||||
"public-key": multiAccounts["m/43'/60'/1581'/0'/0"]["publicKey"],
|
||||
"address": multiAccounts["m/43'/60'/1581'/0'/0"]["address"],
|
||||
"name":"Delectable Overjoyed Nauplius",
|
||||
"photo-path":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAmElEQVR4nOzX4QmAIBBA4Yp2aY52aox2ao6mqf+SoajwON73M0J4HBy6TEEYQmMIjSE0htCECVlbDziv+/n6fuzb3OP/UmEmYgiNITRNm+LPqO2UE2YihtAYQlN818ptoZzau1btOakwEzGExhCa5hdi7d2p1zZLhZmIITSG0PhCpDGExhANEmYihtAYQmMIjSE0bwAAAP//kHQdRIWYzToAAAAASUVORK5CYII=",
|
||||
"path":"m/43'/60'/1581'/0'/0",
|
||||
"chat":true
|
||||
"name": "Delectable Overjoyed Nauplius",
|
||||
"photo-path": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAmElEQVR4nOzX4QmAIBBA4Yp2aY52aox2ao6mqf+SoajwON73M0J4HBy6TEEYQmMIjSE0htCECVlbDziv+/n6fuzb3OP/UmEmYgiNITRNm+LPqO2UE2YihtAYQlN818ptoZzau1btOakwEzGExhCa5hdi7d2p1zZLhZmIITSG0PhCpDGExhANEmYihtAYQmMIjSE0bwAAAP//kHQdRIWYzToAAAAASUVORK5CYII=",
|
||||
"path": "m/43'/60'/1581'/0'/0",
|
||||
"chat": true
|
||||
}
|
||||
]
|
||||
|
||||
result = $libstatus.saveAccountAndLogin($accountData, password, $settingsJSON, $configJSON, $subaccountData)
|
||||
|
||||
result = $libstatus.saveAccountAndLogin($accountData, password, $settingsJSON,
|
||||
$configJSON, $subaccountData)
|
||||
let saveResult = result.parseJson
|
||||
|
||||
|
||||
if saveResult["error"].getStr == "":
|
||||
echo "Account saved succesfully"
|
||||
|
||||
|
||||
|
||||
proc callRPC*(inputJSON: string): string =
|
||||
return $libstatus.callRPC(inputJSON)
|
||||
return $libstatus.callRPC(inputJSON)
|
||||
|
||||
proc callPrivateRPC*(inputJSON: string): string =
|
||||
return $libstatus.callPrivateRPC(inputJSON)
|
||||
return $libstatus.callPrivateRPC(inputJSON)
|
||||
|
||||
proc addPeer*(peer: string): string =
|
||||
return $libstatus.addPeer(peer)
|
||||
return $libstatus.addPeer(peer)
|
||||
|
||||
# proc onMessage*(callback: proc(message: string)): void =
|
||||
# $libstatus.setSignalEventCallback(callback)
|
||||
|
|
|
@ -0,0 +1,387 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.3
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
import Qt.labs.platform 1.1
|
||||
import "../imports"
|
||||
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
width: parent.height
|
||||
height: parent.width
|
||||
anchors.fill: parent
|
||||
// spacing: 50
|
||||
|
||||
TabBar {
|
||||
id: tabBar
|
||||
y: 0
|
||||
width: 50
|
||||
height: width *2 + spacing
|
||||
Layout.preferredHeight: 0
|
||||
currentIndex: 0
|
||||
topPadding: 57
|
||||
rightPadding: 19
|
||||
leftPadding: 19
|
||||
transformOrigin: Item.Top
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillHeight: true
|
||||
spacing: 5
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: 80
|
||||
Layout.preferredWidth: 80
|
||||
Layout.maximumWidth: 80
|
||||
Layout.minimumHeight: 0
|
||||
background: Rectangle {
|
||||
color: "#00000000"
|
||||
border.color: Theme.grey
|
||||
}
|
||||
|
||||
TabButton {
|
||||
id: chatBtn
|
||||
x: 0
|
||||
width: 40
|
||||
height: 40
|
||||
text: ""
|
||||
padding: 0
|
||||
transformOrigin: Item.Center
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
background: Rectangle {
|
||||
color: Theme.lightBlue
|
||||
opacity: parent.checked ? 1 : 0
|
||||
radius: 50
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: parent.checked ? "img/messageActive.svg" : "img/message.svg"
|
||||
}
|
||||
}
|
||||
|
||||
TabButton {
|
||||
id: walletBtn
|
||||
width: 40
|
||||
height: 40
|
||||
text: ""
|
||||
anchors.topMargin: 50
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: chatBtn.top
|
||||
background: Rectangle {
|
||||
color: Theme.lightBlue
|
||||
opacity: parent.checked ? 1 : 0
|
||||
radius: 50
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image1
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: parent.checked ? "img/walletActive.svg" : "img/wallet.svg"
|
||||
}
|
||||
}
|
||||
|
||||
TabButton {
|
||||
id: browserBtn
|
||||
width: 40
|
||||
height: 40
|
||||
text: ""
|
||||
anchors.topMargin: 50
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: walletBtn.top
|
||||
background: Rectangle {
|
||||
color: Theme.lightBlue
|
||||
opacity: parent.checked ? 1 : 0
|
||||
radius: 50
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: parent.checked ? "img/compassActive.svg" : "img/compass.svg"
|
||||
}
|
||||
}
|
||||
|
||||
TabButton {
|
||||
id: profileBtn
|
||||
width: 40
|
||||
height: 40
|
||||
text: ""
|
||||
anchors.topMargin: 50
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: browserBtn.top
|
||||
background: Rectangle {
|
||||
color: Theme.lightBlue
|
||||
opacity: parent.checked ? 1 : 0
|
||||
radius: 50
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image3
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: parent.checked ? "img/profileActive.svg" : "img/profile.svg"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
StackLayout {
|
||||
anchors.left: tabBar.right
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
Layout.fillWidth: true
|
||||
currentIndex: tabBar.currentIndex
|
||||
|
||||
SplitView {
|
||||
id: splitView
|
||||
x: 0
|
||||
y: 0
|
||||
Layout.fillHeight: true
|
||||
// anchors.fill: parent
|
||||
// width: parent.width
|
||||
Layout.leftMargin: 0
|
||||
Layout.fillWidth: true
|
||||
|
||||
Item {
|
||||
id: element1
|
||||
width: 300
|
||||
height: parent.height
|
||||
Layout.minimumWidth: 200
|
||||
|
||||
ColumnLayout {
|
||||
anchors.rightMargin: 0
|
||||
anchors.fill: parent
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: 100
|
||||
Layout.fillHeight: false
|
||||
Layout.fillWidth: true
|
||||
|
||||
Text {
|
||||
id: element
|
||||
x: 772
|
||||
text: qsTr("Chat")
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 17
|
||||
font.bold: true
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.pixelSize: 17
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: searchBox
|
||||
height: 36
|
||||
color: Theme.grey
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 59
|
||||
radius: 8
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 65
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 16
|
||||
|
||||
TextField {
|
||||
id: searchText
|
||||
placeholderText: qsTr("Search")
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 32
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: 12
|
||||
background: Rectangle {
|
||||
color: "#00000000"
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image4
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "img/search.svg"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
onClicked : {
|
||||
searchText.forceActiveFocus(Qt.MouseFocusReason)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: addChat
|
||||
width: 36
|
||||
height: 36
|
||||
color: Theme.blue
|
||||
radius: 50
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 16
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 59
|
||||
|
||||
Text {
|
||||
id: element3
|
||||
color: "#ffffff"
|
||||
text: qsTr("+")
|
||||
anchors.verticalCenterOffset: -1
|
||||
anchors.horizontalCenterOffset: 1
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
lineHeight: 1
|
||||
fontSizeMode: Text.FixedSize
|
||||
font.bold: true
|
||||
font.pixelSize: 28
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
Component {
|
||||
id: chatViewDelegate
|
||||
|
||||
Rectangle {
|
||||
id: wrapper
|
||||
height: 64
|
||||
color: ListView.isCurrentItem ? Theme.lightBlue : Theme.transparent
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 16
|
||||
anchors.top: applicationWindow.top
|
||||
anchors.topMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 16
|
||||
radius: 8
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: listView.currentIndex = index
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: contactImage
|
||||
width: 40
|
||||
color: Theme.darkGrey
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 16
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 12
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 12
|
||||
radius: 50
|
||||
}
|
||||
|
||||
Text {
|
||||
id: contactInfo
|
||||
text: "Name:" + name
|
||||
font.weight: Font.Medium
|
||||
font.pixelSize: 15
|
||||
anchors.left: contactImage.right
|
||||
anchors.leftMargin: 16
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 10
|
||||
color: "black"
|
||||
}
|
||||
Text {
|
||||
id: lastChatMessage
|
||||
text: "Chatting blah blah..."
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 10
|
||||
font.pixelSize: 15
|
||||
anchors.left: contactImage.right
|
||||
anchors.leftMargin: 16
|
||||
color: Theme.darkGrey
|
||||
}
|
||||
Text {
|
||||
id: contactTime
|
||||
text: "12:22 AM"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 16
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 10
|
||||
font.pixelSize: 11
|
||||
color: Theme.darkGrey
|
||||
}
|
||||
Rectangle {
|
||||
id: contactNumberChatsCircle
|
||||
width: 22
|
||||
height: 22
|
||||
radius: 50
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 10
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 16
|
||||
color: Theme.blue
|
||||
Text {
|
||||
id: contactNumberChats
|
||||
text: qsTr("1")
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: "white"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
anchors.topMargin: 24
|
||||
anchors.fill: parent
|
||||
model: chatsModel
|
||||
delegate: chatViewDelegate
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.rightMargin: 0
|
||||
|
||||
RowLayout {
|
||||
Layout.fillHeight: true
|
||||
TextArea { id: callResult; Layout.fillWidth: true; text: logic.callResult; readOnly: true }
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.bottomMargin: 20
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignBottom
|
||||
transformOrigin: Item.Bottom
|
||||
Label { text: "data2" }
|
||||
TextField { id: txtData; Layout.fillWidth: true; text: "" }
|
||||
Button {
|
||||
text: "Send"
|
||||
onClicked: logic.onSend(txtData.text)
|
||||
enabled: txtData.text !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
RowLayout {
|
||||
Layout.fillHeight: true
|
||||
TextArea { id: accountResult; Layout.fillWidth: true; text: logic.accountResult; readOnly: true }
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;height:770;width:1232}
|
||||
}
|
||||
##^##*/
|
Before Width: | Height: | Size: 680 B After Width: | Height: | Size: 680 B |
Before Width: | Height: | Size: 655 B After Width: | Height: | Size: 655 B |
Before Width: | Height: | Size: 869 B After Width: | Height: | Size: 869 B |
Before Width: | Height: | Size: 883 B After Width: | Height: | Size: 883 B |
Before Width: | Height: | Size: 622 B After Width: | Height: | Size: 622 B |
Before Width: | Height: | Size: 611 B After Width: | Height: | Size: 611 B |
Before Width: | Height: | Size: 709 B After Width: | Height: | Size: 709 B |
Before Width: | Height: | Size: 657 B After Width: | Height: | Size: 657 B |
Before Width: | Height: | Size: 646 B After Width: | Height: | Size: 646 B |
|
@ -0,0 +1 @@
|
|||
AppMain 1.0 AppMain.qml
|
|
@ -0,0 +1,64 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.3
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
import Qt.labs.platform 1.1
|
||||
import "./onboarding" as Onboarding
|
||||
import "./app" as App
|
||||
|
||||
ApplicationWindow {
|
||||
id: applicationWindow
|
||||
width: 1232
|
||||
height: 770
|
||||
title: "Nim Status Client"
|
||||
visible: true
|
||||
|
||||
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
|
||||
|
||||
Onboarding.Intro {
|
||||
id: onboarding
|
||||
visible: !app.visible
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
App.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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:9;anchors_height:40;anchors_width:40}
|
||||
}
|
||||
##^##*/
|
|
@ -49,4 +49,32 @@ DISTFILES += \
|
|||
Inter-ThinItalic.otf \
|
||||
Inter-V.otf \
|
||||
Theme.qml \
|
||||
imports/qmldir
|
||||
app/AppMain.qml \
|
||||
app/img/compass.svg \
|
||||
app/img/compassActive.svg \
|
||||
app/img/message.svg \
|
||||
app/img/messageActive.svg \
|
||||
app/img/profile.svg \
|
||||
app/img/profileActive.svg \
|
||||
app/img/search.svg \
|
||||
app/img/wallet.svg \
|
||||
app/img/walletActive.svg \
|
||||
app/qmldir \
|
||||
imports/qmldir \
|
||||
onboarding/Intro.qml \
|
||||
onboarding/img/browser-dark@2x.jpg \
|
||||
onboarding/img/browser-dark@3x.jpg \
|
||||
onboarding/img/browser@2x.jpg \
|
||||
onboarding/img/browser@3x.jpg \
|
||||
onboarding/img/chat-dark@2x.jpg \
|
||||
onboarding/img/chat-dark@3x.jpg \
|
||||
onboarding/img/chat@2x.jpg \
|
||||
onboarding/img/chat@3x.jpg \
|
||||
onboarding/img/next.svg \
|
||||
onboarding/img/wallet-dark@2x.jpg \
|
||||
onboarding/img/wallet-dark@3x.jpg \
|
||||
onboarding/img/wallet@2x.jpg \
|
||||
onboarding/img/wallet@3x.jpg \
|
||||
onboarding/qmldir \
|
||||
shared/Image.qml \
|
||||
shared/qmldir
|
|
@ -0,0 +1,350 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.3
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
RowLayout {
|
||||
id: obLayout
|
||||
anchors.fill: parent
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Rectangle {
|
||||
border.width: 0
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
SwipeView {
|
||||
id: vwOnboarding
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
currentIndex: 0
|
||||
interactive: false
|
||||
anchors.fill: parent
|
||||
|
||||
Item {
|
||||
id: itmSlide1
|
||||
|
||||
Image {
|
||||
id: img1
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
sourceSize.width: 414
|
||||
sourceSize.height: 414
|
||||
anchors.topMargin: 17
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "img/chat@2x.jpg"
|
||||
}
|
||||
|
||||
Text {
|
||||
id: txtTitle1
|
||||
text: qsTr("Truly private communication")
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 177
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 177
|
||||
anchors.top: img1.bottom
|
||||
anchors.topMargin: 44
|
||||
font.letterSpacing: -0.2
|
||||
font.weight: Font.Bold
|
||||
lineHeight: 1
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
transformOrigin: Item.Center
|
||||
font.bold: true
|
||||
font.pixelSize: 22
|
||||
font.kerning: true
|
||||
|
||||
}
|
||||
|
||||
Text {
|
||||
id: txtDesc1
|
||||
x: 772
|
||||
color: "#939BA1"
|
||||
text: qsTr("Chat over a peer-to-peer, encrypted network\n where messages can't be censored or hacked")
|
||||
font.weight: Font.Normal
|
||||
style: Text.Normal
|
||||
anchors.horizontalCenterOffset: 0
|
||||
anchors.top: txtTitle1.bottom
|
||||
anchors.topMargin: 14
|
||||
font.bold: true
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.pixelSize: 15
|
||||
}
|
||||
|
||||
Button {
|
||||
id: btnNext1
|
||||
width: 40
|
||||
height: 40
|
||||
anchors.top: txtDesc1.top
|
||||
anchors.bottomMargin: -2
|
||||
anchors.bottom: txtDesc1.bottom
|
||||
anchors.topMargin: -2
|
||||
anchors.left: txtDesc1.right
|
||||
anchors.leftMargin: 32
|
||||
onClicked: vwOnboarding.currentIndex++
|
||||
background: Rectangle {
|
||||
id: rctNext1
|
||||
color: "#ECEFFC"
|
||||
border.width: 0
|
||||
radius: 50
|
||||
|
||||
Image {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
source: "img/next.svg"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
id: itmSlide2
|
||||
|
||||
Image {
|
||||
id: img2
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
sourceSize.width: 414
|
||||
sourceSize.height: 414
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 17
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "img/wallet@2x.jpg"
|
||||
}
|
||||
|
||||
Text {
|
||||
id: txtTitle2
|
||||
text: qsTr("Secure crypto wallet")
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 177
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 177
|
||||
anchors.top: img2.bottom
|
||||
anchors.topMargin: 44
|
||||
font.letterSpacing: -0.2
|
||||
font.weight: Font.Bold
|
||||
lineHeight: 1
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
transformOrigin: Item.Center
|
||||
font.bold: true
|
||||
font.pixelSize: 22
|
||||
font.kerning: true
|
||||
|
||||
}
|
||||
|
||||
Button {
|
||||
id: btnPrev2
|
||||
width: 40
|
||||
height: 40
|
||||
anchors.top: txtDesc2.top
|
||||
anchors.bottomMargin: -2
|
||||
anchors.bottom: txtDesc2.bottom
|
||||
anchors.topMargin: -2
|
||||
anchors.right: txtDesc2.left
|
||||
anchors.rightMargin: 32
|
||||
onClicked: vwOnboarding.currentIndex--
|
||||
background: Rectangle {
|
||||
id: rctPrev2
|
||||
color: "#ECEFFC"
|
||||
border.width: 0
|
||||
radius: 50
|
||||
|
||||
Image {
|
||||
rotation: 180
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
source: "img/next.svg"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: txtDesc2
|
||||
x: 772
|
||||
color: "#939BA1"
|
||||
text: qsTr("Send and receive digital assets anywhere in the\nworld--no bank account required")
|
||||
font.weight: Font.Normal
|
||||
style: Text.Normal
|
||||
anchors.horizontalCenterOffset: 0
|
||||
anchors.top: txtTitle2.bottom
|
||||
anchors.topMargin: 14
|
||||
font.bold: true
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.pixelSize: 15
|
||||
}
|
||||
|
||||
Button {
|
||||
id: btnNext2
|
||||
width: 40
|
||||
height: 40
|
||||
anchors.top: txtDesc2.top
|
||||
anchors.bottomMargin: -2
|
||||
anchors.bottom: txtDesc2.bottom
|
||||
anchors.topMargin: -2
|
||||
anchors.left: txtDesc2.right
|
||||
anchors.leftMargin: 32
|
||||
onClicked: vwOnboarding.currentIndex++
|
||||
background: Rectangle {
|
||||
id: rctNext2
|
||||
color: "#ECEFFC"
|
||||
border.width: 0
|
||||
radius: 50
|
||||
|
||||
Image {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
source: "img/next.svg"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
id: itmSlide3
|
||||
|
||||
Image {
|
||||
id: img3
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
sourceSize.width: 414
|
||||
sourceSize.height: 414
|
||||
anchors.topMargin: 17
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "img/browser@2x.jpg"
|
||||
}
|
||||
|
||||
Text {
|
||||
id: txtTitle3
|
||||
text: qsTr("Decentralized apps")
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 177
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 177
|
||||
anchors.top: img3.bottom
|
||||
anchors.topMargin: 44
|
||||
font.letterSpacing: -0.2
|
||||
font.weight: Font.Bold
|
||||
lineHeight: 1
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
transformOrigin: Item.Center
|
||||
font.bold: true
|
||||
font.pixelSize: 22
|
||||
font.kerning: true
|
||||
|
||||
}
|
||||
|
||||
Button {
|
||||
id: btnPrev3
|
||||
width: 40
|
||||
height: 40
|
||||
anchors.top: txtDesc3.top
|
||||
anchors.bottomMargin: -2
|
||||
anchors.bottom: txtDesc3.bottom
|
||||
anchors.topMargin: -2
|
||||
anchors.right: txtDesc3.left
|
||||
anchors.rightMargin: 32
|
||||
onClicked: vwOnboarding.currentIndex--
|
||||
background: Rectangle {
|
||||
id: rctPrev3
|
||||
color: "#ECEFFC"
|
||||
border.width: 0
|
||||
radius: 50
|
||||
|
||||
Image {
|
||||
rotation: 180
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
source: "img/next.svg"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: txtDesc3
|
||||
x: 772
|
||||
color: "#939BA1"
|
||||
text: qsTr("Explore games, exchanges and social networks\nwhere you alone own your data")
|
||||
font.weight: Font.Normal
|
||||
style: Text.Normal
|
||||
anchors.horizontalCenterOffset: 0
|
||||
anchors.top: txtTitle3.bottom
|
||||
anchors.topMargin: 14
|
||||
font.bold: true
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.pixelSize: 15
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: rctPageIndicator
|
||||
border.width: 0
|
||||
anchors.bottom: vwOnboarding.bottom
|
||||
anchors.bottomMargin: 191
|
||||
anchors.top: vwOnboarding.top
|
||||
anchors.topMargin: 567
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: parent.width
|
||||
|
||||
|
||||
PageIndicator {
|
||||
id: pgOnboarding
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: 5
|
||||
padding: 0
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
rightPadding: 0
|
||||
leftPadding: 0
|
||||
font.pixelSize: 6
|
||||
count: vwOnboarding.count
|
||||
currentIndex: vwOnboarding.currentIndex
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: btnGetStarted
|
||||
rightPadding: 32
|
||||
leftPadding: 32
|
||||
bottomPadding: 11
|
||||
topPadding: 11
|
||||
width: 146
|
||||
height: 44
|
||||
anchors.top: rctPageIndicator.bottom
|
||||
anchors.topMargin: 87
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
onClicked: app.visible = true
|
||||
background: Rectangle {
|
||||
color: "#ECEFFC"
|
||||
radius: 8
|
||||
}
|
||||
|
||||
Text {
|
||||
id: txtGetStarted
|
||||
color: "#4360DF"
|
||||
text: qsTr("Get started")
|
||||
font.weight: Font.DemiBold
|
||||
font.pointSize: 15
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: txtPrivacyPolicy
|
||||
x: 772
|
||||
text: qsTr("Status does not collect, share or sell any personal data. By continuing you agree with the privacy policy.")
|
||||
anchors.top: btnGetStarted.bottom
|
||||
anchors.topMargin: 17
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.pixelSize: 12
|
||||
font.letterSpacing: 0.1
|
||||
color: "#939BA1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;autoSize:true;height:770;width:1232}
|
||||
}
|
||||
##^##*/
|
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 83 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 89 KiB |
|
@ -0,0 +1,3 @@
|
|||
<svg width="9" height="16" viewBox="0 0 9 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.70719 8.71434L1.69578 15.7079C1.3074 16.0953 0.681196 16.0988 0.291074 15.7097C-0.0963472 15.3232 -0.0907033 14.6911 0.292809 14.3085L6.61881 7.99859L0.292809 1.68865C-0.0955705 1.30126 -0.0990483 0.676638 0.291074 0.287507C0.678495 -0.0989301 1.31227 -0.0933004 1.69578 0.289237L8.70719 7.28284C8.93181 7.50689 9.02769 7.81029 8.99313 8.10159C8.97295 8.32613 8.8772 8.54476 8.70719 8.71434Z" fill="#4360DF"/>
|
||||
</svg>
|
After Width: | Height: | Size: 563 B |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 112 KiB |
|
@ -0,0 +1 @@
|
|||
Intro 1.0 Intro.qml
|
|
@ -0,0 +1,10 @@
|
|||
Image {
|
||||
source: {
|
||||
if (Screen.PixelDensity < 40)
|
||||
"image_low_dpi.png"
|
||||
else if (Screen.PixelDensity > 300)
|
||||
"image_high_dpi.png"
|
||||
else
|
||||
"image.png"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
@ -0,0 +1 @@
|
|||
Image 1.0 Image.qml
|