Browse Source

Wallet: update UI

pull/18/head
Sun 4 years ago
parent
commit
d59d4e45f8
  1. BIN
      assets/logo/logo_btc.png
  2. BIN
      assets/logo/logo_erc20.png
  3. 64
      lib/apps/wallet/models.dart
  4. 153
      lib/apps/wallet/page.dart
  5. 4
      lib/l10n/localizations.dart
  6. 8
      lib/l10n/localizations_en.dart
  7. 8
      lib/l10n/localizations_zh.dart
  8. 4
      lib/security.dart
  9. 2
      pubspec.yaml
  10. 20
      src/apps/wallet/models.rs
  11. 1
      src/apps/wallet/rpc.rs
  12. 3
      src/migrate/wallet.rs

BIN
assets/logo/logo_btc.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1002 B

BIN
assets/logo/logo_erc20.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

64
lib/apps/wallet/models.dart

@ -8,6 +8,17 @@ enum ChainToken { @@ -8,6 +8,17 @@ enum ChainToken {
}
extension ChainTokenExtension on ChainToken {
bool isEth() {
switch (this) {
case ChainToken.ETH:
case ChainToken.ERC20:
case ChainToken.ERC721:
return true;
default:
return false;
}
}
int toInt() {
switch (this) {
case ChainToken.ETH:
@ -115,6 +126,7 @@ class Address { @@ -115,6 +126,7 @@ class Address {
String name = '';
String address = '';
bool isGen = true;
String balanceString = '';
String icon() {
return this.address.substring(2, 4);
@ -149,6 +161,17 @@ class Address { @@ -149,6 +161,17 @@ class Address {
}
}
String get balance {
switch (this.chain) {
case ChainToken.ETH:
case ChainToken.ERC20:
case ChainToken.ERC721:
return unit_balance(this.balanceString, 18, 4);
case ChainToken.BTC:
return unit_balance(this.balanceString, 8, 4);
}
}
Address.fromList(List params) {
this.id = params[0];
this.chain = ChainTokenExtension.fromInt(params[1]);
@ -156,6 +179,7 @@ class Address { @@ -156,6 +179,7 @@ class Address {
this.name = params[3];
this.address = params[4];
this.isGen = params[5];
this.balanceString = params[6];
}
}
@ -170,10 +194,24 @@ class Token { @@ -170,10 +194,24 @@ class Token {
String balanceString = '';
double amount = 0.0;
double fiat = 0.0;
String logo = 'assets/logo/logo_eth.png';
Token() {}
String get logo {
switch (name.toUpperCase()) {
case 'ETH':
return 'assets/logo/logo_eth.png';
case 'USDT':
return 'assets/logo/logo_tether.png';
default:
if (chain.isEth()) {
return 'assets/logo/logo_erc20.png';
} else {
return 'assets/logo/logo_btc.png';
}
}
}
Token.fromList(List params) {
this.id = params[0];
this.chain = ChainTokenExtension.fromInt(params[1]);
@ -195,17 +233,19 @@ class Token { @@ -195,17 +233,19 @@ class Token {
balance(String number) {
this.balanceString = number;
this.amount = double.parse(unit_balance(number, this.decimal, 8));
}
}
final pad = number.length - (this.decimal + 1); // 0.00..00
if (pad < 0) {
number = ('0' * (-pad)) + number;
}
String right = number.substring(number.length - this.decimal, number.length);
final left = number.substring(0, number.length - this.decimal);
if (right.length > 8) {
right = right.substring(0, 8);
}
final amount_s = left + '.' + right;
this.amount = double.parse(amount_s);
String unit_balance(String number, int decimal, int limit) {
final pad = number.length - (decimal + 1); // 0.00..00
if (pad < 0) {
number = ('0' * (-pad)) + number;
}
String right = number.substring(number.length - decimal, number.length);
final left = number.substring(0, number.length - decimal);
if (right.length > limit) {
right = right.substring(0, limit);
}
return left + '.' + right;
}

153
lib/apps/wallet/page.dart

@ -35,9 +35,10 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt @@ -35,9 +35,10 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt
List<Token> _tokens = [];
List tokens = [
['ETH', '2000', '2000', 'assets/logo/logo_eth.png'],
['USDT', '2000', '2000', 'assets/logo/logo_tether.png'],
['XXX', '100', '1000', 'assets/logo/logo_eth.png'],
['FFF', '100', '1000', 'assets/logo/logo_eth.png'],
['XXX', '100', '1000', 'assets/logo/logo_erc20.png'],
['wBTC', '100', '1000', 'assets/logo/logo_btc.png'],
];
@override
@ -59,22 +60,24 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt @@ -59,22 +60,24 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt
});
if (isNew) {
this._addresses.add(address);
_changeAddress(address);
setState(() {});
}
}
_walletBalance(List params) {
print(params);
final address = params[0];
final network = NetworkExtension.fromInt(params[1]);
final contract = params[2];
final balance = params[3];
if (address == this._selectedAddress!.address && network == this._selectedNetwork!) {
final contract = params[2];
final balance = params[3];
// TODO check token.
// TODO check token.
this._mainToken = Token.eth(network);
this._mainToken.balance(balance);
setState(() {});
this._mainToken = Token.eth(network);
this._mainToken.balance(balance);
setState(() {});
}
}
_load() async {
@ -99,6 +102,10 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt @@ -99,6 +102,10 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt
this._networks = address.networks();
if (!this._networks.contains(this._selectedNetwork)) {
_changeNetwork(this._networks[0]);
} else {
rpc.send('wallet-balance', [
this._selectedNetwork!.toInt(), this._selectedAddress!.address
]);
}
}
@ -107,7 +114,6 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt @@ -107,7 +114,6 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt
rpc.send('wallet-balance', [
this._selectedNetwork!.toInt(), this._selectedAddress!.address
]);
print('sended balances');
}
@override
@ -151,6 +157,11 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt @@ -151,6 +157,11 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt
_changeAddress(this._addresses[0]);
}
List<PopupMenuEntry<int>> addressWidges = [];
this._addresses.asMap().forEach((index, value) {
addressWidges.add(_menuItem(index + 3, value, color, value == this._selectedAddress));
});
return Scaffold(
appBar: AppBar(
title: DropdownButton<Network>(
@ -186,33 +197,58 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt @@ -186,33 +197,58 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt
),
actions: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: DropdownButton<Address>(
icon: Container(),
underline: Container(),
value: this._selectedAddress,
onChanged: (Address? value) {
if (value != null) {
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: PopupMenuButton<int>(
child: Container(
margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 8.0),
width: 40.0,
decoration: BoxDecoration(
color: color.surface,
borderRadius: BorderRadius.circular(25.0)
),
child: Center(child: Text(this._selectedAddress!.icon()))
),
onSelected: (int value) {
if (value == 0) {
rpc.send('wallet-generate', [this._selectedAddress!.chain.toInt(), ""]);
} else if (value == 1) {
//
} else if (value == 2) {
//
} else {
setState(() {
_changeAddress(value);
_changeAddress(this._addresses[value - 3]);
});
}
},
items: this._addresses.map((Address addr) {
return DropdownMenuItem<Address>(
value: addr,
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 10.0),
width: 40.0,
height: 40.0,
decoration: BoxDecoration(
color: color.surface,
borderRadius: BorderRadius.circular(25.0)
),
child: Center(child: Text(addr.icon()))
itemBuilder: (context) {
return addressWidges + <PopupMenuEntry<int>>[
PopupMenuItem<int>(
value: 0,
child: ListTile(
leading: Icon(Icons.add, color: const Color(0xFF6174FF)),
title: Text(lang.createAccount,
style: TextStyle(color: const Color(0xFF6174FF))),
),
);
}).toList(),
),
PopupMenuItem<int>(
value: 1,
child: ListTile(
leading: Icon(Icons.vertical_align_bottom, color: const Color(0xFF6174FF)),
title: Text(lang.importAccount,
style: TextStyle(color: const Color(0xFF6174FF))),
),
),
PopupMenuItem<int>(
value: 2,
child: ListTile(
leading: Icon(Icons.settings, color: const Color(0xFF6174FF)),
title: Text(lang.setting,
style: TextStyle(color: const Color(0xFF6174FF))),
),
)
];
},
),
)
]
@ -323,24 +359,36 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt @@ -323,24 +359,36 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt
children: [
ListView.separated(
separatorBuilder: (BuildContext context, int index) => const Divider(),
itemCount: tokens.length,
itemCount: tokens.length + 1,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Container(
width: 36.0,
height: 36.0,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(tokens[index][3]),
fit: BoxFit.cover,
if (index == tokens.length) {
return TextButton(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Text('Add new Token' + ' ( ERC20 / ERC721 )')
),
onPressed: () {
//
},
);
} else {
return ListTile(
leading: Container(
width: 36.0,
height: 36.0,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(tokens[index][3]),
fit: BoxFit.cover,
),
),
),
),
title: Text(tokens[index][1] + ' ' + tokens[index][0]),
subtitle: Text('\$' + tokens[index][2]),
trailing: IconButton(icon: Icon(Icons.arrow_forward_ios),
onPressed: () {}),
);
title: Text(tokens[index][1] + ' ' + tokens[index][0]),
subtitle: Text('\$' + tokens[index][2]),
trailing: IconButton(icon: Icon(Icons.arrow_forward_ios),
onPressed: () {}),
);
}
}
),
ListView.separated(
@ -362,3 +410,14 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt @@ -362,3 +410,14 @@ class _WalletDetailState extends State<WalletDetail> with SingleTickerProviderSt
);
}
}
PopupMenuEntry<int> _menuItem(int value, Address address, ColorScheme color, bool selected) {
return PopupMenuItem<int>(
value: value,
child: ListTile(
leading: Icon(Icons.check, color: selected ? color.onSurface : Colors.transparent),
title: Text(address.name),
subtitle: Text(address.balance),
),
);
}

4
lib/l10n/localizations.dart

@ -122,10 +122,10 @@ abstract class AppLocalizations { @@ -122,10 +122,10 @@ abstract class AppLocalizations {
String get portuguese;
// security page (did)
String get createAccount;
String get importAccount;
String get loginChooseAccount;
String get loginRestore;
String get loginRestoreOnline;
String get loginNew;
String get loginQuick;
String get newMnemonicTitle;
String get newMnemonicInput;

8
lib/l10n/localizations_en.dart

@ -163,13 +163,13 @@ class AppLocalizationsEn extends AppLocalizations { @@ -163,13 +163,13 @@ class AppLocalizationsEn extends AppLocalizations {
// security page (did)
@override
String get loginChooseAccount => 'Choose account';
String get createAccount => 'Create Account';
@override
String get loginRestore => 'Restore Account';
String get importAccount => 'Import Account';
@override
String get loginRestoreOnline => 'Restore from online';
String get loginChooseAccount => 'Choose account';
@override
String get loginNew => 'Create Account';
String get loginRestoreOnline => 'Import from online';
@override
String get loginQuick => 'Quickly Create';
@override

8
lib/l10n/localizations_zh.dart

@ -163,13 +163,13 @@ class AppLocalizationsZh extends AppLocalizations { @@ -163,13 +163,13 @@ class AppLocalizationsZh extends AppLocalizations {
// security page (did)
@override
String get loginChooseAccount => '选择账户';
String get createAccount => '新建账户';
@override
String get loginRestore => '恢复账户';
String get importAccount => '导入账户';
@override
String get loginRestoreOnline => '账户在线恢复';
String get loginChooseAccount => '选择账户';
@override
String get loginNew => '新建账户';
String get loginRestoreOnline => '账户在线恢复';
@override
String get loginQuick => '快速新建';
@override

4
lib/security.dart

@ -134,7 +134,7 @@ class _SecurityPageState extends State<SecurityPage> { @@ -134,7 +134,7 @@ class _SecurityPageState extends State<SecurityPage> {
onPressed: () => Navigator.push(context,
MaterialPageRoute(builder: (_) => AccountRestorePage())),
child: Text(
lang.loginRestore,
lang.importAccount,
style: TextStyle(fontSize: 16),
),
),
@ -145,7 +145,7 @@ class _SecurityPageState extends State<SecurityPage> { @@ -145,7 +145,7 @@ class _SecurityPageState extends State<SecurityPage> {
onPressed: () => Navigator.push(context,
MaterialPageRoute(builder: (_) => AccountGeneratePage())),
child: Text(
lang.loginNew,
lang.createAccount,
style: TextStyle(fontSize: 16),
),
),

2
pubspec.yaml

@ -86,6 +86,8 @@ flutter: @@ -86,6 +86,8 @@ flutter:
- assets/logo/logo_wallet.png
- assets/logo/logo_eth.png
- assets/logo/logo_tether.png
- assets/logo/logo_erc20.png
- assets/logo/logo_btc.png
- assets/images/background_light.jpg
- assets/images/background_dark.jpg
- assets/images/image_missing.png

20
src/apps/wallet/models.rs

@ -120,6 +120,7 @@ pub(crate) struct Address { @@ -120,6 +120,7 @@ pub(crate) struct Address {
/// if this address is imported, has this field,
/// if this address is generated, no this field.
pub secret: String,
pub balance: String,
}
impl Address {
@ -134,6 +135,7 @@ impl Address { @@ -134,6 +135,7 @@ impl Address {
address,
name: format!("Account {}", index),
secret: "".to_owned(),
balance: "".to_owned(),
id: 0,
}
}
@ -146,11 +148,13 @@ impl Address { @@ -146,11 +148,13 @@ impl Address {
self.name,
self.address,
self.is_gen(),
self.balance,
])
}
fn from_values(mut v: Vec<DsValue>) -> Self {
Self {
balance: v.pop().unwrap().as_string(),
secret: v.pop().unwrap().as_string(),
address: v.pop().unwrap().as_string(),
name: v.pop().unwrap().as_string(),
@ -162,12 +166,13 @@ impl Address { @@ -162,12 +166,13 @@ impl Address {
pub fn insert(&mut self, db: &DStorage) -> Result<()> {
let sql = format!(
"INSERT INTO addresses (chain, indx, name, address, secret) VALUES ({}, {}, '{}', '{}', '{}')",
"INSERT INTO addresses (chain, indx, name, address, secret) VALUES ({}, {}, '{}', '{}', '{}', '{}')",
self.chain.to_i64(),
self.index,
self.name,
self.address,
self.secret,
self.balance,
);
let id = db.insert(&sql)?;
self.id = id;
@ -176,7 +181,7 @@ impl Address { @@ -176,7 +181,7 @@ impl Address {
pub fn list(db: &DStorage) -> Result<Vec<Self>> {
let matrix = db.query(&format!(
"SELECT id, chain, indx, name, address, secret FROM addresses"
"SELECT id, chain, indx, name, address, secret, balance FROM addresses"
))?;
let mut addresses = vec![];
for values in matrix {
@ -187,7 +192,7 @@ impl Address { @@ -187,7 +192,7 @@ impl Address {
pub fn next_index(db: &DStorage, chain: &ChainToken) -> Result<u32> {
let mut matrix = db.query(&format!(
"SELECT indx FROM addresses where chain = {} AND secret = '' ORDER BY indx DESC",
"SELECT indx FROM addresses where chain = {} AND secret = '' ORDER BY indx ASC",
chain.to_i64()
))?;
if matrix.len() > 0 {
@ -199,6 +204,15 @@ impl Address { @@ -199,6 +204,15 @@ impl Address {
}
}
pub fn update_balance(db: &DStorage, address: &str, balance: &str) -> Result<()> {
let sql = format!(
"UPDATE addresses SET balance = '{}' WHERE address = {}",
balance, address
);
db.update(&sql)?;
Ok(())
}
pub fn _delete(db: &DStorage, id: &i64) -> Result<()> {
let sql = format!("DELETE FROM addresses WHERE id = {}", id);
db.delete(&sql)?;

1
src/apps/wallet/rpc.rs

@ -61,6 +61,7 @@ async fn loop_token( @@ -61,6 +61,7 @@ async fn loop_token(
.await
.unwrap();
let balance = balance.to_string();
let _ = Address::update_balance(&db, &address, &balance);
let res = res_balance(gid, &address, &network, "", &balance);
sender.send(SendMessage::Rpc(0, res, true)).await?;

3
src/migrate/wallet.rs

@ -6,7 +6,8 @@ pub(super) const WALLET_VERSIONS: [&str; 2] = [ @@ -6,7 +6,8 @@ pub(super) const WALLET_VERSIONS: [&str; 2] = [
indx INTEGER NOT NULL,
name TEXT NOT NULL,
address TEXT NOT NULL,
secret TEXT NOT NULL);",
secret TEXT NOT NULL,
balance TEXT NOT NULL);",
"CREATE TABLE IF NOT EXISTS tokens(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
chain INTEGER NOT NULL,

Loading…
Cancel
Save