From dafd11fbc0d30e4ff777e087818a69d9489a0a54 Mon Sep 17 00:00:00 2001 From: emizzle Date: Tue, 19 May 2020 23:22:38 +1000 Subject: [PATCH] feat: onboarding generate new account Generates 5 random accounts with identicons, allows user to enter password, then stores the account and logs in to the statusgo node. Add EventEmitter that notifies nim_status_client.nim once node has started and is logged in (likely needs some refactoring to include the eventemitter in the base controller class). Add QML StateMachine for the onboarding view. Add nimcrytpo, uuids, eventemitter, isaac dependencies via submodules. Add button to Intro view to randomly gen account. --- .gitignore | 1 + .gitmodules | 14 + nim_status_client.nimble | 2 +- src/constants/constants.nim | 172 ++++++++ src/constants/default_networks.json | 1 + src/constants/node_config.json | 83 ++++ src/constants/signing_phrases.nim | 623 ++++++++++++++++++++++++++++ src/models/accounts.nim | 10 + src/nim_status_client.nim | 62 ++- src/onboarding.nim | 147 +++++++ src/status/accounts.nim | 15 + src/status/libstatus.nim | 4 + src/status/libstatusqml.nim | 51 +++ src/status/test.nim | 14 +- src/status/types.nim | 5 + src/status/utils.nim | 25 +- ui/main.qml | 31 +- ui/nim-status-client.pro | 7 + ui/onboarding/ExistingKey.qml | 18 + ui/onboarding/GenKey.qml | 241 +++++++++++ ui/onboarding/Intro.qml | 45 +- ui/onboarding/KeysMain.qml | 91 ++++ ui/onboarding/OnboardingMain.qml | 101 +++++ ui/onboarding/img/key.png | Bin 0 -> 19995 bytes ui/onboarding/img/key@2x.png | Bin 0 -> 56683 bytes ui/onboarding/qmldir | 6 +- ui/shared/StyledButton.qml | 34 ++ ui/shared/qmldir | 1 + vendor/eventemitter | 1 + vendor/isaac | 1 + vendor/nimcrypto | 1 + vendor/uuids | 1 + 32 files changed, 1752 insertions(+), 56 deletions(-) create mode 100644 src/constants/constants.nim create mode 100644 src/constants/default_networks.json create mode 100644 src/constants/node_config.json create mode 100644 src/constants/signing_phrases.nim create mode 100644 src/models/accounts.nim create mode 100644 src/onboarding.nim create mode 100644 src/status/accounts.nim create mode 100644 src/status/libstatusqml.nim create mode 100644 ui/onboarding/ExistingKey.qml create mode 100644 ui/onboarding/GenKey.qml create mode 100644 ui/onboarding/KeysMain.qml create mode 100644 ui/onboarding/OnboardingMain.qml create mode 100644 ui/onboarding/img/key.png create mode 100644 ui/onboarding/img/key@2x.png create mode 100644 ui/shared/StyledButton.qml create mode 160000 vendor/eventemitter create mode 160000 vendor/isaac create mode 160000 vendor/nimcrypto create mode 160000 vendor/uuids diff --git a/.gitignore b/.gitignore index 445c45263..b89dcf032 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ vendor/.nimble *.AppImage tmp nimcache +.DS_Store \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 348e6671e..0960e643d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,3 +34,17 @@ [submodule "vendor/nim-serialization"] path = vendor/nim-serialization url = https://github.com/status-im/nim-serialization/ +[submodule "vendor/nimcrypto"] + path = vendor/nimcrypto + url = https://github.com/cheatfate/nimcrypto +[submodule "vendor/uuids"] + path = vendor/uuids + url = https://github.com/pragmagic/uuids +[submodule "vendor/isaac"] + path = vendor/isaac + url = https://github.com/pragmagic/isaac +[submodule "vendor/eventemitter"] + path = vendor/eventemitter + url = https://github.com/al-bimani/eventemitter + ignore = dirty + branch = master diff --git a/nim_status_client.nimble b/nim_status_client.nimble index b39851f4c..ab5837bb3 100644 --- a/nim_status_client.nimble +++ b/nim_status_client.nimble @@ -10,4 +10,4 @@ skipExt = @["nim"] # Deps -requires "nim >= 1.0.0", " nimqml >= 0.7.0", "stint" +requires "nim >= 1.0.0", " nimqml >= 0.7.0", "stint", "nimcrypto >= 0.4.11", "uuids >= 0.1.10" diff --git a/src/constants/constants.nim b/src/constants/constants.nim new file mode 100644 index 000000000..67792ac4d --- /dev/null +++ b/src/constants/constants.nim @@ -0,0 +1,172 @@ +import json + +const PATH_WALLET_ROOT* = "m/44'/60'/0'/0" +# EIP1581 Root Key, the extended key from which any whisper key/encryption key can be derived +const PATH_EIP_1581* = "m/43'/60'/1581'" +# BIP44-0 Wallet key, the default wallet key +const PATH_DEFAULT_WALLET* = PATH_WALLET_ROOT & "/0" +# EIP1581 Chat Key 0, the default whisper key +const PATH_WHISPER* = PATH_EIP_1581 & "/0'/0" + +let DEFAULT_NETWORKS* = %* [ + { + "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" + } + } + }, + { + "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" + } + } + }, + { + "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/" + } + } + }, + { + "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" + } + } + }, + { + "id": "xdai_rpc", + "name": "xDai Chain", + "config": { + "NetworkId": 100, + "DataDir": "/ethereum/xdai_rpc", + "UpstreamConfig": { + "Enabled": true, + "URL": "https://dai.poa.network" + } + } + }, + { + "id": "poa_rpc", + "name": "POA Network", + "config": { + "NetworkId": 99, + "DataDir": "/ethereum/poa_rpc", + "UpstreamConfig": { + "Enabled": true, + "URL": "https://core.poa.network" + } + } + } +] + +let NODE_CONFIG* = %* { + "BrowsersConfig": { + "Enabled": true + }, + "ClusterConfig": { + "BootNodes": [ + "enode://23d0740b11919358625d79d4cac7d50a34d79e9c69e16831c5c70573757a1f5d7d884510bc595d7ee4da3c1508adf87bbc9e9260d804ef03f8c1e37f2fb2fc69@47.52.106.107:443", + "enode://5395aab7833f1ecb671b59bf0521cf20224fe8162fc3d2675de4ee4d5636a75ec32d13268fc184df8d1ddfa803943906882da62a4df42d4fccf6d17808156a87@178.128.140.188:443", + "enode://6e6554fb3034b211398fcd0f0082cbb6bd13619e1a7e76ba66e1809aaa0c5f1ac53c9ae79cf2fd4a7bacb10d12010899b370c75fed19b991d9c0cdd02891abad@47.75.99.169:443", + "enode://5405c509df683c962e7c9470b251bb679dd6978f82d5b469f1f6c64d11d50fbd5dd9f7801c6ad51f3b20a5f6c7ffe248cc9ab223f8bcbaeaf14bb1c0ef295fd0@35.223.215.156:443" + ], + "Enabled": true, + "Fleet": "eth.prod", + "RendezvousNodes": [ + "/ip4/34.70.75.208/tcp/30703/ethv4/16Uiu2HAm6ZsERLx2BwVD2UM9SVPnnMU6NBycG8XPtu8qKys5awsU", + "/ip4/178.128.140.188/tcp/30703/ethv4/16Uiu2HAmLqTXuY4Sb6G28HNooaFUXUKzpzKXCcgyJxgaEE2i5vnf", + "/ip4/47.52.106.107/tcp/30703/ethv4/16Uiu2HAmEHiptiDDd9gqNY8oQqo8hHUWMHJzfwt5aLRdD6W2zcXR" + ], + "StaticNodes": [ + "enode://887cbd92d95afc2c5f1e227356314a53d3d18855880ac0509e0c0870362aee03939d4074e6ad31365915af41d34320b5094bfcc12a67c381788cd7298d06c875@178.128.141.0:443", + "enode://fbeddac99d396b91d59f2c63a3cb5fc7e0f8a9f7ce6fe5f2eed5e787a0154161b7173a6a73124a4275ef338b8966dc70a611e9ae2192f0f2340395661fad81c0@34.67.230.193:443" + ], + "TrustedMailServers": [ + "enode://2c8de3cbb27a3d30cbb5b3e003bc722b126f5aef82e2052aaef032ca94e0c7ad219e533ba88c70585ebd802de206693255335b100307645ab5170e88620d2a81@47.244.221.14:443", + "enode://ee2b53b0ace9692167a410514bca3024695dbf0e1a68e1dff9716da620efb195f04a4b9e873fb9b74ac84de801106c465b8e2b6c4f0d93b8749d1578bfcaf03e@104.197.238.144:443", + "enode://8a64b3c349a2e0ef4a32ea49609ed6eb3364be1110253c20adc17a3cebbc39a219e5d3e13b151c0eee5d8e0f9a8ba2cd026014e67b41a4ab7d1d5dd67ca27427@178.128.142.94:443", + "enode://7aa648d6e855950b2e3d3bf220c496e0cae4adfddef3e1e6062e6b177aec93bc6cdcf1282cb40d1656932ebfdd565729da440368d7c4da7dbd4d004b1ac02bf8@178.128.142.26:443", + "enode://c42f368a23fa98ee546fd247220759062323249ef657d26d357a777443aec04db1b29a3a22ef3e7c548e18493ddaf51a31b0aed6079bd6ebe5ae838fcfaf3a49@178.128.142.54:443", + "enode://30211cbd81c25f07b03a0196d56e6ce4604bb13db773ff1c0ea2253547fafd6c06eae6ad3533e2ba39d59564cfbdbb5e2ce7c137a5ebb85e99dcfc7a75f99f55@23.236.58.92:443" + ] + }, + "DataDir": "./ethereum/mainnet", + "EnableNTPSync": true, + "KeyStoreDir": "./keystore", + "ListenAddr": ":30304", + "LogEnabled": true, + "LogFile": "geth.log", + "LogLevel": "INFO", + "MailserversConfig": { + "Enabled": true + }, + "Name": "StatusIM", + "NetworkId": 1, + "NoDiscovery": false, + "PermissionsConfig": { + "Enabled": true + }, + "Rendezvous": true, + "RequireTopics": { + "whisper": { + "Max": 2, + "Min": 2 + } + }, + "ShhextConfig": { + "BackupDisabledDataDir": "./", + "DataSyncEnabled": true, + "InstallationID": "aef27732-8d86-5039-a32e-bdbe094d8791", + "MailServerConfirmations": true, + "MaxMessageDeliveryAttempts": 6, + "PFSEnabled": true, + "VerifyENSContractAddress": "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", + "VerifyENSURL": "https://mainnet.infura.io/v3/f315575765b14720b32382a61a89341a", + "VerifyTransactionChainID": 1, + "VerifyTransactionURL": "https://mainnet.infura.io/v3/f315575765b14720b32382a61a89341a" + }, + "StatusAccountsConfig": { + "Enabled": true + }, + "UpstreamConfig": { + "Enabled": true, + "URL": "https://mainnet.infura.io/v3/f315575765b14720b32382a61a89341a" + }, + "WakuConfig": { + "BloomFilterMode": nil, + "Enabled": true, + "LightClient": true, + "MinimumPoW": 0.001 + }, + "WalletConfig": { + "Enabled": true + } +} \ No newline at end of file diff --git a/src/constants/default_networks.json b/src/constants/default_networks.json new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/src/constants/default_networks.json @@ -0,0 +1 @@ + diff --git a/src/constants/node_config.json b/src/constants/node_config.json new file mode 100644 index 000000000..d2a49c511 --- /dev/null +++ b/src/constants/node_config.json @@ -0,0 +1,83 @@ +{ + "BrowsersConfig": { + "Enabled": true + }, + "ClusterConfig": { + "BootNodes": [ + "enode://23d0740b11919358625d79d4cac7d50a34d79e9c69e16831c5c70573757a1f5d7d884510bc595d7ee4da3c1508adf87bbc9e9260d804ef03f8c1e37f2fb2fc69@47.52.106.107:443", + "enode://5395aab7833f1ecb671b59bf0521cf20224fe8162fc3d2675de4ee4d5636a75ec32d13268fc184df8d1ddfa803943906882da62a4df42d4fccf6d17808156a87@178.128.140.188:443", + "enode://6e6554fb3034b211398fcd0f0082cbb6bd13619e1a7e76ba66e1809aaa0c5f1ac53c9ae79cf2fd4a7bacb10d12010899b370c75fed19b991d9c0cdd02891abad@47.75.99.169:443", + "enode://5405c509df683c962e7c9470b251bb679dd6978f82d5b469f1f6c64d11d50fbd5dd9f7801c6ad51f3b20a5f6c7ffe248cc9ab223f8bcbaeaf14bb1c0ef295fd0@35.223.215.156:443" + ], + "Enabled": true, + "Fleet": "eth.prod", + "RendezvousNodes": [ + "/ip4/34.70.75.208/tcp/30703/ethv4/16Uiu2HAm6ZsERLx2BwVD2UM9SVPnnMU6NBycG8XPtu8qKys5awsU", + "/ip4/178.128.140.188/tcp/30703/ethv4/16Uiu2HAmLqTXuY4Sb6G28HNooaFUXUKzpzKXCcgyJxgaEE2i5vnf", + "/ip4/47.52.106.107/tcp/30703/ethv4/16Uiu2HAmEHiptiDDd9gqNY8oQqo8hHUWMHJzfwt5aLRdD6W2zcXR" + ], + "StaticNodes": [ + "enode://887cbd92d95afc2c5f1e227356314a53d3d18855880ac0509e0c0870362aee03939d4074e6ad31365915af41d34320b5094bfcc12a67c381788cd7298d06c875@178.128.141.0:443", + "enode://fbeddac99d396b91d59f2c63a3cb5fc7e0f8a9f7ce6fe5f2eed5e787a0154161b7173a6a73124a4275ef338b8966dc70a611e9ae2192f0f2340395661fad81c0@34.67.230.193:443" + ], + "TrustedMailServers": [ + "enode://2c8de3cbb27a3d30cbb5b3e003bc722b126f5aef82e2052aaef032ca94e0c7ad219e533ba88c70585ebd802de206693255335b100307645ab5170e88620d2a81@47.244.221.14:443", + "enode://ee2b53b0ace9692167a410514bca3024695dbf0e1a68e1dff9716da620efb195f04a4b9e873fb9b74ac84de801106c465b8e2b6c4f0d93b8749d1578bfcaf03e@104.197.238.144:443", + "enode://8a64b3c349a2e0ef4a32ea49609ed6eb3364be1110253c20adc17a3cebbc39a219e5d3e13b151c0eee5d8e0f9a8ba2cd026014e67b41a4ab7d1d5dd67ca27427@178.128.142.94:443", + "enode://7aa648d6e855950b2e3d3bf220c496e0cae4adfddef3e1e6062e6b177aec93bc6cdcf1282cb40d1656932ebfdd565729da440368d7c4da7dbd4d004b1ac02bf8@178.128.142.26:443", + "enode://c42f368a23fa98ee546fd247220759062323249ef657d26d357a777443aec04db1b29a3a22ef3e7c548e18493ddaf51a31b0aed6079bd6ebe5ae838fcfaf3a49@178.128.142.54:443", + "enode://30211cbd81c25f07b03a0196d56e6ce4604bb13db773ff1c0ea2253547fafd6c06eae6ad3533e2ba39d59564cfbdbb5e2ce7c137a5ebb85e99dcfc7a75f99f55@23.236.58.92:443" + ] + }, + "DataDir": "./ethereum/mainnet", + "EnableNTPSync": true, + "KeyStoreDir": "./keystore", + "ListenAddr": ":30304", + "LogEnabled": true, + "LogFile": "geth.log", + "LogLevel": "INFO", + "MailserversConfig": { + "Enabled": true + }, + "Name": "StatusIM", + "NetworkId": 1, + "NoDiscovery": false, + "PermissionsConfig": { + "Enabled": true + }, + "Rendezvous": true, + "RequireTopics": { + "whisper": { + "Max": 2, + "Min": 2 + } + }, + "ShhextConfig": { + "BackupDisabledDataDir": "./", + "DataSyncEnabled": true, + "InstallationID": "aef27732-8d86-5039-a32e-bdbe094d8791", + "MailServerConfirmations": true, + "MaxMessageDeliveryAttempts": 6, + "PFSEnabled": true, + "VerifyENSContractAddress": "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", + "VerifyENSURL": "https://mainnet.infura.io/v3/f315575765b14720b32382a61a89341a", + "VerifyTransactionChainID": 1, + "VerifyTransactionURL": "https://mainnet.infura.io/v3/f315575765b14720b32382a61a89341a" + }, + "StatusAccountsConfig": { + "Enabled": true + }, + "UpstreamConfig": { + "Enabled": true, + "URL": "https://mainnet.infura.io/v3/f315575765b14720b32382a61a89341a" + }, + "WakuConfig": { + "BloomFilterMode": null, + "Enabled": true, + "LightClient": true, + "MinimumPoW": 0.001 + }, + "WalletConfig": { + "Enabled": true + } +} diff --git a/src/constants/signing_phrases.nim b/src/constants/signing_phrases.nim new file mode 100644 index 000000000..e459823bf --- /dev/null +++ b/src/constants/signing_phrases.nim @@ -0,0 +1,623 @@ +const phrases*: seq[string] = @[ + "acid", + "alto", + "apse", + "arch", + "area", + "army", + "atom", + "aunt", + "babe", + "baby", + "back", + "bail", + "bait", + "bake", + "ball", + "band", + "bank", + "barn", + "base", + "bass", + "bath", + "bead", + "beak", + "beam", + "bean", + "bear", + "beat", + "beef", + "beer", + "beet", + "bell", + "belt", + "bend", + "bike", + "bill", + "bird", + "bite", + "blow", + "blue", + "boar", + "boat", + "body", + "bolt", + "bomb", + "bone", + "book", + "boot", + "bore", + "boss", + "bowl", + "brow", + "bulb", + "bull", + "burn", + "bush", + "bust", + "cafe", + "cake", + "calf", + "call", + "calm", + "camp", + "cane", + "cape", + "card", + "care", + "carp", + "cart", + "case", + "cash", + "cast", + "cave", + "cell", + "cent", + "chap", + "chef", + "chin", + "chip", + "chop", + "chub", + "chug", + "city", + "clam", + "clef", + "clip", + "club", + "clue", + "coal", + "coat", + "code", + "coil", + "coin", + "coke", + "cold", + "colt", + "comb", + "cone", + "cook", + "cope", + "copy", + "cord", + "cork", + "corn", + "cost", + "crab", + "craw", + "crew", + "crib", + "crop", + "crow", + "curl", + "cyst", + "dame", + "dare", + "dark", + "dart", + "dash", + "data", + "date", + "dead", + "deal", + "dear", + "debt", + "deck", + "deep", + "deer", + "desk", + "dhow", + "diet", + "dill", + "dime", + "dirt", + "dish", + "disk", + "dock", + "doll", + "door", + "dory", + "drag", + "draw", + "drop", + "drug", + "drum", + "duck", + "dump", + "dust", + "duty", + "ease", + "east", + "eave", + "eddy", + "edge", + "envy", + "epee", + "exam", + "exit", + "face", + "fact", + "fail", + "fall", + "fame", + "fang", + "farm", + "fawn", + "fear", + "feed", + "feel", + "feet", + "file", + "fill", + "film", + "find", + "fine", + "fire", + "fish", + "flag", + "flat", + "flax", + "flow", + "foam", + "fold", + "font", + "food", + "foot", + "fork", + "form", + "fort", + "fowl", + "frog", + "fuel", + "full", + "gain", + "gale", + "galn", + "game", + "garb", + "gate", + "gear", + "gene", + "gift", + "girl", + "give", + "glad", + "glen", + "glue", + "glut", + "goal", + "goat", + "gold", + "golf", + "gong", + "good", + "gown", + "grab", + "gram", + "gray", + "grey", + "grip", + "grit", + "gyro", + "hail", + "hair", + "half", + "hall", + "hand", + "hang", + "harm", + "harp", + "hate", + "hawk", + "head", + "heat", + "heel", + "hell", + "helo", + "help", + "hemp", + "herb", + "hide", + "high", + "hill", + "hire", + "hive", + "hold", + "hole", + "home", + "hood", + "hoof", + "hook", + "hope", + "hops", + "horn", + "hose", + "host", + "hour", + "hunt", + "hurt", + "icon", + "idea", + "inch", + "iris", + "iron", + "item", + "jail", + "jeep", + "jeff", + "joey", + "join", + "joke", + "judo", + "jump", + "junk", + "jury", + "jute", + "kale", + "keep", + "kick", + "kill", + "kilt", + "kind", + "king", + "kiss", + "kite", + "knee", + "knot", + "lace", + "lack", + "lady", + "lake", + "lamb", + "lamp", + "land", + "lark", + "lava", + "lawn", + "lead", + "leaf", + "leek", + "lier", + "life", + "lift", + "lily", + "limo", + "line", + "link", + "lion", + "lisa", + "list", + "load", + "loaf", + "loan", + "lock", + "loft", + "long", + "look", + "loss", + "lout", + "love", + "luck", + "lung", + "lute", + "lynx", + "lyre", + "maid", + "mail", + "main", + "make", + "male", + "mall", + "manx", + "many", + "mare", + "mark", + "mask", + "mass", + "mate", + "math", + "meal", + "meat", + "meet", + "menu", + "mess", + "mice", + "midi", + "mile", + "milk", + "mime", + "mind", + "mine", + "mini", + "mint", + "miss", + "mist", + "moat", + "mode", + "mole", + "mood", + "moon", + "most", + "moth", + "move", + "mule", + "mutt", + "nail", + "name", + "neat", + "neck", + "need", + "neon", + "nest", + "news", + "node", + "nose", + "note", + "oboe", + "okra", + "open", + "oval", + "oven", + "oxen", + "pace", + "pack", + "page", + "pail", + "pain", + "pair", + "palm", + "pard", + "park", + "part", + "pass", + "past", + "path", + "peak", + "pear", + "peen", + "peer", + "pelt", + "perp", + "pest", + "pick", + "pier", + "pike", + "pile", + "pimp", + "pine", + "ping", + "pink", + "pint", + "pipe", + "piss", + "pith", + "plan", + "play", + "plot", + "plow", + "poem", + "poet", + "pole", + "polo", + "pond", + "pony", + "poof", + "pool", + "port", + "post", + "prow", + "pull", + "puma", + "pump", + "pupa", + "push", + "quit", + "race", + "rack", + "raft", + "rage", + "rail", + "rain", + "rake", + "rank", + "rate", + "read", + "rear", + "reef", + "rent", + "rest", + "rice", + "rich", + "ride", + "ring", + "rise", + "risk", + "road", + "robe", + "rock", + "role", + "roll", + "roof", + "room", + "root", + "rope", + "rose", + "ruin", + "rule", + "rush", + "ruth", + "sack", + "safe", + "sage", + "sail", + "sale", + "salt", + "sand", + "sari", + "sash", + "save", + "scow", + "seal", + "seat", + "seed", + "self", + "sell", + "shed", + "shin", + "ship", + "shoe", + "shop", + "shot", + "show", + "sick", + "side", + "sign", + "silk", + "sill", + "silo", + "sing", + "sink", + "site", + "size", + "skin", + "sled", + "slip", + "smog", + "snob", + "snow", + "soap", + "sock", + "soda", + "sofa", + "soft", + "soil", + "song", + "soot", + "sort", + "soup", + "spot", + "spur", + "stag", + "star", + "stay", + "stem", + "step", + "stew", + "stop", + "stud", + "suck", + "suit", + "swan", + "swim", + "tail", + "tale", + "talk", + "tank", + "tard", + "task", + "taxi", + "team", + "tear", + "teen", + "tell", + "temp", + "tent", + "term", + "test", + "text", + "thaw", + "tile", + "till", + "time", + "tire", + "toad", + "toga", + "togs", + "tone", + "tool", + "toot", + "tote", + "tour", + "town", + "tram", + "tray", + "tree", + "trim", + "trip", + "tuba", + "tube", + "tuna", + "tune", + "turn", + "tutu", + "twig", + "type", + "unit", + "user", + "vane", + "vase", + "vast", + "veal", + "veil", + "vein", + "vest", + "vibe", + "view", + "vise", + "wait", + "wake", + "walk", + "wall", + "wash", + "wasp", + "wave", + "wear", + "weed", + "week", + "well", + "west", + "whip", + "wife", + "will", + "wind", + "wine", + "wing", + "wire", + "wish", + "wolf", + "wood", + "wool", + "word", + "work", + "worm", + "wrap", + "wren", + "yard", + "yarn", + "yawl", + "year", + "yoga", + "yoke", + "yurt", + "zinc", + "zone"] \ No newline at end of file diff --git a/src/models/accounts.nim b/src/models/accounts.nim new file mode 100644 index 000000000..fbaa719a1 --- /dev/null +++ b/src/models/accounts.nim @@ -0,0 +1,10 @@ +import json + +type + GeneratedAccount* = object + publicKey*: string + address*: string + id*: string + keyUid*: string + mnemonic*: string + derived*: JsonNode \ No newline at end of file diff --git a/src/nim_status_client.nim b/src/nim_status_client.nim index 8551cf4f6..e08f489d3 100644 --- a/src/nim_status_client.nim +++ b/src/nim_status_client.nim @@ -6,6 +6,10 @@ import app/node/core as node import app/profile/core as profile import app/signals/core as signals import state +import onboarding +import status/utils +import strformat +import strutils import strformat import strutils import json @@ -16,16 +20,43 @@ import status/types as types import status/wallet as status_wallet import status/libstatus import state +import status/libstatusqml +import status/types +import eventemitter +import os var signalsQObjPointer: pointer logScope: topics = "main" +proc ensureDir(dirname: string) = + if not existsDir(dirname): + # removeDir(dirname) + createDir(dirname) + +proc initNode(): string = + const datadir = "./data/" + const keystoredir = "./data/keystore/" + const nobackupdir = "./noBackup/" + + ensureDir(datadir) + ensureDir(keystoredir) + ensureDir(nobackupdir) + + # 1 + result = $libstatus.initKeystore(keystoredir); + + # 2 + result = $libstatus.openAccounts(datadir); + proc mainProc() = + discard initNode() + let app = newQApplication() let engine = newQQmlApplicationEngine() let signalController = signals.newController(app) + let events = createEventEmitter() defer: # Defer will run this just before mainProc() function ends app.delete() @@ -42,10 +73,12 @@ proc mainProc() = var accounts = status_test.setupNewAccount() debug "Accounts", accounts0 = parseJSON(accounts)[0], accounts1 = parseJSON(accounts)[1] - status_chat.startMessenger() + events.on("node:ready") do(a: Args): + status_chat.startMessenger() var wallet = wallet.newController() - wallet.init() + events.on("node:ready") do(a: Args): + wallet.init() engine.setRootContextProperty("assetsModel", wallet.variant) var chat = chat.newController() @@ -54,7 +87,23 @@ proc mainProc() = var node = node.newController() node.init() + engine.setRootContextProperty("nodeModel", node.variant) + + var onboarding = newOnboarding(events); + defer: onboarding.delete + + let onboardingVariant = newQVariant(onboarding) + defer: onboardingVariant.delete + + engine.setRootContextProperty("onboardingLogic", onboardingVariant) + + # TODO: figure out a way to prevent this from breaking Qt Creator + # var initLibStatusQml = proc(): LibStatusQml = + # let libStatus = newLibStatusQml(); + # return libStatus; + + # discard qmlRegisterSingletonType[LibStatusQml]("im.status.desktop.Status", 1, 0, "Status", initLibStatusQml) var profile = profile.newController() profile.init(accounts) # TODO: use correct account @@ -73,9 +122,14 @@ proc mainProc() = chat.join(channel.name) ) - appState.addChannel("test") - appState.addChannel("test2") + events.on("node:ready") do(a: Args): + appState.addChannel("test") + appState.addChannel("test2") + + + + engine.load("../ui/main.qml") # Please note that this must use the `cdecl` calling convention because diff --git a/src/onboarding.nim b/src/onboarding.nim new file mode 100644 index 000000000..ee6e537d4 --- /dev/null +++ b/src/onboarding.nim @@ -0,0 +1,147 @@ +import NimQml +import json +import status/accounts +import nimcrypto +import status/utils +import status/libstatus +import models/accounts as Models +import constants/constants +import uuids +import eventemitter +import status/test as status_test + +# Probably all QT classes will look like this: +QtObject: + type Onboarding* = ref object of QObject + m_generatedAddresses: string + events: EventEmitter + + # ¯\_(ツ)_/¯ dunno what is this + proc setup(self: Onboarding) = + self.QObject.setup + + # ¯\_(ツ)_/¯ seems to be a method for garbage collection + proc delete*(self: Onboarding) = + self.QObject.delete + + # Constructor + proc newOnboarding*(events: EventEmitter): Onboarding = + new(result, delete) + result.events = events + result.setup() + + # Read more about slots and signals here: https://doc.qt.io/qt-5/signalsandslots.html + + # Accesors + proc getGeneratedAddresses*(self: Onboarding): string {.slot.} = + result = self.m_generatedAddresses + + proc generatedAddressesChanged*(self: Onboarding, + generatedAddresses: string) {.signal.} + + proc setGeneratedAddresses*(self: Onboarding, generatedAddresses: string) {.slot.} = + if self.m_generatedAddresses == generatedAddresses: + return + self.m_generatedAddresses = generatedAddresses + self.generatedAddressesChanged(generatedAddresses) + + QtProperty[string]generatedAddresses: + read = getGeneratedAddresses + write = setGeneratedAddresses + notify = generatedAddressesChanged + + # QML functions + proc generateAddresses*(self: Onboarding) {.slot.} = + self.setGeneratedAddresses(generateAddresses()) + + proc generateAlias*(self: Onboarding, publicKey: string): string {.slot.} = + result = $libstatus.generateAlias(publicKey.toGoString) + + proc identicon*(self: Onboarding, publicKey: string): string {.slot.} = + result = $libstatus.identicon(publicKey.toGoString) + + proc storeAccountAndLogin(self: Onboarding, selectedAccount: string, password: string): string {.slot.} = + let account = to(json.parseJson(selectedAccount), Models.GeneratedAccount) + let password = "0x" & $keccak_256.digest(password) + let multiAccount = %* { + "accountID": account.id, + "paths": [constants.PATH_WALLET_ROOT, constants.PATH_EIP_1581, constants.PATH_WHISPER, + constants.PATH_DEFAULT_WALLET], + "password": password + } + let storeResult = $libstatus.multiAccountStoreDerivedAccounts($multiAccount); + let multiAccounts = storeResult.parseJson + let whisperPubKey = account.derived[constants.PATH_WHISPER]["publicKey"].getStr + let alias = $libstatus.generateAlias(whisperPubKey.toGoString) + let identicon = $libstatus.identicon(whisperPubKey.toGoString) + let accountData = %* { + "name": alias, + "address": account.address, + "photo-path": identicon, + "key-uid": account.keyUid, + "keycard-pairing": nil + } + var nodeConfig = constants.NODE_CONFIG + let defaultNetworks = constants.DEFAULT_NETWORKS + let settingsJSON = %* { + "key-uid": account.keyUid, + "mnemonic": account.mnemonic, + "public-key": multiAccounts[constants.PATH_WHISPER]["publicKey"].getStr, + "name": alias, + "address": account.address, + "eip1581-address": multiAccounts[constants.PATH_EIP_1581]["address"].getStr, + "dapps-address": multiAccounts[constants.PATH_DEFAULT_WALLET]["address"].getStr, + "wallet-root-address": multiAccounts[constants.PATH_WALLET_ROOT]["address"].getStr, + "preview-privacy?": true, + "signing-phrase": generateSigningPhrase(3), + "log-level": "INFO", + "latest-derived-path": 0, + "networks/networks": $defaultNetworks, + "currency": "usd", + "photo-path": identicon, + "waku-enabled": true, + "wallet/visible-tokens": { + "mainnet": ["SNT"] + }, + "appearance": 0, + "networks/current-network": "mainnet_rpc", + "installation-id": $genUUID() + } + + let subaccountData = %* [ + { + "public-key": multiAccounts[constants.PATH_DEFAULT_WALLET]["publicKey"], + "address": multiAccounts[constants.PATH_DEFAULT_WALLET]["address"], + "color": "#4360df", + "wallet": true, + "path": constants.PATH_DEFAULT_WALLET, + "name": "Status account" + }, + { + "public-key": multiAccounts[constants.PATH_WHISPER]["publicKey"], + "address": multiAccounts[constants.PATH_WHISPER]["address"], + "name": alias, + "photo-path": identicon, + "path": constants.PATH_WHISPER, + "chat": true + } + ] + + result = $libstatus.saveAccountAndLogin($accountData, password, $settingsJSON, + $nodeConfig, $subaccountData) + + let saveResult = result.parseJson + + if saveResult["error"].getStr == "": + self.events.emit("node:ready", Args()) + echo "Account saved succesfully" + + proc generateRandomAccountAndLogin*(self: Onboarding) {.slot.} = + status_test.setupNewAccount() + self.events.emit("node:ready", Args()) + + + + + # This class has the metaObject property available which lets + # access all the QProperties which are stored as QVariants diff --git a/src/status/accounts.nim b/src/status/accounts.nim new file mode 100644 index 000000000..2a30af38a --- /dev/null +++ b/src/status/accounts.nim @@ -0,0 +1,15 @@ +import libstatus +import json +import utils + +proc generateAddresses*(): string = + let multiAccountConfig = %* { + "n": 5, + "mnemonicPhraseLength": 12, + "bip39Passphrase": "", + "paths": ["m/43'/60'/1581'/0'/0", "m/44'/60'/0'/0/0"] + } + result = $libstatus.multiAccountGenerateAndDeriveAddresses($multiAccountConfig) + +proc generateAlias*(publicKey: string): string = + result = $libstatus.generateAlias(publicKey.toGoString) diff --git a/src/status/libstatus.nim b/src/status/libstatus.nim index 55874c3dc..b2b500dce 100644 --- a/src/status/libstatus.nim +++ b/src/status/libstatus.nim @@ -21,3 +21,7 @@ proc addPeer*(peer: cstring): cstring {.importc: "AddPeer".} proc setSignalEventCallback*(callback: SignalCallback) {.importc: "SetSignalEventCallback".} proc sendTransaction*(jsonArgs: cstring, password: cstring): cstring {.importc: "SendTransaction".} + +proc generateAlias*(p0: GoString): cstring {.importc: "GenerateAlias".} + +proc identicon*(p0: GoString): cstring {.importc: "Identicon".} diff --git a/src/status/libstatusqml.nim b/src/status/libstatusqml.nim new file mode 100644 index 000000000..86825d7c4 --- /dev/null +++ b/src/status/libstatusqml.nim @@ -0,0 +1,51 @@ +import NimQml +import libstatus +import utils + +QtObject: + type + LibStatusQml* = ref object of QObject + + + # ¯\_(ツ)_/¯ dunno what is this + proc setup(self: LibStatusQml) = + self.QObject.setup + + # ¯\_(ツ)_/¯ seems to be a method for garbage collection + proc delete*(self: LibStatusQml) = + self.QObject.delete + + # Constructor + proc newLibStatusQml*(): LibStatusQml = + new(result, delete) + result.setup + + proc hashMessage*(self: LibStatusQml, p0: string): string {.slot.} = + return $libstatus.hashMessage(p0) + + proc initKeystore*(self: LibStatusQml, keydir: string): string {.slot.} = + return $libstatus.initKeystore(keydir) + + proc openAccounts*(self: LibStatusQml, datadir: string): string {.slot.} = + return $libstatus.openAccounts(datadir) + + proc multiAccountGenerateAndDeriveAddresses*(self: LibStatusQml, paramsJSON: string): string {.slot.} = + return $libstatus.multiAccountGenerateAndDeriveAddresses(paramsJSON) + + proc multiAccountStoreDerivedAccounts*(self: LibStatusQml, paramsJSON: string): string {.slot.} = + return $libstatus.multiAccountStoreDerivedAccounts(paramsJSON) + + proc saveAccountAndLogin*(self: LibStatusQml, accountData: string, password: string, settingsJSON: string, configJSON: string, subaccountData: string): string {.slot.} = + return $libstatus.saveAccountAndLogin(accountData, password, settingsJSON, configJSON, subaccountData) + + proc callRPC*(self: LibStatusQml, inputJSON: string): string {.slot.} = + return $libstatus.callRPC(inputJSON) + + proc callPrivateRPC*(self: LibStatusQml, inputJSON: string): string {.slot.} = + return $libstatus.callPrivateRPC(inputJSON) + + proc addPeer*(self: LibStatusQml, peer: string): string {.slot.} = + return $libstatus.addPeer(peer) + + proc generateAlias*(self: LibStatusQml, p0: string): string {.slot.} = + return $libstatus.generateAlias(p0.toGoString) \ No newline at end of file diff --git a/src/status/test.nim b/src/status/test.nim index 7a8acda94..fe9a216f0 100644 --- a/src/status/test.nim +++ b/src/status/test.nim @@ -31,17 +31,17 @@ proc queryAccounts*(): string = proc setupNewAccount*(): string = # Deleting directories - recreateDir(datadir) - recreateDir(keystoredir) - recreateDir(nobackupdir) + # recreateDir(datadir) + # recreateDir(keystoredir) + # recreateDir(nobackupdir) var result: string - # 1 - result = $libstatus.initKeystore(keystoredir); + # # 1 + # result = $libstatus.initKeystore(keystoredir); - # 2 - result = $libstatus.openAccounts(datadir); + # # 2 + # result = $libstatus.openAccounts(datadir); # 3 let multiAccountConfig = %* { diff --git a/src/status/types.nim b/src/status/types.nim index 2c52fd35d..d75c3a506 100644 --- a/src/status/types.nim +++ b/src/status/types.nim @@ -14,3 +14,8 @@ type SignalType* {.pure.} = enum SubscriptionsError = "subscriptions.error" WhisperFilterAdded = "whisper.filter.added" Unknown + +type + GoString* = object + str*: cstring + length*: cint diff --git a/src/status/utils.nim b/src/status/utils.nim index b6a4782d4..5b79ca19e 100644 --- a/src/status/utils.nim +++ b/src/status/utils.nim @@ -1,4 +1,9 @@ +import json +import types +import random +from times import getTime, toUnix, nanosecond import strutils +import ../constants/signing_phrases proc isWakuEnabled(): bool = true # TODO: @@ -8,4 +13,22 @@ proc prefix*(methodName: string): string = result = result & methodName proc isOneToOneChat*(chatId: string): bool = - result = chatId.startsWith("0x") # There is probably a better way to do this \ No newline at end of file + result = chatId.startsWith("0x") # There is probably a better way to do this + +proc keys*(obj: JsonNode): seq[string] = + result = newSeq[string]() + for k, _ in obj: + result.add k + +proc toGoString*(str: string): GoString = + result = GoString(str: str, length: cint(str.len)) + +proc generateSigningPhrase*(count: int): string = + let now = getTime() + var rng = initRand(now.toUnix * 1000000000 + now.nanosecond) + var phrases: seq[string] = @[] + + for i in 1..count: + phrases.add(rng.sample(signing_phrases.phrases)) + + result = phrases.join(" ") \ No newline at end of file diff --git a/ui/main.qml b/ui/main.qml index 13769244c..11d0fb1e5 100644 --- a/ui/main.qml +++ b/ui/main.qml @@ -30,27 +30,18 @@ ApplicationWindow { } } - Rectangle { - id: rctAppBg - color: "#FFFFFF" - Layout.fillHeight: true - Layout.fillWidth: true + OnboardingMain { + id: onboarding + visible: !app.visible 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 - } + 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 } } diff --git a/ui/nim-status-client.pro b/ui/nim-status-client.pro index d1a7a0b75..f39e0c352 100644 --- a/ui/nim-status-client.pro +++ b/ui/nim-status-client.pro @@ -70,7 +70,11 @@ DISTFILES += \ app/img/walletActive.svg \ app/qmldir \ imports/qmldir \ + onboarding/ExistingKey.qml \ + onboarding/GenKey.qml \ onboarding/Intro.qml \ + onboarding/KeysMain.qml \ + onboarding/OnboardingMain.qml \ onboarding/img/browser-dark@2x.jpg \ onboarding/img/browser-dark@3x.jpg \ onboarding/img/browser@2x.jpg \ @@ -79,11 +83,14 @@ DISTFILES += \ onboarding/img/chat-dark@3x.jpg \ onboarding/img/chat@2x.jpg \ onboarding/img/chat@3x.jpg \ + onboarding/img/key.png \ + onboarding/img/key@2x.png \ 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/StyledButton.qml \ shared/RoundedIcon.qml \ shared/qmldir diff --git a/ui/onboarding/ExistingKey.qml b/ui/onboarding/ExistingKey.qml new file mode 100644 index 000000000..8923ee003 --- /dev/null +++ b/ui/onboarding/ExistingKey.qml @@ -0,0 +1,18 @@ +import QtQuick 2.3 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import QtQuick.Dialogs 1.3 + + + +Text { + text: "Existing key flow [COMING SOON]" + font.pointSize: 36 + anchors.centerIn: parent +} +/*##^## +Designer { + D{i:0;autoSize:true;height:480;width:640} +} +##^##*/ diff --git a/ui/onboarding/GenKey.qml b/ui/onboarding/GenKey.qml new file mode 100644 index 000000000..e9be40cbf --- /dev/null +++ b/ui/onboarding/GenKey.qml @@ -0,0 +1,241 @@ +import QtQuick 2.3 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import QtQuick.Dialogs 1.3 + +SwipeView { + id: swipeView + anchors.fill: parent + currentIndex: 0 + + property string strGeneratedAccounts: onboardingLogic.generatedAddresses + property var generatedAccounts: {} + signal storeAccountAndLoginResult(response: var) + + onCurrentItemChanged: { + currentItem.txtPassword.focus = true; + } + + ListModel { + id: generatedAccountsModel + } + + Item { + id: wizardStep2 + property int selectedIndex: 0 + + Text { + text: "Generated accounts" + font.pointSize: 36 + anchors.top: parent.top + anchors.topMargin: 20 + anchors.horizontalCenter: parent.horizontalCenter + } + + Item { + anchors.top: parent.top + anchors.topMargin: 50 + + Column { + spacing: 10 + ButtonGroup { + id: accountGroup + } + + Repeater { + model: generatedAccountsModel + Rectangle { + height: 32 + width: 32 + anchors.leftMargin: 20 + anchors.rightMargin: 20 + Row { + RadioButton { + checked: index == 0 ? true : false + ButtonGroup.group: accountGroup + onClicked: { + wizardStep2.selectedIndex = index; + } + } + Column { + Image { + source: identicon + } + } + Column { + Text { + text: alias + } + Text { + text: publicKey + width: 160 + elide: Text.ElideMiddle + } + + } + } + } + } + } + + + } + + Button { + text: "Select" + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + onClicked: { + console.log("button: " + wizardStep2.selectedIndex); + + swipeView.incrementCurrentIndex(); + } + } + } + + Item { + id: wizardStep3 + property Item txtPassword: txtPassword + + Text { + text: "Enter password" + font.pointSize: 36 + anchors.top: parent.top + anchors.topMargin: 20 + anchors.horizontalCenter: parent.horizontalCenter + + } + + Rectangle { + color: "#EEEEEE" + anchors.left: parent.left + anchors.right: parent.right + anchors.centerIn: parent + height: 32 + width: parent.width - 40 + TextInput { + id: txtPassword + anchors.fill: parent + focus: true + echoMode: TextInput.Password + selectByMouse: true + } + } + + Button { + text: "Next" + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + onClicked: { + console.log("password: " + txtPassword.text); + + swipeView.incrementCurrentIndex(); + } + } + } + + Item { + id: wizardStep4 + property Item txtPassword: txtConfirmPassword + + Text { + text: "Confirm password" + font.pointSize: 36 + anchors.top: parent.top + anchors.topMargin: 20 + anchors.horizontalCenter: parent.horizontalCenter + } + + Rectangle { + color: "#EEEEEE" + anchors.left: parent.left + anchors.right: parent.right + anchors.centerIn: parent + height: 32 + width: parent.width - 40 + + TextInput { + id: txtConfirmPassword + anchors.fill: parent + focus: true + echoMode: TextInput.Password + selectByMouse: true + } + } + + MessageDialog { + id: passwordsDontMatchError + title: "Error" + text: "Passwords don't match" + icon: StandardIcon.Warning + standardButtons: StandardButton.Ok + onAccepted: { + txtConfirmPassword.clear(); + swipeView.currentIndex = 1 + txtPassword.focus = true + } + } + + MessageDialog { + id: storeAccountAndLoginError + title: "Error storing account and logging in" + text: "An error occurred while storing your account and logging in: " + icon: StandardIcon.Error + standardButtons: StandardButton.Ok + } + + Button { + text: "Finish" + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + onClicked: { + console.log("confirm clicked " + txtConfirmPassword.text + " : " + txtPassword.text); + + if (txtConfirmPassword.text != txtPassword.text) { + passwordsDontMatchError.open(); + } + else { + const selectedAccount = swipeView.generatedAccounts[wizardStep2.selectedIndex]; + const storeResponse = onboardingLogic.storeAccountAndLogin(JSON.stringify(selectedAccount), txtPassword.text) + const response = JSON.parse(storeResponse); + if (response.error) { + storeAccountAndLoginError.text += response.error; + return storeAccountAndLoginError.open(); + } + swipeView.storeAccountAndLoginResult(response); + } + } + } + } + + // handle the serialised result coming from node and deserialise into JSON + // TODO: maybe we should figure out a clever to avoid this? + onStrGeneratedAccountsChanged: { + if (generatedAccounts === null || generatedAccounts === "") { + return; + } + swipeView.generatedAccounts = JSON.parse(strGeneratedAccounts); + } + + // handle deserialised data coming from the node + onGeneratedAccountsChanged: { + generatedAccountsModel.clear(); + generatedAccounts.forEach(acc => { + generatedAccountsModel.append({ + publicKey: acc.publicKey, + alias: onboardingLogic.generateAlias(acc.publicKey), + identicon: onboardingLogic.identicon(acc.publicKey) + }); + }); + } +} +/*##^## +Designer { + D{i:0;autoSize:true;height:480;width:640} +} +##^##*/ + diff --git a/ui/onboarding/Intro.qml b/ui/onboarding/Intro.qml index b103f15e8..476c96dd0 100644 --- a/ui/onboarding/Intro.qml +++ b/ui/onboarding/Intro.qml @@ -2,8 +2,11 @@ import QtQuick 2.3 import QtQuick.Controls 1.3 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 +import "../shared" RowLayout { + property alias btnGetStarted: btnGetStarted + id: obLayout anchors.fill: parent Layout.fillWidth: true @@ -26,6 +29,21 @@ RowLayout { Item { id: itmSlide1 + StyledButton { + id: btnGenRandomAcct + width: 250 + height: 50 + anchors.top: parent.top + anchors.topMargin: 50 + anchors.left: parent.left + anchors.leftMargin: 15 + label: "Generate random acct and login" + onClicked: { + onboardingLogic.generateRandomAccountAndLogin() + app.visible = true + } + } + Image { id: img1 anchors.horizontalCenter: parent.horizontalCenter @@ -301,32 +319,15 @@ RowLayout { } } - Button { + StyledButton { id: btnGetStarted - rightPadding: 32 - leftPadding: 32 - bottomPadding: 11 - topPadding: 11 - width: 146 - height: 44 + label: "Get started" 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 - } +// onClicked: app.visible = true + width: 146 + height: 44 } Text { diff --git a/ui/onboarding/KeysMain.qml b/ui/onboarding/KeysMain.qml new file mode 100644 index 000000000..0db14d340 --- /dev/null +++ b/ui/onboarding/KeysMain.qml @@ -0,0 +1,91 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.3 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 +import "../shared" + +Page { + property alias btnExistingKey: btnExistingKey + property alias btnGenKey: btnGenKey + + Image { + id: img1 + anchors.horizontalCenter: parent.horizontalCenter + sourceSize.width: 160 + sourceSize.height: 160 + anchors.topMargin: 24 + anchors.top: parent.top + fillMode: Image.PreserveAspectFit + source: "img/key@2x.png" + } + + Text { + id: txtTitle1 + text: qsTr("Get your keys") + anchors.right: parent.right + anchors.rightMargin: 177 + anchors.left: parent.left + anchors.leftMargin: 177 + anchors.top: img1.bottom + anchors.topMargin: 16 + 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("A set of keys controls your account. Your keys live on\nyour device, so only you can use them.") + horizontalAlignment: Text.AlignHCenter + font.weight: Font.Normal + style: Text.Normal + anchors.horizontalCenterOffset: 0 + anchors.top: txtTitle1.bottom + anchors.topMargin: 14 + font.bold: true + font.family: "Inter" + anchors.horizontalCenter: parent.horizontalCenter + font.pixelSize: 15 + } + + StyledButton { + id: btnExistingKey + label: "Access existing key" + anchors.top: txtDesc1.bottom + anchors.topMargin: 87 + anchors.horizontalCenter: parent.horizontalCenter + // onClicked: logic.generateAddresses() + width: 142 + height: 44 + } + + StyledButton { + id: btnGenKey + width: 194 + height: 44 + anchors.top: btnExistingKey.bottom + anchors.topMargin: 19 + anchors.horizontalCenter: parent.horizontalCenter + label: "I'm new, generate me a key" + background: Rectangle {color: "transparent"} + onClicked: onboardingLogic.generateAddresses() + } + +} + + + +/*##^## +Designer { + D{i:0;autoSize:true;height:480;width:720} +} +##^##*/ diff --git a/ui/onboarding/OnboardingMain.qml b/ui/onboarding/OnboardingMain.qml new file mode 100644 index 000000000..5a2b92735 --- /dev/null +++ b/ui/onboarding/OnboardingMain.qml @@ -0,0 +1,101 @@ +import QtQuick 2.3 +import QtQml.StateMachine 1.14 as DSM +import QtQuick.Controls 2.3 + +Page { + id: onboardingMain + property string state + anchors.fill: parent + + DSM.StateMachine { + id: stateMachine + initialState: stateIntro + running: onboardingMain.visible + + DSM.State { + id: stateIntro + onEntered: intro.visible = true + onExited: intro.visible = false + + DSM.SignalTransition { + targetState: keysMainState + signal: intro.btnGetStarted.clicked + } + } + + DSM.State { + id: keysMainState + onEntered: keysMain.visible = true + onExited: keysMain.visible = false + + DSM.SignalTransition { + targetState: existingKeyState + signal: keysMain.btnExistingKey.clicked + } + + DSM.SignalTransition { + targetState: genKeyState + signal: keysMain.btnGenKey.clicked + } + } + + DSM.State { + id: existingKeyState + onEntered: existingKey.visible = true + onExited: existingKey.visible = false + +// DSM.SignalTransition { +// targetState: keysMainState +// signal: keysMain.btnExistingKey.clicked +// } + } + + DSM.State { + id: genKeyState + onEntered: genKey.visible = true + onExited: genKey.visible = false + + DSM.SignalTransition { + targetState: appState + signal: genKey.storeAccountAndLoginResult + guard: !response.error + } + } + + DSM.FinalState { + id: appState + onEntered: app.visible = true + onExited: app.visible = false + } + } + + Intro { + id: intro + anchors.fill: parent + visible: true + } + + KeysMain { + id: keysMain + anchors.fill: parent + visible: false + } + + ExistingKey { + id: existingKey + anchors.fill: parent + visible: false + } + + GenKey { + id: genKey + anchors.fill: parent + visible: false + } +} + +/*##^## +Designer { + D{i:0;autoSize:true;height:770;width:1232} +} +##^##*/ diff --git a/ui/onboarding/img/key.png b/ui/onboarding/img/key.png new file mode 100644 index 0000000000000000000000000000000000000000..7d09df17a19b376821a4be432ff8062e7e5fc47d GIT binary patch literal 19995 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