Skip to content
Snippets Groups Projects
wallet_options.dart 21.4 KiB
Newer Older
// ignore_for_file: use_build_context_synchronously

import 'dart:io';
Hugo Trentesaux's avatar
Hugo Trentesaux committed
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';
import 'package:gecko/globals.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/duniter_indexer.dart';
import 'package:gecko/providers/my_wallets.dart';
poka's avatar
poka committed
import 'package:gecko/models/wallet_data.dart';
poka's avatar
poka committed
import 'package:gecko/providers/substrate_sdk.dart';
poka's avatar
poka committed
import 'package:gecko/screens/animated_text.dart';
import 'package:gecko/screens/common_elements.dart';
poka's avatar
poka committed
import 'package:gecko/screens/myWallets/unlocking_wallet.dart';
import 'package:gecko/screens/transaction_in_progress.dart';
poka's avatar
poka committed
import 'package:image_picker/image_picker.dart';
poka's avatar
poka committed
import 'package:provider/provider.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:truncate/truncate.dart';

class WalletOptionsProvider with ChangeNotifier {
  TextEditingController address = TextEditingController();
poka's avatar
poka committed
  final TextEditingController _newWalletName = TextEditingController();
  bool isWalletUnlock = false;
  bool ischangedPin = false;
poka's avatar
poka committed
  TextEditingController newPin = TextEditingController();
  bool isEditing = false;
poka's avatar
poka committed
  bool isBalanceBlur = false;
  FocusNode walletNameFocus = FocusNode();
  TextEditingController nameController = TextEditingController();
poka's avatar
poka committed
  late bool isDefaultWallet;
poka's avatar
poka committed
  bool canValidateNameBool = false;
  Map<String, String> idtyStatusCache = {};
poka's avatar
poka committed
  Future<NewWallet>? get badWallet => null;
  int getPinLenght(walletNbr) {
  void _renameWallet(List<int?> walletID, String newName,
      {required bool isCesium}) async {
poka's avatar
poka committed
    MyWalletsProvider myWalletClass = MyWalletsProvider();
    WalletData walletTarget = myWalletClass.getWalletDataById(walletID)!;
    walletTarget.name = newName;
    await walletBox.put(walletTarget.key, walletTarget);
poka's avatar
poka committed

    _newWalletName.text = '';
  Future<int> deleteWallet(context, WalletData wallet) async {
    SubstrateSdk sub = Provider.of<SubstrateSdk>(context, listen: false);
    final bool? answer = await (confirmPopup(
        context, 'areYouSureToForgetWallet'.tr(args: [wallet.name!])));
    if (answer ?? false) {
      final balance = await sub.getBalance(wallet.address!);
      if (balance != {}) {
        MyWalletsProvider myWalletProvider =
            Provider.of<MyWalletsProvider>(context, listen: false);
        final defaultWallet = myWalletProvider.getDefaultWallet();
        log.d(defaultWallet.address);
        sub.pay(
            destAddress: defaultWallet.address!,
            password: myWalletProvider.pinCode);
      await walletBox.delete(wallet.key);
      await sub.deleteAccounts([wallet.address!]);
      Navigator.pop(context);
poka's avatar
poka committed
    return 0;
  void bluringBalance() {
    isBalanceBlur = !isBalanceBlur;
    notifyListeners();
  }

  Future<String> changeAvatar() async {
    // File _image;
poka's avatar
poka committed
    final picker = ImagePicker();

poka's avatar
poka committed
    XFile? pickedFile = await picker.pickImage(source: ImageSource.gallery);
poka's avatar
poka committed

    if (pickedFile != null) {
      File imageFile = File(pickedFile.path);
      if (!await imageDirectory.exists()) {
        log.e("Image folder doesn't exist");
        return '';
      }

      CroppedFile? croppedFile = await ImageCropper().cropImage(
        sourcePath: imageFile.path,
        aspectRatioPresets: [CropAspectRatioPreset.square],
        cropStyle: CropStyle.circle,
        uiSettings: [
          AndroidUiSettings(
              hideBottomControls: true,
              toolbarTitle: 'Personnalisation',
              toolbarColor: Colors.deepOrange,
              toolbarWidgetColor: Colors.white,
              initAspectRatio: CropAspectRatioPreset.original,
              lockAspectRatio: true),
          IOSUiSettings(
            title: 'Cropper',
          ),
        ],
      );
      final newPath = "${imageDirectory.path}/${pickedFile.name}";
      if (croppedFile != null) {
        await File(croppedFile.path).rename(newPath);
      } else {
        log.w('No image selected.');
        return '';
      }
      // await imageFile.copy(newPath);
poka's avatar
poka committed
    } else {
poka's avatar
poka committed
      log.w('No image selected.');
poka's avatar
poka committed
  Widget idtyStatus(BuildContext context, String address,
poka's avatar
poka committed
      {bool isOwner = false, Color color = Colors.black}) {
    DuniterIndexer duniterIndexer =
        Provider.of<DuniterIndexer>(context, listen: false);
poka's avatar
poka committed

poka's avatar
poka committed
    showText(String text,
        [double size = 18, bool bold = false, bool smooth = true]) {
      log.d('$address $text');
poka's avatar
poka committed
      return AnimatedFadeOutIn<String>(
        data: text,
        duration: Duration(milliseconds: smooth ? 200 : 0),
        builder: (value) => Text(
          value,
          textAlign: TextAlign.center,
          style: TextStyle(
              fontSize: size,
              color: bold ? color : Colors.black,
              fontWeight: bold ? FontWeight.w500 : FontWeight.w400),
    return Consumer<SubstrateSdk>(builder: (context, sub, _) {
poka's avatar
poka committed
      return FutureBuilder(
          future: sub.idtyStatus(address),
poka's avatar
poka committed
          initialData: '',
poka's avatar
poka committed
          builder: (context, snapshot) {
            idtyStatusCache[address] = snapshot.data.toString();
poka's avatar
poka committed
            switch (snapshot.data.toString()) {
              case 'noid':
                {
poka's avatar
poka committed
                  return showText('noIdentity'.tr());
poka's avatar
poka committed
                }
              case 'Created':
                {
poka's avatar
poka committed
                  return showText('identityCreated'.tr());
poka's avatar
poka committed
                }
              case 'ConfirmedByOwner':
                {
poka's avatar
poka committed
                      ? showText('identityConfirmed'.tr())
                      : duniterIndexer.getNameByAddress(
poka's avatar
poka committed
                          context,
                          address,
                          null,
                          20,
                          true,
                          Colors.grey[700]!,
                          FontWeight.w500,
                          FontStyle.italic);
poka's avatar
poka committed
                }

              case 'Validated':
                {
poka's avatar
poka committed
                      ? showText('memberValidated'.tr(), 18, true)
                      : duniterIndexer.getNameByAddress(
poka's avatar
poka committed
                          context,
                          address,
                          null,
                          20,
                          true,
                          Colors.black,
                          FontWeight.w600,
                          FontStyle.normal);
poka's avatar
poka committed
                }

              case 'expired':
                {
poka's avatar
poka committed
                  return showText('identityExpired'.tr());
poka's avatar
poka committed
                }
            }
            return SizedBox(
poka's avatar
poka committed
              child: showText('', 18, false, false),
poka's avatar
poka committed
  Future<bool> isMember(BuildContext context, String address) async {
    SubstrateSdk sub = Provider.of<SubstrateSdk>(context, listen: false);
    return await sub.idtyStatus(address) == 'Validated';
  Future<String?> confirmIdentityPopup(BuildContext context) async {
poka's avatar
poka committed
    TextEditingController idtyName = TextEditingController();
    SubstrateSdk sub = Provider.of<SubstrateSdk>(context, listen: false);
    WalletOptionsProvider walletOptions =
poka's avatar
poka committed
        Provider.of<WalletOptionsProvider>(context, listen: false);
    MyWalletsProvider myWalletProvider =
poka's avatar
poka committed
        Provider.of<MyWalletsProvider>(context, listen: false);

    return showDialog<String>(
      context: context,
      barrierDismissible: true, // user must tap button!
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text(
            'confirmYourIdentity'.tr(),
            style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
poka's avatar
poka committed
          content: SizedBox(
            height: 100,
            child: Column(children: [
poka's avatar
poka committed
              TextField(
                key: keyEnterIdentityUsername,
                onChanged: (_) => notifyListeners(),
                inputFormatters: <TextInputFormatter>[
                  // FilteringTextInputFormatter.allow(RegExp("[0-9a-zA-Z]")),
                  FilteringTextInputFormatter.deny(RegExp(r'^ ')),
                  // FilteringTextInputFormatter.deny(RegExp(r' $')),
                ],
                autofocus: true,
poka's avatar
poka committed
                controller: idtyName,
                style: const TextStyle(fontSize: 19),
poka's avatar
poka committed
              )
            ]),
          ),
          actions: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Consumer<WalletOptionsProvider>(
                    builder: (context, wOptions, _) {
poka's avatar
poka committed
                    key: keyConfirm,
Hugo Trentesaux's avatar
Hugo Trentesaux committed
                      "validate".tr(),
                        color: idtyName.text.length.clamp(3, 64) ==
                                idtyName.text.length
                            ? const Color(0xffD80000)
                            : Colors.grey,
                      ),
                    ),
                    onPressed: () async {
                      idtyName.text = idtyName.text.trim().replaceAll('  ', '');

                      if (idtyName.text.length.clamp(3, 64) ==
                          idtyName.text.length) {
poka's avatar
poka committed
                        WalletData? defaultWallet =
                            myWalletProvider.getDefaultWallet();
poka's avatar
poka committed

                        String? pin;
                        if (myWalletProvider.pinCode == '') {
                          pin = await Navigator.push(
poka's avatar
poka committed
                            context,
                            MaterialPageRoute(
                              builder: (homeContext) {
                                return UnlockingWallet(wallet: defaultWallet);
                              },
                            ),
                          );
                        }
                        if (pin != null || myWalletProvider.pinCode != '') {
                          final wallet = myWalletProvider
poka's avatar
poka committed
                              .getWalletDataByAddress(address.text);
                          await sub.setCurrentWallet(wallet!);
                          sub.confirmIdentity(walletOptions.address.text,
                              idtyName.text, myWalletProvider.pinCode);
poka's avatar
poka committed
                          Navigator.pop(context);

                          Navigator.push(
                            context,
                            MaterialPageRoute(builder: (context) {
                              return TransactionInProgress(
                                transType: 'comfirmIdty',
                                fromAddress: getShortPubkey(wallet.address!),
                                toAddress: getShortPubkey(wallet.address!),
poka's avatar
poka committed
                            }),
                          );
                        }
poka's avatar
poka committed
            ),
  Future<String?> editWalletName(BuildContext context, List<int?> wID) async {
poka's avatar
poka committed
    TextEditingController walletName = TextEditingController();
    canValidateNameBool = false;

    return showDialog<String>(
      context: context,
      barrierDismissible: true,
      builder: (BuildContext context) {
        return AlertDialog(
Hugo Trentesaux's avatar
Hugo Trentesaux committed
          title: Text(
            'chooseWalletName'.tr(),
poka's avatar
poka committed
            textAlign: TextAlign.center,
Hugo Trentesaux's avatar
Hugo Trentesaux committed
            style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
poka's avatar
poka committed
          ),
          content: SizedBox(
            height: 100,
            child: Column(children: [
              const SizedBox(height: 20),
              TextField(
                onChanged: (_) => canValidateName(context, walletName),
                textAlign: TextAlign.center,
                autofocus: true,
                controller: walletName,
                style: const TextStyle(fontSize: 19),
              )
            ]),
          ),
          actions: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Consumer<WalletOptionsProvider>(
                    builder: (context, wOptions, _) {
poka's avatar
poka committed
                  return TextButton(
poka's avatar
poka committed
                    child: Text(
Hugo Trentesaux's avatar
Hugo Trentesaux committed
                      "validate".tr(),
poka's avatar
poka committed
                      style: TextStyle(
                        fontSize: 21,
                        color: canValidateNameBool
                            ? const Color(0xffD80000)
                            : Colors.grey,
                        fontWeight: FontWeight.w600,
                      ),
                    ),
                    onPressed: () async {
                      if (canValidateNameBool) {
                        nameController.text = walletName.text;
                        _renameWallet(wID, walletName.text, isCesium: false);
poka's avatar
poka committed
                        // notifyListeners();
                        Navigator.pop(context);
                      }
                    },
                  );
                })
              ],
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                TextButton(
poka's avatar
poka committed
                  child: Text(
poka's avatar
poka committed
                    "cancel".tr(),
poka's avatar
poka committed
                    style: TextStyle(
                        fontSize: 18,
                        color: Colors.grey[800],
                        fontWeight: FontWeight.w300),
                  ),
                  onPressed: () async {
                    Navigator.pop(context);
                  },
                )
              ],
            ),
            const SizedBox(height: 20)
          ],
        );
      },
    );
  }

  bool canValidateName(BuildContext context, TextEditingController walletName) {
    MyWalletsProvider myWalletProvider =
poka's avatar
poka committed
        Provider.of<MyWalletsProvider>(context, listen: false);

    bool isNameValid = walletName.text.length >= 2 &&
        !walletName.text.contains(':') &&
        walletName.text.length <= 39;

    if (isNameValid) {
      for (var wallet in myWalletProvider.listWallets) {
poka's avatar
poka committed
        if (walletName.text == wallet.name!) {
          canValidateNameBool = false;
          break;
        }
        canValidateNameBool = true;
      }
    } else {
      canValidateNameBool = false;
    }
    notifyListeners();
    return canValidateNameBool;
  }

poka's avatar
poka committed
  void reload() {
    notifyListeners();
  }
  Future changePinCacheChoice() async {
    bool isCacheChecked = configBox.get('isCacheChecked') ?? false;
    await configBox.put('isCacheChecked', !isCacheChecked);
    notifyListeners();
  }

  String? getAddress(int chest, int derivation) {
    String? addressGet;
    walletBox.toMap().forEach((key, value) {
poka's avatar
poka committed
      if (value.chest == chest && value.derivation == derivation) {
        addressGet = value.address!;
    address.text = addressGet ?? '';
    return addressGet;

  Widget walletNameController(BuildContext context, WalletData wallet,
      [double size = 20]) {
    nameController.text = wallet.name!;

    return SizedBox(
      width: 260,
      child: Stack(children: <Widget>[
        TextField(
          autofocus: false,
          focusNode: walletNameFocus,
          enabled: isEditing,
          controller: nameController,
          minLines: 1,
          maxLines: 3,
          textAlign: TextAlign.center,
          decoration: const InputDecoration(
            border: InputBorder.none,
            focusedBorder: InputBorder.none,
            enabledBorder: InputBorder.none,
            disabledBorder: InputBorder.none,
            contentPadding: EdgeInsets.all(15.0),
          ),
          style: TextStyle(
            fontSize: isTall ? size : size * 0.9,
            color: Colors.black,
            fontWeight: FontWeight.w400,
          ),
        ),
        Positioned(
          right: 0,
          child: InkWell(
            onTap: () async {
              // _isNewNameValid =
              // walletProvider.editWalletName(wallet.id(), isCesium: false);
              await editWalletName(context, wallet.id());
              await Future.delayed(const Duration(milliseconds: 30));
              walletNameFocus.requestFocus();
            },
            child: ClipRRect(
              child: Image.asset(
                  isEditing
                      ? 'assets/walletOptions/android-checkmark.png'
                      : 'assets/walletOptions/edit.png',
                  width: 25,
                  height: 25),
            ),
          ),
        ),
      ]),
    );
  }

  Widget walletName(BuildContext context, WalletData wallet,
      [double size = 20, Color color = Colors.black]) {
    double newSize = wallet.name!.length <= 15 ? size : size - 2;

    return Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
      Text(
        truncate(wallet.name!, 20),
        textAlign: TextAlign.center,
        style: TextStyle(
          fontSize: isTall ? newSize : newSize * 0.9,
          color: color,
          fontWeight: FontWeight.w400,
          fontStyle: FontStyle.italic,
        softWrap: false,
        overflow: TextOverflow.ellipsis,
      ),
    ]);
poka's avatar
poka committed

poka's avatar
poka committed
Map<String, double> balanceCache = {};
poka's avatar
poka committed

Widget balance(BuildContext context, String address, double size,
    [Color color = Colors.black,
    Color loadingColor = const Color(0xffd07316)]) {
poka's avatar
poka committed
  return Column(children: <Widget>[
    Consumer<SubstrateSdk>(builder: (context, sdk, _) {
poka's avatar
poka committed
      return FutureBuilder(
          future: sdk.getBalance(address),
          builder: (BuildContext context,
              AsyncSnapshot<Map<String, double>> globalBalance) {
            if (globalBalance.connectionState != ConnectionState.done ||
                globalBalance.hasError) {
              if (balanceCache[address] != null &&
                  balanceCache[address] != -1) {
poka's avatar
poka committed
                return Row(children: [
                  Text(balanceCache[address]!.toString(),
                      style: TextStyle(
                          fontSize: isTall ? size : size * 0.9, color: color)),
                  const SizedBox(width: 5),
                  udUnitDisplay(size, color),
                ]);
poka's avatar
poka committed
              } else {
                return SizedBox(
                  height: 15,
                  width: 15,
                  child: CircularProgressIndicator(
                    color: loadingColor,
poka's avatar
poka committed
                    strokeWidth: 2,
                  ),
                );
              }
poka's avatar
poka committed
            }
            balanceCache[address] = globalBalance.data!['transferableBalance']!;
            if (balanceCache[address] != -1) {
poka's avatar
poka committed
              return Row(children: [
                Text(
                  balanceCache[address]!.toString(),
                  style: TextStyle(
                    fontSize: isTall ? size : size * 0.9,
                    color: color,
                  ),
poka's avatar
poka committed
                const SizedBox(width: 5),
                udUnitDisplay(size, color),
              ]);
poka's avatar
poka committed
          });
    }),
  ]);
}
poka's avatar
poka committed

Widget getCerts(BuildContext context, String address, double size,
    [Color color = Colors.black]) {
poka's avatar
poka committed
  return Column(children: <Widget>[
    Consumer<SubstrateSdk>(builder: (context, sdk, _) {
poka's avatar
poka committed
      return FutureBuilder(
          future: sdk.getCerts(address),
          builder: (BuildContext context, AsyncSnapshot<List<int>> certs) {
            // log.d(_certs.data);
            return certs.data?[0] != 0 && certs.data != null
poka's avatar
poka committed
                      Image.asset('assets/medal.png', height: 20),
                      const SizedBox(width: 1),
                      Text(certs.data?[0].toString() ?? '0',
poka's avatar
poka committed
                          style: const TextStyle(fontSize: 20)),
                      const SizedBox(width: 5),
                      Text(
                        "(${certs.data?[1].toString() ?? '0'})",
poka's avatar
poka committed
                        style: const TextStyle(fontSize: 14),
                      )
poka's avatar
poka committed
          });
    }),
  ]);
}
poka's avatar
poka committed

Widget udUnitDisplay(double size, [Color color = Colors.black]) {
  final bool isUdUnit = configBox.get('isUdUnit') ?? false;
  return isUdUnit
      ? Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            Text(
poka's avatar
poka committed
              'ud'.tr(args: ['']),
poka's avatar
poka committed
              style:
                  TextStyle(fontSize: isTall ? size : size * 0.9, color: color),
            ),
            Column(
              children: [
                Text(
                  currencyName,
                  style: TextStyle(
                      fontSize: (isTall ? size : size * 0.9) * 0.7,
                      fontWeight: FontWeight.w500,
                      color: color),
                ),
                const SizedBox(height: 15)
              ],
            )
          ],
        )
      : Text(currencyName,
          style: TextStyle(fontSize: isTall ? size : size * 0.9, color: color));
}