diff --git a/lib/models/history.dart b/lib/models/history.dart index a82a4b4..da3ce26 100644 --- a/lib/models/history.dart +++ b/lib/models/history.dart @@ -7,15 +7,21 @@ import 'package:sentry/sentry.dart' as sentry; import 'package:qrscan/qrscan.dart' as scanner; import 'dart:math'; import 'package:intl/intl.dart'; +import 'package:truncate/truncate.dart'; +import 'package:crypto/crypto.dart'; +import 'package:fast_base58/fast_base58.dart'; class HistoryProvider with ChangeNotifier { String pubkey = ''; + String pubkeyShort = ''; HistoryProvider(this.pubkey); final TextEditingController outputPubkey = TextEditingController(); List transBC; bool isFirstBuild = true; String fetchMoreCursor; Map pageInfo; + bool isHistoryScreen = false; + String historySwitchButtun = "Voir l'historique"; Future scan() async { await Permission.camera.request(); @@ -54,7 +60,13 @@ class HistoryProvider with ChangeNotifier { print("C'est une pubkey !!!"); this.pubkey = pubkey; + getShortPubkey(pubkey); + this.outputPubkey.text = pubkey; + print(pubkeyShort); + + isHistoryScreen = false; + historySwitchButtun = "Voir l'historique"; notifyListeners(); return pubkey; @@ -63,6 +75,22 @@ class HistoryProvider with ChangeNotifier { return ''; } + String getShortPubkey(String pubkey) { + List pubkeyByte = Base58Decode(pubkey); + Digest pubkeyS256 = sha256.convert(sha256.convert(pubkeyByte).bytes); + String pubkeyCheksum = Base58Encode(pubkeyS256.bytes); + String pubkeyChecksumShort = truncate(pubkeyCheksum, 3, + omission: "", position: TruncatePosition.end); + + pubkeyShort = truncate(pubkey, 5, + omission: String.fromCharCode(0x2026), + position: TruncatePosition.end) + + truncate(pubkey, 4, omission: "", position: TruncatePosition.start) + + ':$pubkeyChecksumShort'; + + return pubkeyShort; + } + // Pi: D2meevcAHFTS2gQMvmRW5Hzi25jDdikk4nC4u1FkwRaU // For debug // Boris: JE6mkuzSpT3ePciCPRTpuMT9fqPUVVLJz2618d33p7tn // Matograine portefeuille: 9p5nHsES6xujFR7pw2yGy4PLKKHgWsMvsDHaHF64Uj25. @@ -111,11 +139,13 @@ class HistoryProvider with ChangeNotifier { num amountUD = amount / currentUD; if (direction == "RECEIVED") { transBC[i].add(transaction['issuers'][0]); + transBC[i].add(getShortPubkey(transaction['issuers'][0])); transBC[i].add(amount.toString()); transBC[i].add(amountUD.toStringAsFixed(2)); } else if (direction == "SENT") { final outPubkey = output.split("SIG(")[1].replaceAll(')', ''); transBC[i].add(outPubkey); + transBC[i].add(getShortPubkey(outPubkey)); transBC[i].add('- ' + amount.toString()); transBC[i].add(amountUD.toStringAsFixed(2)); } @@ -190,6 +220,24 @@ class HistoryProvider with ChangeNotifier { return num.parse(result); } + snackCopyKey(context) { + final snackBar = SnackBar( + content: + Text("Cette clé publique a été copié dans votre presse-papier."), + duration: Duration(seconds: 2)); + Scaffold.of(context).showSnackBar(snackBar); + } + + void switchProfileView() { + isHistoryScreen = !isHistoryScreen; + if (isHistoryScreen) { + historySwitchButtun = "Payer"; + } else { + historySwitchButtun = "Voir l'historique"; + } + notifyListeners(); + } + // num getBalance(_pubkey) { // getBalance(_pubkey); // } diff --git a/lib/models/home.dart b/lib/models/home.dart index 923fc49..9d854de 100644 --- a/lib/models/home.dart +++ b/lib/models/home.dart @@ -11,6 +11,10 @@ import 'package:path_provider/path_provider.dart'; class HomeProvider with ChangeNotifier { int _currentIndex = 0; + bool isSearching; + Icon searchIcon = Icon(Icons.search); + final TextEditingController searchQuery = new TextEditingController(); + Widget appBarTitle = Text('Ğecko', style: TextStyle(color: Colors.grey[850])); get currentIndex => _currentIndex; @@ -101,8 +105,25 @@ class HomeProvider with ChangeNotifier { } T getRandomElement(List list) { - final random = new Random(); + final random = Random(); var i = random.nextInt(list.length); return list[i]; } + + void handleSearchStart() { + isSearching = true; + notifyListeners(); + } + + void handleSearchEnd() { + searchIcon = Icon( + Icons.search, + color: Colors.grey[850], + ); + appBarTitle = Text('Ğecko', style: TextStyle(color: Colors.grey[850])); + isSearching = false; + searchQuery.clear(); + + notifyListeners(); + } } diff --git a/lib/screens/history.dart b/lib/screens/history.dart index 1297086..12c5d2b 100644 --- a/lib/screens/history.dart +++ b/lib/screens/history.dart @@ -10,7 +10,6 @@ import 'package:flutter/foundation.dart'; import 'dart:ui'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:provider/provider.dart'; -import 'package:truncate/truncate.dart'; // ignore: must_be_immutable class HistoryScreen extends StatelessWidget with ChangeNotifier { @@ -21,6 +20,7 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { final _formKey = GlobalKey(); FocusNode _pubkeyFocus = FocusNode(); List cesiumData; + final double avatarsSize = 80; FetchMore fetchMore; FetchMoreOptions opts; @@ -55,39 +55,13 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { ), ), body: Column(children: [ - SizedBox(height: 20), - TextField( - autofocus: false, - focusNode: _pubkeyFocus, - // Entrée de la pubkey - onChanged: (text) { - print("Clé tappxé: $text"); - _historyProvider.isPubkey(text); - }, - controller: this._outputPubkey, - maxLines: 1, - textAlign: TextAlign.center, - decoration: InputDecoration( - hintText: 'Tappez/Collez une clé publique, ou scannez', - hintStyle: TextStyle(fontSize: 14), - contentPadding: - EdgeInsets.symmetric(horizontal: 7, vertical: 15), - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - ), - style: TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.bold, - fontFamily: 'Monospace')), + SizedBox(height: 0), if (_historyProvider.pubkey != '') historyQuery(context, _historyProvider), ])); } - Widget historyQuery(context, _historyProvider) { + Widget historyQuery(context, HistoryProvider _historyProvider) { _pubkeyFocus.unfocus(); // HistoryProvider _historyProvider = Provider.of(context); CesiumPlusProvider _cesiumPlusProvider = @@ -148,7 +122,7 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { child: ListView( controller: scrollController, children: [ - SizedBox(height: 15), + SizedBox(height: 20), if (_historyProvider.pubkey != '') Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -157,7 +131,8 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { children: [ if (_isFirstExec) Container( - padding: const EdgeInsets.only(left: 30), + padding: + const EdgeInsets.fromLTRB(12, 0, 5, 0), child: FutureBuilder( future: _cesiumPlusProvider .getAvatar(_historyProvider.pubkey), @@ -174,71 +149,93 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { return Image.file( File(appPath.path + '/default_avatar.png'), - height: 65); + height: avatarsSize); } if (_avatar.hasError) { return Image.file( File(appPath.path + '/default_avatar.png'), - height: 65); + height: avatarsSize); } if (_avatar.hasData) { return SingleChildScrollView( padding: EdgeInsets.all(0.0), child: Image.file(_avatar.data[0], - height: 65)); + height: avatarsSize)); } return Image.file( File(appPath.path + '/default_avatar.png'), - height: 65); + height: avatarsSize); })), - if (_isFirstExec) - Text(balance.toString() + ' Ğ1', - textAlign: TextAlign.center, - style: TextStyle(fontSize: 30.0)), + GestureDetector( + onTap: () { + Clipboard.setData(ClipboardData( + text: _historyProvider.pubkey)); + _historyProvider.snackCopyKey(context); + }, + child: Text(_historyProvider.pubkeyShort, + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.w800, + fontFamily: 'Monospace')), + ), Container( padding: const EdgeInsets.fromLTRB( - 30, 0, 15, 0), // .only(right: 15), - child: IconButton( - icon: Icon(Icons.payments), - onPressed: () { - showDialog( - context: context, - builder: (BuildContext context) { - return paymentPopup(context); - }); - }, - iconSize: 30, - color: Color(0xFFB16E16))) + 30, 0, 5, 0), // .only(right: 15), + child: Text('TODO')), + SizedBox(width: 0) ]), - SizedBox(height: 10), if (_isFirstExec) Row( mainAxisAlignment: MainAxisAlignment.spaceAround, crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), // padding: const EdgeInsets., child: FutureBuilder( future: _cesiumPlusProvider .getName(_historyProvider.pubkey), - initialData: '', + initialData: '...', builder: (context, snapshot) { - return Text(snapshot.data); + return Text( + snapshot.data != '' + ? snapshot.data + : '-', + style: TextStyle(fontSize: 20)); })) ]), + SizedBox(height: 18), + if (_isFirstExec) + Container( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), + child: Text(balance.toString() + ' Ğ1', + textAlign: TextAlign.center, + style: TextStyle(fontSize: 18.0))), SizedBox(height: 20), - const Divider( - color: Colors.grey, - height: 5, - thickness: 0.5, - indent: 0, - endIndent: 0, - ), - _historyProvider.transBC == null - ? Text('Aucune transaction à afficher.') - : loopTransactions(context, result), + ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 1, + primary: Colors.grey[50], // background + onPrimary: Colors.black, // foreground + ), + onPressed: () { + _historyProvider.switchProfileView(); + }, + child: Text(_historyProvider.historySwitchButtun, + style: TextStyle( + fontSize: 15, color: Color(0xffD28928)))), + // const Divider( + // color: Colors.grey, + // height: 5, + // thickness: 0.5, + // indent: 0, + // endIndent: 0, + // ), + _historyProvider.isHistoryScreen + ? historyView(context, result) + : payView(context), ], )), onNotification: (t) { @@ -255,104 +252,114 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { )); } - Widget loopTransactions(context, result) { - HistoryProvider _historyProvider = Provider.of(context); + Widget payView(context) { + TextEditingController payComment = new TextEditingController(); - return Column(children: [ - for (var repository in _historyProvider.transBC) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: ListTile( - contentPadding: const EdgeInsets.all(5.0), - leading: Text(repository[1].toString(), - style: TextStyle( - fontSize: 12, - color: Colors.grey[800], - fontWeight: FontWeight.w700), - textAlign: TextAlign.center), - title: Text(repository[5], - style: TextStyle(fontSize: 14.0), - textAlign: TextAlign.center), - subtitle: Text( - truncate(repository[2], 20, - omission: "...", position: TruncatePosition.end), - style: TextStyle(fontSize: 11.0, fontFamily: 'Monospace'), - textAlign: TextAlign.center), - trailing: Text("${repository[3]} Ğ1", - style: TextStyle(fontSize: 14.0), - textAlign: TextAlign.justify), - dense: true, - isThreeLine: false, - onTap: () { - // this._outputPubkey.text = repository[2]; - _historyProvider.isPubkey(repository[2]); - })), - if (result.isLoading) - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CircularProgressIndicator(), - ], - ), - // if (_historyProvider.isTheEnd) // What I did before ... - if (!_historyProvider.pageInfo['hasPreviousPage']) - Column(children: [ - SizedBox(height: 15), - Text("Début de l'historique.", - textAlign: TextAlign.center, style: TextStyle(fontSize: 20)), - SizedBox(height: 15) - ]) - ]); - } - - Widget paymentPopup(context) { - return AlertDialog( - content: Stack( - overflow: Overflow.visible, - children: [ - Form( - key: _formKey, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text('À:'), - Padding( + return Stack( + overflow: Overflow.visible, + children: [ + Form( + key: _formKey, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox(height: 20), + Text('Commentaire:'), + Padding( padding: EdgeInsets.all(8.0), - child: Text(this._outputPubkey.text, + child: TextField( + controller: payComment, + maxLines: 2, textAlign: TextAlign.center, - style: - TextStyle(fontSize: 15, fontWeight: FontWeight.w500)), + decoration: InputDecoration(), + style: TextStyle( + fontSize: 14.0, + color: Colors.black, + fontWeight: FontWeight.bold))), + SizedBox(height: 20), + Text('Montant (Ğ1):'), + Padding( + padding: EdgeInsets.all(8.0), + child: TextFormField( + textAlign: TextAlign.center, + maxLines: 1, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'(^\d*\.?\d*)')) + ], ), - SizedBox(height: 20), - Text('Montant (Ğ1):'), - Padding( - padding: EdgeInsets.all(8.0), - child: TextFormField( - textAlign: TextAlign.center, - autofocus: true, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r'(^\d*\.?\d*)')) - ], - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: RaisedButton( - child: Text("Payer"), - color: Color(0xffFFD68E), + ), + Padding( + padding: const EdgeInsets.only(top: 15), + child: OutlineButton( + borderSide: BorderSide(width: 2, color: Color(0xffD28928)), onPressed: () { if (_formKey.currentState.validate()) { _formKey.currentState.save(); } }, - ), - ) - ], - ), + child: Padding( + padding: const EdgeInsets.all(12), + child: Text("PAYER", + style: TextStyle( + fontSize: 25, color: Colors.grey[850]))), + )) + ], ), - ], - ), + ), + ], ); } + + Widget historyView(context, result) { + HistoryProvider _historyProvider = Provider.of(context); + + return _historyProvider.transBC == null + ? Text('Aucune transaction à afficher.') + : Column(children: [ + for (var repository in _historyProvider.transBC) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 5.0), + child: ListTile( + contentPadding: const EdgeInsets.all(5.0), + leading: Text(repository[1].toString(), + style: TextStyle( + fontSize: 12, + color: Colors.grey[800], + fontWeight: FontWeight.w700), + textAlign: TextAlign.center), + title: Text(repository[3], + style: TextStyle( + fontSize: 15.0, fontFamily: 'Monospace'), + textAlign: TextAlign.center), + subtitle: Text(repository[6] != '' ? repository[6] : '-', + style: TextStyle(fontSize: 12.0), + textAlign: TextAlign.center), + trailing: Text("${repository[4]} Ğ1", + style: TextStyle(fontSize: 14.0), + textAlign: TextAlign.justify), + dense: true, + isThreeLine: false, + onTap: () { + // this._outputPubkey.text = repository[2]; + _historyProvider.isPubkey(repository[2]); + })), + if (result.isLoading) + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CircularProgressIndicator(), + ], + ), + // if (_historyProvider.isTheEnd) // What I did before ... + if (!_historyProvider.pageInfo['hasPreviousPage']) + Column(children: [ + SizedBox(height: 15), + Text("Début de l'historique.", + textAlign: TextAlign.center, + style: TextStyle(fontSize: 20)), + SizedBox(height: 15) + ]) + ]); + } } diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 7841f60..dc5ca63 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -1,4 +1,5 @@ import 'package:gecko/globals.dart'; +import 'package:gecko/models/history.dart'; import 'package:gecko/models/home.dart'; import 'package:gecko/screens/history.dart'; import 'package:flutter/material.dart'; @@ -14,6 +15,7 @@ class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { HomeProvider _homeProvider = Provider.of(context); + HistoryProvider _historyProvider = Provider.of(context); return Scaffold( drawer: Drawer( child: Column( @@ -65,12 +67,51 @@ class HomeScreen extends StatelessWidget { icon: new Icon(Icons.menu, color: Colors.grey[850]), onPressed: () => Scaffold.of(context).openDrawer(), )), - title: Text('Ğecko', style: TextStyle(color: Colors.grey[850])), + title: _homeProvider.appBarTitle, actions: [ Padding( - padding: EdgeInsets.symmetric(horizontal: 16), - child: Icon(Icons.search, color: Colors.grey[850]), - ), + padding: EdgeInsets.symmetric(horizontal: 16), + child: IconButton( + icon: _homeProvider.searchIcon, + color: Colors.grey[850], + onPressed: () { + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) { + // return SearchList(); + // }), + // ); + + if (_homeProvider.searchIcon.icon == Icons.search) { + _homeProvider.searchIcon = Icon( + Icons.close, + color: Colors.grey[850], + ); + _homeProvider.appBarTitle = TextField( + autofocus: true, + controller: _homeProvider.searchQuery, + onChanged: (text) { + print("Clé tappé: $text"); + final String searchResult = + _historyProvider.isPubkey(text); + if (searchResult != '') { + _homeProvider.currentIndex = 0; + } + }, + style: TextStyle( + color: Colors.grey[850], + ), + decoration: InputDecoration( + prefixIcon: + Icon(Icons.search, color: Colors.grey[850]), + hintText: "Rechercher ...", + hintStyle: TextStyle(color: Colors.grey[850])), + ); + _homeProvider.handleSearchStart(); + } else { + _homeProvider.handleSearchEnd(); + } + })) ], backgroundColor: Color(0xffFFD58D), ), diff --git a/lib/screens/myWallets/generateWallets.dart b/lib/screens/myWallets/generateWallets.dart index 5333173..0c16321 100644 --- a/lib/screens/myWallets/generateWallets.dart +++ b/lib/screens/myWallets/generateWallets.dart @@ -91,7 +91,7 @@ class GenerateWalletsScreen extends StatelessWidget { ), ), SizedBox(height: 20), - new ElevatedButton( + ElevatedButton( style: ElevatedButton.styleFrom( primary: Color(0xffFFD68E), // background onPrimary: Colors.black, // foreground diff --git a/pubspec.lock b/pubspec.lock index a34da15..efabd63 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -100,7 +100,7 @@ packages: source: hosted version: "2.1.1" crypto: - dependency: transitive + dependency: "direct main" description: name: crypto url: "https://pub.dartlang.org" @@ -120,6 +120,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0-nullsafety.1" + fast_base58: + dependency: "direct main" + description: + name: fast_base58 + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.9" ffi: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 8b28242..62c0aa6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,8 @@ dependencies: printing: ^4.0.0 shared_preferences: ^0.5.12+4 sync_http: ^0.2.0 + crypto: ^2.1.5 + fast_base58: flutter_icons: