mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-16 09:17:37 +00:00
Merge branch 'testing' into monerodart_testing
This commit is contained in:
commit
fe98b1b215
33 changed files with 849 additions and 1301 deletions
Binary file not shown.
Binary file not shown.
|
@ -1 +1 @@
|
|||
Subproject commit 032407f0f7734f3cec3eefba76c5dc587b9a252d
|
||||
Subproject commit b654bf4488357c8a104900e11f9468d54a39f22b
|
|
@ -9,10 +9,22 @@ Here you will find instructions on how to install the necessary tools for buildi
|
|||
- 100 GB of storage
|
||||
|
||||
## Linux host
|
||||
|
||||
The following instructions are for building and running on a Linux host. Alternatively, see the [Mac](#mac-host) and/or [Windows](#windows-host) section. This entire section (except for the Android Studio section) needs to be completed in WSL if building on a Windows host.
|
||||
|
||||
### Flutter
|
||||
Install Flutter 3.19.5 by following these instructions: https://docs.flutter.dev/get-started/install/linux/desktop?tab=download#install-the-flutter-sdk. You can also clone https://github.com/flutter/flutter, check out the `3.19.5` tag, and add its `flutter/bin` folder to your PATH. Run `flutter doctor` in a terminal to confirm its installation.
|
||||
Install Flutter 3.19.6 by [following their guide](https://docs.flutter.dev/get-started/install/linux/desktop?tab=download#install-the-flutter-sdk). You can also clone https://github.com/flutter/flutter, check out the `3.19.6` tag, and add its `flutter/bin` folder to your PATH as in
|
||||
```sh
|
||||
FLUTTER_DIR="$HOME/development/flutter"
|
||||
git clone https://github.com/flutter/flutter.git "$FLUTTER_DIR"
|
||||
cd "$FLUTTER_DIR"
|
||||
git checkout 3.16.9
|
||||
echo 'export PATH="$PATH:'"$FLUTTER_DIR"'/bin"' >> "$HOME/.profile"
|
||||
source "$HOME/.profile"
|
||||
flutter precache
|
||||
```
|
||||
|
||||
Run `flutter doctor` in a terminal to confirm its installation.
|
||||
|
||||
### Android Studio
|
||||
Install Android Studio. Follow instructions here [https://developer.android.com/studio/install#linux](https://developer.android.com/studio/install#linux) or install via snap:
|
||||
|
@ -38,17 +50,7 @@ The following *may* be needed for Android studio:
|
|||
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386
|
||||
```
|
||||
|
||||
### Flutter
|
||||
|
||||
Flutter and the Dart SDK should have been set up by Android studio, but if running `flutter` doesn't work (try `flutter doctor`, too), follow the [guide to install Flutter on any of their supported platforms](https://docs.flutter.dev/get-started/install) or:
|
||||
- `git clone https://github.com/flutter/flutter` somewhere it can live (`/var`, `/opt`, `~`)
|
||||
- `git checkout 3.16.0` after navigating into the `flutter` directory, and
|
||||
- add `flutter/bin` to your PATH (on Ubuntu, add `PATH=$PATH:path/to/flutter/bin` to `~/.profile`).
|
||||
|
||||
Run `flutter doctor` to install any missing dependencies and review and agree to any license agreements.
|
||||
|
||||
### Build dependencies
|
||||
|
||||
Install basic dependencies
|
||||
```
|
||||
sudo apt-get install libssl-dev curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev llvm python3-distutils g++ gcc gperf
|
||||
|
@ -104,7 +106,7 @@ Coinlib's native secp256k1 library must be built prior to running Stack Wallet.
|
|||
|
||||
To build coinlib on Linux, you will need `docker` (see [installation instructions](https://docs.docker.com/engine/install/ubuntu/)) or [`podman`](https://podman.io/docs/installation) (`sudo apt-get -y install podman`)
|
||||
|
||||
For Windows targets, you can use a `secp256k1.dll` produced by any of the three middle options if the first attempt doesn't succeed!
|
||||
For Windows targets, you can use a `secp256k1.dll` produced by any of the three middle options if the first attempt doesn't succeed.
|
||||
|
||||
### Run prebuild script
|
||||
|
||||
|
@ -221,7 +223,6 @@ cd scripts/macos
|
|||
```
|
||||
|
||||
### Run prebuild script
|
||||
|
||||
Certain test wallet parameter and API key template files must be created in order to run Stack Wallet. These can be created by script as in
|
||||
```
|
||||
cd scripts
|
||||
|
@ -247,6 +248,7 @@ flutter run macos
|
|||
```
|
||||
|
||||
## Windows host
|
||||
|
||||
### Visual Studio
|
||||
Visual Studio is required for Windows development with the Flutter SDK. Download it at https://visualstudio.microsoft.com/downloads/ and install the "Desktop development with C++", "Linux development with C++", and "Visual C++ build tools" workloads. You may also need the Windows 10, 11, and/or Universal SDK workloads depending on your Windows version.
|
||||
|
||||
|
@ -280,7 +282,18 @@ Copy the resulting `dll`s to their respective positions on the Windows host:
|
|||
Frostdart will be built by the Windows host later.
|
||||
|
||||
### Install Flutter on Windows host
|
||||
Install Flutter 3.19.5 on your Windows host (not in WSL2) by following these instructions: https://docs.flutter.dev/get-started/install/windows/desktop?tab=download#install-the-flutter-sdk. You can also clone https://github.com/flutter/flutter, check out the `3.19.5` tag, and add its `flutter/bin` folder to your PATH. Run `flutter doctor` in PowerShell to confirm its installation.
|
||||
Install Flutter 3.19.6 on your Windows host (not in WSL2) by [following their guide](https://docs.flutter.dev/get-started/install/windows/desktop?tab=download#install-the-flutter-sdk) or by cloning https://github.com/flutter/flutter, checking out the `3.19.6` tag, and adding its `flutter/bin` folder to your PATH as in
|
||||
```bat
|
||||
@echo off
|
||||
set "FLUTTER_DIR=%USERPROFILE%\development\flutter"
|
||||
git clone https://github.com/flutter/flutter.git "%FLUTTER_DIR%"
|
||||
cd /d "%FLUTTER_DIR%"
|
||||
git checkout 3.16.9
|
||||
setx PATH "%PATH%;%FLUTTER_DIR%\bin"
|
||||
echo Flutter setup completed. Please restart your command prompt.
|
||||
```
|
||||
|
||||
Run `flutter doctor` in PowerShell to confirm its installation.
|
||||
|
||||
### Rust
|
||||
Install [Rust](https://www.rust-lang.org/tools/install) on the Windows host (not in WSL2). Download the installer from [rustup.rs](https://rustup.rs), make sure it works on the commandline (you may need to open a new terminal), and install the following versions:
|
||||
|
|
|
@ -170,11 +170,11 @@ enum AddressType {
|
|||
String get readableName {
|
||||
switch (this) {
|
||||
case AddressType.p2pkh:
|
||||
return "Legacy";
|
||||
return "P2PKH";
|
||||
case AddressType.p2sh:
|
||||
return "Wrapped segwit";
|
||||
case AddressType.p2wpkh:
|
||||
return "Segwit";
|
||||
return "P2WPKH (segwit)";
|
||||
case AddressType.cryptonote:
|
||||
return "Cryptonote";
|
||||
case AddressType.mimbleWimble:
|
||||
|
@ -200,7 +200,7 @@ enum AddressType {
|
|||
case AddressType.solana:
|
||||
return "Solana";
|
||||
case AddressType.p2tr:
|
||||
return "Taproot"; // Why not use P2TR, P2PKH, etc.?
|
||||
return "P2TR (taproot)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
@ -128,9 +129,9 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> {
|
|||
_searchFocusNode = FocusNode();
|
||||
// _coinsTestnet.remove(Coin.firoTestNet);
|
||||
|
||||
// Remove Solana from the list of coins based on our frostEnabled preference.
|
||||
if (!ref.read(prefsChangeNotifierProvider).solanaEnabled) {
|
||||
_coins.remove(Coin.solana);
|
||||
if (Util.isDesktop && !kDebugMode) {
|
||||
_coins.remove(Coin.bitcoinFrost);
|
||||
_coins.remove(Coin.bitcoinFrostTestNet);
|
||||
}
|
||||
|
||||
coinEntities.addAll(_coins.map((e) => CoinEntity(e)));
|
||||
|
|
|
@ -11,9 +11,7 @@
|
|||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_rounded_date_picker/flutter_rounded_date_picker.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart';
|
||||
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/mobile_mnemonic_length_selector.dart';
|
||||
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart';
|
||||
|
@ -24,7 +22,6 @@ import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/sub_widge
|
|||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
|
||||
import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart';
|
||||
import 'package:stackwallet/themes/stack_colors.dart';
|
||||
import 'package:stackwallet/themes/theme_providers.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
@ -33,6 +30,7 @@ import 'package:stackwallet/utilities/text_styles.dart';
|
|||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/date_picker/date_picker.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||
import 'package:stackwallet/widgets/expandable.dart';
|
||||
|
@ -42,10 +40,10 @@ import 'package:tuple/tuple.dart';
|
|||
|
||||
class RestoreOptionsView extends ConsumerStatefulWidget {
|
||||
const RestoreOptionsView({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.walletName,
|
||||
required this.coin,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
static const routeName = "/restoreOptions";
|
||||
|
||||
|
@ -68,7 +66,6 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
|||
|
||||
final bool _nextEnabled = true;
|
||||
DateTime _restoreFromDate = DateTime.fromMillisecondsSinceEpoch(0);
|
||||
late final Color baseColor;
|
||||
bool hidePassword = true;
|
||||
bool _expandedAdavnced = false;
|
||||
|
||||
|
@ -77,7 +74,6 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
baseColor = ref.read(themeProvider.state).state.textSubtitle2;
|
||||
walletName = widget.walletName;
|
||||
coin = widget.coin;
|
||||
isDesktop = Util.isDesktop;
|
||||
|
@ -99,52 +95,6 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
MaterialRoundedDatePickerStyle _buildDatePickerStyle() {
|
||||
return MaterialRoundedDatePickerStyle(
|
||||
paddingMonthHeader: const EdgeInsets.only(top: 11),
|
||||
colorArrowNext: Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||
colorArrowPrevious:
|
||||
Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||
textStyleButtonNegative: STextStyles.datePicker600(context).copyWith(
|
||||
color: baseColor,
|
||||
),
|
||||
textStyleButtonPositive: STextStyles.datePicker600(context).copyWith(
|
||||
color: baseColor,
|
||||
),
|
||||
textStyleCurrentDayOnCalendar: STextStyles.datePicker400(context),
|
||||
textStyleDayHeader: STextStyles.datePicker600(context),
|
||||
textStyleDayOnCalendar: STextStyles.datePicker400(context).copyWith(
|
||||
color: baseColor,
|
||||
),
|
||||
textStyleDayOnCalendarDisabled:
|
||||
STextStyles.datePicker400(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle3,
|
||||
),
|
||||
textStyleDayOnCalendarSelected:
|
||||
STextStyles.datePicker400(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
),
|
||||
textStyleMonthYearHeader: STextStyles.datePicker600(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||
),
|
||||
textStyleYearButton: STextStyles.datePicker600(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textWhite,
|
||||
),
|
||||
textStyleButtonAction: GoogleFonts.inter(),
|
||||
);
|
||||
}
|
||||
|
||||
MaterialRoundedYearPickerStyle _buildYearPickerStyle() {
|
||||
return MaterialRoundedYearPickerStyle(
|
||||
textStyleYear: STextStyles.datePicker600(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle2,
|
||||
),
|
||||
textStyleYearSelected: STextStyles.datePicker600(context).copyWith(
|
||||
fontSize: 18,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> nextPressed() async {
|
||||
if (!isDesktop) {
|
||||
// hide keyboard if has focus
|
||||
|
@ -169,67 +119,23 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
|||
}
|
||||
|
||||
Future<void> chooseDate() async {
|
||||
final height = MediaQuery.of(context).size.height;
|
||||
final fetchedColor =
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark;
|
||||
// check and hide keyboard
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(const Duration(milliseconds: 125));
|
||||
}
|
||||
|
||||
final date = await showRoundedDatePicker(
|
||||
context: context,
|
||||
initialDate: DateTime.now(),
|
||||
height: height / 3.0,
|
||||
theme: ThemeData(
|
||||
primarySwatch: Util.createMaterialColor(fetchedColor),
|
||||
),
|
||||
//TODO pick a better initial date
|
||||
// 2007 chosen as that is just before bitcoin launched
|
||||
firstDate: DateTime(2007),
|
||||
lastDate: DateTime.now(),
|
||||
borderRadius: Constants.size.circularBorderRadius * 2,
|
||||
|
||||
textPositiveButton: "SELECT",
|
||||
|
||||
styleDatePicker: _buildDatePickerStyle(),
|
||||
styleYearPicker: _buildYearPickerStyle(),
|
||||
);
|
||||
if (date != null) {
|
||||
_restoreFromDate = date;
|
||||
_dateController.text = Format.formatDate(date);
|
||||
if (mounted) {
|
||||
final date = await showSWDatePicker(context);
|
||||
if (date != null) {
|
||||
_restoreFromDate = date;
|
||||
_dateController.text = Format.formatDate(date);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> chooseDesktopDate() async {
|
||||
final height = MediaQuery.of(context).size.height;
|
||||
final fetchedColor =
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark;
|
||||
// check and hide keyboard
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(const Duration(milliseconds: 125));
|
||||
}
|
||||
|
||||
final date = await showRoundedDatePicker(
|
||||
context: context,
|
||||
initialDate: DateTime.now(),
|
||||
height: height / 3.0,
|
||||
theme: ThemeData(
|
||||
primarySwatch: Util.createMaterialColor(fetchedColor),
|
||||
),
|
||||
//TODO pick a better initial date
|
||||
// 2007 chosen as that is just before bitcoin launched
|
||||
firstDate: DateTime(2007),
|
||||
lastDate: DateTime.now(),
|
||||
borderRadius: Constants.size.circularBorderRadius * 2,
|
||||
|
||||
textPositiveButton: "SELECT",
|
||||
|
||||
styleDatePicker: _buildDatePickerStyle(),
|
||||
styleYearPicker: _buildYearPickerStyle(),
|
||||
);
|
||||
final date = await showSWDatePicker(context);
|
||||
if (date != null) {
|
||||
_restoreFromDate = date;
|
||||
_dateController.text = Format.formatDate(date);
|
||||
|
|
|
@ -29,6 +29,7 @@ import 'package:stackwallet/utilities/assets.dart';
|
|||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
|
@ -39,10 +40,10 @@ final exchangeFromAddressBookAddressStateProvider =
|
|||
|
||||
class ContactPopUp extends ConsumerWidget {
|
||||
const ContactPopUp({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.contactId,
|
||||
this.clipboard = const ClipboardWrapper(),
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
final String contactId;
|
||||
final ClipboardInterface clipboard;
|
||||
|
@ -384,13 +385,18 @@ class ContactPopUp extends ConsumerWidget {
|
|||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
padding:
|
||||
const EdgeInsets.all(4),
|
||||
padding: EdgeInsets.all(
|
||||
Util.isDesktop ? 4 : 6,
|
||||
),
|
||||
child: SvgPicture.asset(
|
||||
Assets
|
||||
.svg.circleArrowUpRight,
|
||||
width: 12,
|
||||
height: 12,
|
||||
width: Util.isDesktop
|
||||
? 12
|
||||
: 16,
|
||||
height: Util.isDesktop
|
||||
? 12
|
||||
: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<
|
||||
StackColors>()!
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_rounded_date_picker/flutter_rounded_date_picker.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/themes/stack_colors.dart';
|
||||
import 'package:stackwallet/themes/theme_providers.dart';
|
||||
|
@ -21,6 +20,7 @@ import 'package:stackwallet/utilities/text_styles.dart';
|
|||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/background.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/date_picker/date_picker.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
|
@ -69,8 +69,8 @@ final ordinalFilterProvider = StateProvider<OrdinalFilter?>((_) => null);
|
|||
|
||||
class OrdinalsFilterView extends ConsumerStatefulWidget {
|
||||
const OrdinalsFilterView({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
super.key,
|
||||
});
|
||||
|
||||
static const String routeName = "/ordinalsFilterView";
|
||||
|
||||
|
@ -146,56 +146,6 @@ class _OrdinalsFilterViewState extends ConsumerState<OrdinalsFilterView> {
|
|||
DateTime? _selectedFromDate = DateTime(2007);
|
||||
DateTime? _selectedToDate = DateTime.now();
|
||||
|
||||
MaterialRoundedDatePickerStyle _buildDatePickerStyle() {
|
||||
return MaterialRoundedDatePickerStyle(
|
||||
backgroundPicker: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
// backgroundHeader: Theme.of(context).extension<StackColors>()!.textSubtitle2,
|
||||
paddingMonthHeader: const EdgeInsets.only(top: 11),
|
||||
colorArrowNext: Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||
colorArrowPrevious:
|
||||
Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||
textStyleButtonNegative: STextStyles.datePicker600(context).copyWith(
|
||||
color: baseColor,
|
||||
),
|
||||
textStyleButtonPositive: STextStyles.datePicker600(context).copyWith(
|
||||
color: baseColor,
|
||||
),
|
||||
textStyleCurrentDayOnCalendar: STextStyles.datePicker400(context),
|
||||
textStyleDayHeader: STextStyles.datePicker600(context),
|
||||
textStyleDayOnCalendar: STextStyles.datePicker400(context).copyWith(
|
||||
color: baseColor,
|
||||
),
|
||||
textStyleDayOnCalendarDisabled:
|
||||
STextStyles.datePicker400(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle3,
|
||||
),
|
||||
textStyleDayOnCalendarSelected:
|
||||
STextStyles.datePicker400(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textWhite,
|
||||
),
|
||||
textStyleMonthYearHeader: STextStyles.datePicker600(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||
),
|
||||
textStyleYearButton: STextStyles.datePicker600(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textWhite,
|
||||
),
|
||||
// textStyleButtonAction: GoogleFonts.inter(),
|
||||
);
|
||||
}
|
||||
|
||||
MaterialRoundedYearPickerStyle _buildYearPickerStyle() {
|
||||
return MaterialRoundedYearPickerStyle(
|
||||
backgroundPicker: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
textStyleYear: STextStyles.datePicker600(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle2,
|
||||
fontSize: 16,
|
||||
),
|
||||
textStyleYearSelected: STextStyles.datePicker600(context).copyWith(
|
||||
fontSize: 18,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDateRangePicker() {
|
||||
const middleSeparatorPadding = 2.0;
|
||||
const middleSeparatorWidth = 12.0;
|
||||
|
@ -216,9 +166,6 @@ class _OrdinalsFilterViewState extends ConsumerState<OrdinalsFilterView> {
|
|||
child: GestureDetector(
|
||||
key: const Key("OrdinalsViewFromDatePickerKey"),
|
||||
onTap: () async {
|
||||
final color =
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark;
|
||||
final height = MediaQuery.of(context).size.height;
|
||||
// check and hide keyboard
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
|
@ -226,28 +173,7 @@ class _OrdinalsFilterViewState extends ConsumerState<OrdinalsFilterView> {
|
|||
}
|
||||
|
||||
if (mounted) {
|
||||
final date = await showRoundedDatePicker(
|
||||
// This doesn't change statusbar color...
|
||||
// background: CFColors.starryNight.withOpacity(0.8),
|
||||
context: context,
|
||||
initialDate: DateTime.now(),
|
||||
height: height * 0.5,
|
||||
theme: ThemeData(
|
||||
primarySwatch: Util.createMaterialColor(
|
||||
color,
|
||||
),
|
||||
),
|
||||
//TODO pick a better initial date
|
||||
// 2007 chosen as that is just before bitcoin launched
|
||||
firstDate: DateTime(2007),
|
||||
lastDate: DateTime.now(),
|
||||
borderRadius: Constants.size.circularBorderRadius * 2,
|
||||
|
||||
textPositiveButton: "SELECT",
|
||||
|
||||
styleDatePicker: _buildDatePickerStyle(),
|
||||
styleYearPicker: _buildYearPickerStyle(),
|
||||
);
|
||||
final date = await showSWDatePicker(context);
|
||||
if (date != null) {
|
||||
_selectedFromDate = date;
|
||||
|
||||
|
@ -330,9 +256,6 @@ class _OrdinalsFilterViewState extends ConsumerState<OrdinalsFilterView> {
|
|||
child: GestureDetector(
|
||||
key: const Key("OrdinalsViewToDatePickerKey"),
|
||||
onTap: () async {
|
||||
final color =
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark;
|
||||
final height = MediaQuery.of(context).size.height;
|
||||
// check and hide keyboard
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
|
@ -340,28 +263,7 @@ class _OrdinalsFilterViewState extends ConsumerState<OrdinalsFilterView> {
|
|||
}
|
||||
|
||||
if (mounted) {
|
||||
final date = await showRoundedDatePicker(
|
||||
// This doesn't change statusbar color...
|
||||
// background: CFColors.starryNight.withOpacity(0.8),
|
||||
context: context,
|
||||
height: height * 0.5,
|
||||
theme: ThemeData(
|
||||
primarySwatch: Util.createMaterialColor(
|
||||
color,
|
||||
),
|
||||
),
|
||||
//TODO pick a better initial date
|
||||
// 2007 chosen as that is just before bitcoin launched
|
||||
initialDate: DateTime.now(),
|
||||
firstDate: DateTime(2007),
|
||||
lastDate: DateTime.now(),
|
||||
borderRadius: Constants.size.circularBorderRadius * 2,
|
||||
|
||||
textPositiveButton: "SELECT",
|
||||
|
||||
styleDatePicker: _buildDatePickerStyle(),
|
||||
styleYearPicker: _buildYearPickerStyle(),
|
||||
);
|
||||
final date = await showSWDatePicker(context);
|
||||
if (date != null) {
|
||||
_selectedToDate = date;
|
||||
|
||||
|
@ -467,7 +369,7 @@ class _OrdinalsFilterViewState extends ConsumerState<OrdinalsFilterView> {
|
|||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(const Duration(milliseconds: 75));
|
||||
}
|
||||
if (mounted) {
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
|
@ -840,7 +742,7 @@ class _OrdinalsFilterViewState extends ConsumerState<OrdinalsFilterView> {
|
|||
);
|
||||
}
|
||||
}
|
||||
if (mounted) {
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
|
|
|
@ -33,6 +33,7 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
|||
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart';
|
||||
import 'package:stackwallet/wallets/wallet/impl/bitcoin_wallet.dart';
|
||||
import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart';
|
||||
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/bcash_interface.dart';
|
||||
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/multi_address_interface.dart';
|
||||
|
@ -198,6 +199,10 @@ class _ReceiveViewState extends ConsumerState<ReceiveView> {
|
|||
}
|
||||
}
|
||||
|
||||
if (_walletAddressTypes.length > 1 && wallet is BitcoinWallet) {
|
||||
_walletAddressTypes.removeWhere((e) => e == AddressType.p2pkh);
|
||||
}
|
||||
|
||||
_addressMap[_walletAddressTypes[_currentIndex]] =
|
||||
ref.read(pWalletReceivingAddress(walletId));
|
||||
|
||||
|
@ -389,7 +394,11 @@ class _ReceiveViewState extends ConsumerState<ReceiveView> {
|
|||
DropdownMenuItem(
|
||||
value: i,
|
||||
child: Text(
|
||||
"${_walletAddressTypes[i].readableName} address",
|
||||
_supportsSpark &&
|
||||
_walletAddressTypes[i] ==
|
||||
AddressType.p2pkh
|
||||
? "Transparent address"
|
||||
: "${_walletAddressTypes[i].readableName} address",
|
||||
style: STextStyles.w500_14(context),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -906,6 +906,10 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
sendToController.text = _data!.contactLabel;
|
||||
_address = _data!.address.trim();
|
||||
_addressToggleFlag = true;
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
_setValidAddressProviders(_address);
|
||||
});
|
||||
}
|
||||
|
||||
if (isPaynymSend) {
|
||||
|
|
|
@ -173,85 +173,91 @@ class _FiroBalanceSelectionSheetState
|
|||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
final state =
|
||||
ref.read(publicPrivateBalanceStateProvider.state).state;
|
||||
if (state != FiroType.lelantus) {
|
||||
ref.read(publicPrivateBalanceStateProvider.state).state =
|
||||
FiroType.lelantus;
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: Radio(
|
||||
activeColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.radioButtonIconEnabled,
|
||||
value: FiroType.lelantus,
|
||||
groupValue: ref
|
||||
.watch(
|
||||
publicPrivateBalanceStateProvider.state)
|
||||
.state,
|
||||
onChanged: (x) {
|
||||
ref
|
||||
.read(publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state = FiroType.lelantus;
|
||||
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
if (firoWallet.info.cachedBalanceSecondary.spendable.raw >
|
||||
BigInt.zero)
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
if (firoWallet.info.cachedBalanceSecondary.spendable.raw >
|
||||
BigInt.zero)
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
final state = ref
|
||||
.read(publicPrivateBalanceStateProvider.state)
|
||||
.state;
|
||||
if (state != FiroType.lelantus) {
|
||||
ref
|
||||
.read(publicPrivateBalanceStateProvider.state)
|
||||
.state = FiroType.lelantus;
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
// Row(
|
||||
// children: [
|
||||
Text(
|
||||
"Lelantus balance",
|
||||
style: STextStyles.titleBold12(context),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 2,
|
||||
),
|
||||
Text(
|
||||
ref.watch(pAmountFormatter(coin)).format(
|
||||
firoWallet.info.cachedBalanceSecondary
|
||||
.spendable,
|
||||
),
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
textAlign: TextAlign.left,
|
||||
SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: Radio(
|
||||
activeColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.radioButtonIconEnabled,
|
||||
value: FiroType.lelantus,
|
||||
groupValue: ref
|
||||
.watch(publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state,
|
||||
onChanged: (x) {
|
||||
ref
|
||||
.read(publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state = FiroType.lelantus;
|
||||
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// ],
|
||||
// ),
|
||||
)
|
||||
],
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Row(
|
||||
// children: [
|
||||
Text(
|
||||
"Lelantus balance",
|
||||
style: STextStyles.titleBold12(context),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 2,
|
||||
),
|
||||
Text(
|
||||
ref.watch(pAmountFormatter(coin)).format(
|
||||
firoWallet.info.cachedBalanceSecondary
|
||||
.spendable,
|
||||
),
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
],
|
||||
),
|
||||
// ],
|
||||
// ),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
@ -277,36 +276,6 @@ class HiddenSettings extends StatelessWidget {
|
|||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Consumer(
|
||||
builder: (_, ref, __) {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.solanaEnabled =
|
||||
!(ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.solanaEnabled);
|
||||
if (kDebugMode) {
|
||||
print(
|
||||
"Solana enabled: ${ref.read(prefsChangeNotifierProvider).solanaEnabled}");
|
||||
}
|
||||
},
|
||||
child: RoundedWhiteContainer(
|
||||
child: Text(
|
||||
"Toggle Solana",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Consumer(
|
||||
builder: (_, ref, __) {
|
||||
return GestureDetector(
|
||||
|
|
|
@ -33,9 +33,9 @@ enum _BalanceType {
|
|||
|
||||
class WalletBalanceToggleSheet extends ConsumerWidget {
|
||||
const WalletBalanceToggleSheet({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.walletId,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
final String walletId;
|
||||
|
||||
|
@ -46,7 +46,7 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
final coin = ref.watch(pWalletCoin(walletId));
|
||||
final isFiro = coin == Coin.firo || coin == Coin.firoTestNet;
|
||||
|
||||
Balance balance = ref.watch(pWalletBalance(walletId));
|
||||
final balance = ref.watch(pWalletBalance(walletId));
|
||||
|
||||
_BalanceType _bal =
|
||||
ref.watch(walletBalanceToggleStateProvider.state).state ==
|
||||
|
@ -77,6 +77,11 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
// already set above
|
||||
break;
|
||||
}
|
||||
|
||||
// hack to not show lelantus balance in ui if zero
|
||||
if (balanceSecondary?.spendable.raw == BigInt.zero) {
|
||||
balanceSecondary = null;
|
||||
}
|
||||
}
|
||||
|
||||
return Container(
|
||||
|
@ -289,7 +294,7 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
|
||||
class BalanceSelector<T> extends ConsumerWidget {
|
||||
const BalanceSelector({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.coin,
|
||||
required this.balance,
|
||||
|
@ -297,7 +302,7 @@ class BalanceSelector<T> extends ConsumerWidget {
|
|||
required this.onChanged,
|
||||
required this.value,
|
||||
required this.groupValue,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
final String title;
|
||||
final Coin coin;
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_rounded_date_picker/flutter_rounded_date_picker.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/models/transaction_filter.dart';
|
||||
import 'package:stackwallet/providers/global/locale_provider.dart';
|
||||
|
@ -29,6 +28,7 @@ import 'package:stackwallet/utilities/text_styles.dart';
|
|||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/background.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/date_picker/date_picker.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
|
@ -40,9 +40,9 @@ import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
|||
|
||||
class TransactionSearchFilterView extends ConsumerStatefulWidget {
|
||||
const TransactionSearchFilterView({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.coin,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
static const String routeName = "/transactionSearchFilter";
|
||||
|
||||
|
@ -137,56 +137,6 @@ class _TransactionSearchViewState
|
|||
DateTime? _selectedFromDate = DateTime(2007);
|
||||
DateTime? _selectedToDate = DateTime.now();
|
||||
|
||||
MaterialRoundedDatePickerStyle _buildDatePickerStyle() {
|
||||
return MaterialRoundedDatePickerStyle(
|
||||
backgroundPicker: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
// backgroundHeader: Theme.of(context).extension<StackColors>()!.textSubtitle2,
|
||||
paddingMonthHeader: const EdgeInsets.only(top: 11),
|
||||
colorArrowNext: Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||
colorArrowPrevious:
|
||||
Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||
textStyleButtonNegative: STextStyles.datePicker600(context).copyWith(
|
||||
color: baseColor,
|
||||
),
|
||||
textStyleButtonPositive: STextStyles.datePicker600(context).copyWith(
|
||||
color: baseColor,
|
||||
),
|
||||
textStyleCurrentDayOnCalendar: STextStyles.datePicker400(context),
|
||||
textStyleDayHeader: STextStyles.datePicker600(context),
|
||||
textStyleDayOnCalendar: STextStyles.datePicker400(context).copyWith(
|
||||
color: baseColor,
|
||||
),
|
||||
textStyleDayOnCalendarDisabled:
|
||||
STextStyles.datePicker400(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle3,
|
||||
),
|
||||
textStyleDayOnCalendarSelected:
|
||||
STextStyles.datePicker400(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textWhite,
|
||||
),
|
||||
textStyleMonthYearHeader: STextStyles.datePicker600(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||
),
|
||||
textStyleYearButton: STextStyles.datePicker600(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textWhite,
|
||||
),
|
||||
// textStyleButtonAction: GoogleFonts.inter(),
|
||||
);
|
||||
}
|
||||
|
||||
MaterialRoundedYearPickerStyle _buildYearPickerStyle() {
|
||||
return MaterialRoundedYearPickerStyle(
|
||||
backgroundPicker: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
textStyleYear: STextStyles.datePicker600(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle2,
|
||||
fontSize: 16,
|
||||
),
|
||||
textStyleYearSelected: STextStyles.datePicker600(context).copyWith(
|
||||
fontSize: 18,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDateRangePicker() {
|
||||
const middleSeparatorPadding = 2.0;
|
||||
const middleSeparatorWidth = 12.0;
|
||||
|
@ -207,58 +157,36 @@ class _TransactionSearchViewState
|
|||
child: GestureDetector(
|
||||
key: const Key("transactionSearchViewFromDatePickerKey"),
|
||||
onTap: () async {
|
||||
final color =
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark;
|
||||
final height = MediaQuery.of(context).size.height;
|
||||
// check and hide keyboard
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(const Duration(milliseconds: 125));
|
||||
}
|
||||
|
||||
final date = await showRoundedDatePicker(
|
||||
// This doesn't change statusbar color...
|
||||
// background: CFColors.starryNight.withOpacity(0.8),
|
||||
context: context,
|
||||
initialDate: DateTime.now(),
|
||||
height: height * 0.5,
|
||||
theme: ThemeData(
|
||||
primarySwatch: Util.createMaterialColor(
|
||||
color,
|
||||
),
|
||||
),
|
||||
//TODO pick a better initial date
|
||||
// 2007 chosen as that is just before bitcoin launched
|
||||
firstDate: DateTime(2007),
|
||||
lastDate: DateTime.now(),
|
||||
borderRadius: Constants.size.circularBorderRadius * 2,
|
||||
if (mounted) {
|
||||
final date = await showSWDatePicker(context);
|
||||
if (date != null) {
|
||||
_selectedFromDate = date;
|
||||
|
||||
textPositiveButton: "SELECT",
|
||||
|
||||
styleDatePicker: _buildDatePickerStyle(),
|
||||
styleYearPicker: _buildYearPickerStyle(),
|
||||
);
|
||||
if (date != null) {
|
||||
_selectedFromDate = date;
|
||||
|
||||
// flag to adjust date so from date is always before to date
|
||||
final flag = _selectedToDate != null &&
|
||||
!_selectedFromDate!.isBefore(_selectedToDate!);
|
||||
if (flag) {
|
||||
_selectedToDate = DateTime.fromMillisecondsSinceEpoch(
|
||||
_selectedFromDate!.millisecondsSinceEpoch);
|
||||
}
|
||||
|
||||
setState(() {
|
||||
// flag to adjust date so from date is always before to date
|
||||
final flag = _selectedToDate != null &&
|
||||
!_selectedFromDate!.isBefore(_selectedToDate!);
|
||||
if (flag) {
|
||||
_toDateString = _selectedToDate == null
|
||||
? ""
|
||||
: Format.formatDate(_selectedToDate!);
|
||||
_selectedToDate = DateTime.fromMillisecondsSinceEpoch(
|
||||
_selectedFromDate!.millisecondsSinceEpoch);
|
||||
}
|
||||
_fromDateString = _selectedFromDate == null
|
||||
? ""
|
||||
: Format.formatDate(_selectedFromDate!);
|
||||
});
|
||||
|
||||
setState(() {
|
||||
if (flag) {
|
||||
_toDateString = _selectedToDate == null
|
||||
? ""
|
||||
: Format.formatDate(_selectedToDate!);
|
||||
}
|
||||
_fromDateString = _selectedFromDate == null
|
||||
? ""
|
||||
: Format.formatDate(_selectedFromDate!);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
|
@ -319,58 +247,36 @@ class _TransactionSearchViewState
|
|||
child: GestureDetector(
|
||||
key: const Key("transactionSearchViewToDatePickerKey"),
|
||||
onTap: () async {
|
||||
final color =
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark;
|
||||
final height = MediaQuery.of(context).size.height;
|
||||
// check and hide keyboard
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(const Duration(milliseconds: 125));
|
||||
}
|
||||
|
||||
final date = await showRoundedDatePicker(
|
||||
// This doesn't change statusbar color...
|
||||
// background: CFColors.starryNight.withOpacity(0.8),
|
||||
context: context,
|
||||
height: height * 0.5,
|
||||
theme: ThemeData(
|
||||
primarySwatch: Util.createMaterialColor(
|
||||
color,
|
||||
),
|
||||
),
|
||||
//TODO pick a better initial date
|
||||
// 2007 chosen as that is just before bitcoin launched
|
||||
initialDate: DateTime.now(),
|
||||
firstDate: DateTime(2007),
|
||||
lastDate: DateTime.now(),
|
||||
borderRadius: Constants.size.circularBorderRadius * 2,
|
||||
if (mounted) {
|
||||
final date = await showSWDatePicker(context);
|
||||
if (date != null) {
|
||||
_selectedToDate = date;
|
||||
|
||||
textPositiveButton: "SELECT",
|
||||
|
||||
styleDatePicker: _buildDatePickerStyle(),
|
||||
styleYearPicker: _buildYearPickerStyle(),
|
||||
);
|
||||
if (date != null) {
|
||||
_selectedToDate = date;
|
||||
|
||||
// flag to adjust date so from date is always before to date
|
||||
final flag = _selectedFromDate != null &&
|
||||
!_selectedToDate!.isAfter(_selectedFromDate!);
|
||||
if (flag) {
|
||||
_selectedFromDate = DateTime.fromMillisecondsSinceEpoch(
|
||||
_selectedToDate!.millisecondsSinceEpoch);
|
||||
}
|
||||
|
||||
setState(() {
|
||||
// flag to adjust date so from date is always before to date
|
||||
final flag = _selectedFromDate != null &&
|
||||
!_selectedToDate!.isAfter(_selectedFromDate!);
|
||||
if (flag) {
|
||||
_fromDateString = _selectedFromDate == null
|
||||
? ""
|
||||
: Format.formatDate(_selectedFromDate!);
|
||||
_selectedFromDate = DateTime.fromMillisecondsSinceEpoch(
|
||||
_selectedToDate!.millisecondsSinceEpoch);
|
||||
}
|
||||
_toDateString = _selectedToDate == null
|
||||
? ""
|
||||
: Format.formatDate(_selectedToDate!);
|
||||
});
|
||||
|
||||
setState(() {
|
||||
if (flag) {
|
||||
_fromDateString = _selectedFromDate == null
|
||||
? ""
|
||||
: Format.formatDate(_selectedFromDate!);
|
||||
}
|
||||
_toDateString = _selectedToDate == null
|
||||
? ""
|
||||
: Format.formatDate(_selectedToDate!);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
|
@ -454,7 +360,7 @@ class _TransactionSearchViewState
|
|||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(const Duration(milliseconds: 75));
|
||||
}
|
||||
if (mounted) {
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
|
@ -908,7 +814,7 @@ class _TransactionSearchViewState
|
|||
);
|
||||
}
|
||||
}
|
||||
if (mounted) {
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
|
|
|
@ -170,7 +170,9 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
final wallet = ref.read(pWallets).getWallet(walletId);
|
||||
coin = wallet.info.coin;
|
||||
|
||||
ref.read(currentWalletIdProvider.notifier).state = wallet.walletId;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(currentWalletIdProvider.notifier).state = wallet.walletId;
|
||||
});
|
||||
|
||||
if (!wallet.shouldAutoSync) {
|
||||
// enable auto sync if it wasn't enabled when loading wallet
|
||||
|
|
|
@ -26,9 +26,9 @@ import 'package:stackwallet/widgets/stack_text_field.dart';
|
|||
|
||||
class DesktopAuthSend extends ConsumerStatefulWidget {
|
||||
const DesktopAuthSend({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.coin,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
final Coin coin;
|
||||
|
||||
|
@ -43,11 +43,52 @@ class _DesktopAuthSendState extends ConsumerState<DesktopAuthSend> {
|
|||
bool hidePassword = true;
|
||||
|
||||
bool _confirmEnabled = false;
|
||||
bool _lock = false;
|
||||
|
||||
Future<bool> verifyPassphrase() async {
|
||||
return await ref
|
||||
.read(storageCryptoHandlerProvider)
|
||||
.verifyPassphrase(passwordController.text);
|
||||
Future<void> _confirmPressed() async {
|
||||
if (_lock) {
|
||||
return;
|
||||
}
|
||||
_lock = true;
|
||||
|
||||
try {
|
||||
unawaited(
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => const Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
LoadingIndicator(
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await Future<void>.delayed(const Duration(seconds: 1));
|
||||
|
||||
final passwordIsValid = await ref
|
||||
.read(storageCryptoHandlerProvider)
|
||||
.verifyPassphrase(passwordController.text);
|
||||
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(
|
||||
context,
|
||||
rootNavigator: true,
|
||||
).pop(passwordIsValid);
|
||||
await Future<void>.delayed(
|
||||
const Duration(
|
||||
milliseconds: 100,
|
||||
),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
_lock = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -108,6 +149,12 @@ class _DesktopAuthSendState extends ConsumerState<DesktopAuthSend> {
|
|||
obscureText: hidePassword,
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
autofocus: true,
|
||||
onSubmitted: (_) {
|
||||
if (_confirmEnabled) {
|
||||
_confirmPressed();
|
||||
}
|
||||
},
|
||||
decoration: standardInputDecoration(
|
||||
"Enter password",
|
||||
passwordFocusNode,
|
||||
|
@ -173,38 +220,7 @@ class _DesktopAuthSendState extends ConsumerState<DesktopAuthSend> {
|
|||
enabled: _confirmEnabled,
|
||||
label: "Confirm",
|
||||
buttonHeight: ButtonHeight.l,
|
||||
onPressed: () async {
|
||||
unawaited(
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: const [
|
||||
LoadingIndicator(
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await Future<void>.delayed(const Duration(seconds: 1));
|
||||
|
||||
final passwordIsValid = await verifyPassphrase();
|
||||
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(
|
||||
context,
|
||||
rootNavigator: true,
|
||||
).pop(passwordIsValid);
|
||||
await Future<void>.delayed(const Duration(
|
||||
milliseconds: 100,
|
||||
));
|
||||
}
|
||||
},
|
||||
onPressed: _confirmPressed,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -686,7 +686,7 @@ abstract class EthereumAPI {
|
|||
try {
|
||||
final response = await client.get(
|
||||
url: Uri.parse(
|
||||
"$stackBaseServer/abis?addrs=$contractAddress&verbose=true",
|
||||
"$stackBaseServer/abis?addrs=$contractAddress",
|
||||
),
|
||||
proxyInfo: Prefs.instance.useTor
|
||||
? TorService.sharedInstance.getProxyInfo()
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_libmonero/monero/monero.dart';
|
||||
import 'package:flutter_libmonero/wownero/wownero.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
@ -16,7 +18,6 @@ import 'package:stackwallet/db/isar/main_db.dart';
|
|||
import 'package:stackwallet/services/node_service.dart';
|
||||
import 'package:stackwallet/services/notifications_service.dart';
|
||||
import 'package:stackwallet/services/trade_sent_from_stack_service.dart';
|
||||
import 'package:stackwallet/services/transaction_notification_tracker.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/sync_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
|
@ -134,6 +135,11 @@ class Wallets {
|
|||
}
|
||||
|
||||
Future<void> load(Prefs prefs, MainDB mainDB) async {
|
||||
// return await _loadV1(prefs, mainDB);
|
||||
return await _loadV2(prefs, mainDB);
|
||||
}
|
||||
|
||||
Future<void> _loadV1(Prefs prefs, MainDB mainDB) async {
|
||||
if (hasLoaded) {
|
||||
return;
|
||||
}
|
||||
|
@ -156,10 +162,11 @@ class Wallets {
|
|||
return;
|
||||
}
|
||||
|
||||
List<Future<void>> walletInitFutures = [];
|
||||
List<({Wallet wallet, bool shouldAutoSync})> walletsToInitLinearly = [];
|
||||
final List<Future<void>> walletInitFutures = [];
|
||||
final List<({Wallet wallet, bool shouldAutoSync})> walletsToInitLinearly =
|
||||
[];
|
||||
|
||||
List<String> walletIdsToEnableAutoSync = [];
|
||||
final List<String> walletIdsToEnableAutoSync = [];
|
||||
bool shouldAutoSyncAll = false;
|
||||
switch (prefs.syncType) {
|
||||
case SyncingType.currentWalletOnly:
|
||||
|
@ -185,8 +192,8 @@ class Wallets {
|
|||
if (isVerified) {
|
||||
// TODO: integrate this into the new wallets somehow?
|
||||
// requires some thinking
|
||||
final txTracker =
|
||||
TransactionNotificationTracker(walletId: walletInfo.walletId);
|
||||
// final txTracker =
|
||||
// TransactionNotificationTracker(walletId: walletInfo.walletId);
|
||||
|
||||
final wallet = await Wallet.load(
|
||||
walletId: walletInfo.walletId,
|
||||
|
@ -233,15 +240,134 @@ class Wallets {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> _loadV2(Prefs prefs, MainDB mainDB) async {
|
||||
if (hasLoaded) {
|
||||
return;
|
||||
}
|
||||
hasLoaded = true;
|
||||
|
||||
// clear out any wallet hive boxes where the wallet was deleted in previous app run
|
||||
for (final walletId in DB.instance
|
||||
.values<String>(boxName: DB.boxNameWalletsToDeleteOnStart)) {
|
||||
await mainDB.isar.writeTxn(() async => await mainDB.isar.walletInfo
|
||||
.where()
|
||||
.walletIdEqualTo(walletId)
|
||||
.deleteAll());
|
||||
}
|
||||
// clear list
|
||||
await DB.instance
|
||||
.deleteAll<String>(boxName: DB.boxNameWalletsToDeleteOnStart);
|
||||
|
||||
final walletInfoList = await mainDB.isar.walletInfo.where().findAll();
|
||||
if (walletInfoList.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<Future<String>> walletIDInitFutures = [];
|
||||
final List<Future<void>> deleteFutures = [];
|
||||
final List<({Wallet wallet, bool shouldAutoSync})> walletsToInitLinearly =
|
||||
[];
|
||||
|
||||
final List<String> walletIdsToEnableAutoSync = [];
|
||||
bool shouldAutoSyncAll = false;
|
||||
switch (prefs.syncType) {
|
||||
case SyncingType.currentWalletOnly:
|
||||
// do nothing as this will be set when going into a wallet from the main screen
|
||||
break;
|
||||
case SyncingType.selectedWalletsAtStartup:
|
||||
walletIdsToEnableAutoSync.addAll(prefs.walletIdsSyncOnStartup);
|
||||
break;
|
||||
case SyncingType.allWalletsOnStartup:
|
||||
shouldAutoSyncAll = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (final walletInfo in walletInfoList) {
|
||||
try {
|
||||
final isVerified = await walletInfo.isMnemonicVerified(mainDB.isar);
|
||||
Logging.instance.log(
|
||||
"LOADING WALLET: ${walletInfo.name}:${walletInfo.walletId} "
|
||||
"IS VERIFIED: $isVerified",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
|
||||
if (isVerified) {
|
||||
// TODO: integrate this into the new wallets somehow?
|
||||
// requires some thinking
|
||||
// final txTracker =
|
||||
// TransactionNotificationTracker(walletId: walletInfo.walletId);
|
||||
|
||||
final walletIdCompleter = Completer<String>();
|
||||
|
||||
walletIDInitFutures.add(walletIdCompleter.future);
|
||||
|
||||
await Wallet.load(
|
||||
walletId: walletInfo.walletId,
|
||||
mainDB: mainDB,
|
||||
secureStorageInterface: nodeService.secureStorageInterface,
|
||||
nodeService: nodeService,
|
||||
prefs: prefs,
|
||||
).then((wallet) {
|
||||
if (wallet is CwBasedInterface) {
|
||||
// walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
|
||||
|
||||
walletIdCompleter.complete("dummy_ignore");
|
||||
} else {
|
||||
walletIdCompleter.complete(wallet.walletId);
|
||||
}
|
||||
|
||||
_wallets[wallet.walletId] = wallet;
|
||||
});
|
||||
} else {
|
||||
// wallet creation was not completed by user so we remove it completely
|
||||
deleteFutures.add(_deleteWallet(walletInfo.walletId));
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e $s", level: LogLevel.Fatal);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
final asyncWalletIds = await Future.wait(walletIDInitFutures);
|
||||
asyncWalletIds.removeWhere((e) => e == "dummy_ignore");
|
||||
|
||||
final List<Future<void>> walletInitFutures = asyncWalletIds
|
||||
.map(
|
||||
(id) => _wallets[id]!.init().then(
|
||||
(_) {
|
||||
if (shouldAutoSyncAll || walletIdsToEnableAutoSync.contains(id)) {
|
||||
_wallets[id]!.shouldAutoSync = true;
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
if (walletInitFutures.isNotEmpty && walletsToInitLinearly.isNotEmpty) {
|
||||
unawaited(Future.wait([
|
||||
_initLinearly(walletsToInitLinearly),
|
||||
...walletInitFutures,
|
||||
]));
|
||||
} else if (walletInitFutures.isNotEmpty) {
|
||||
unawaited(Future.wait(walletInitFutures));
|
||||
} else if (walletsToInitLinearly.isNotEmpty) {
|
||||
unawaited(_initLinearly(walletsToInitLinearly));
|
||||
}
|
||||
|
||||
// finally await any deletions that haven't completed yet
|
||||
await Future.wait(deleteFutures);
|
||||
}
|
||||
|
||||
Future<void> loadAfterStackRestore(
|
||||
Prefs prefs,
|
||||
List<Wallet> wallets,
|
||||
bool isDesktop,
|
||||
) async {
|
||||
List<Future<void>> walletInitFutures = [];
|
||||
List<({Wallet wallet, bool shouldAutoSync})> walletsToInitLinearly = [];
|
||||
final List<Future<void>> walletInitFutures = [];
|
||||
final List<({Wallet wallet, bool shouldAutoSync})> walletsToInitLinearly =
|
||||
[];
|
||||
|
||||
List<String> walletIdsToEnableAutoSync = [];
|
||||
final List<String> walletIdsToEnableAutoSync = [];
|
||||
bool shouldAutoSyncAll = false;
|
||||
switch (prefs.syncType) {
|
||||
case SyncingType.currentWalletOnly:
|
||||
|
|
|
@ -29,7 +29,7 @@ final pThemeService = Provider<ThemeService>((ref) {
|
|||
});
|
||||
|
||||
class ThemeService {
|
||||
static const _currentDefaultThemeVersion = 4;
|
||||
static const _currentDefaultThemeVersion = 8;
|
||||
ThemeService._();
|
||||
static ThemeService? _instance;
|
||||
static ThemeService get instance => _instance ??= ThemeService._();
|
||||
|
|
|
@ -68,7 +68,6 @@ class Prefs extends ChangeNotifier {
|
|||
await _setMaxDecimals();
|
||||
_useTor = await _getUseTor();
|
||||
_fusionServerInfo = await _getFusionServerInfo();
|
||||
_solanaEnabled = await _getSolanaEnabled();
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
@ -1009,25 +1008,4 @@ class Prefs extends ChangeNotifier {
|
|||
|
||||
return actualMap;
|
||||
}
|
||||
|
||||
// Solana
|
||||
|
||||
bool _solanaEnabled = false;
|
||||
|
||||
bool get solanaEnabled => _solanaEnabled;
|
||||
|
||||
set solanaEnabled(bool solanaEnabled) {
|
||||
if (_solanaEnabled != solanaEnabled) {
|
||||
DB.instance.put<dynamic>(
|
||||
boxName: DB.boxNamePrefs, key: "solanaEnabled", value: solanaEnabled);
|
||||
_solanaEnabled = solanaEnabled;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _getSolanaEnabled() async {
|
||||
return await DB.instance.get<dynamic>(
|
||||
boxName: DB.boxNamePrefs, key: "solanaEnabled") as bool? ??
|
||||
false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,14 +62,15 @@ class FiroWallet extends Bip39HDWallet
|
|||
|
||||
@override
|
||||
Future<void> updateTransactions() async {
|
||||
List<Address> allAddressesOld = await fetchAddressesForElectrumXScan();
|
||||
final List<Address> allAddressesOld =
|
||||
await fetchAddressesForElectrumXScan();
|
||||
|
||||
Set<String> receivingAddresses = allAddressesOld
|
||||
final Set<String> receivingAddresses = allAddressesOld
|
||||
.where((e) => e.subType == AddressSubType.receiving)
|
||||
.map((e) => convertAddressString(e.value))
|
||||
.toSet();
|
||||
|
||||
Set<String> changeAddresses = allAddressesOld
|
||||
final Set<String> changeAddresses = allAddressesOld
|
||||
.where((e) => e.subType == AddressSubType.change)
|
||||
.map((e) => convertAddressString(e.value))
|
||||
.toSet();
|
||||
|
@ -98,7 +99,7 @@ class FiroWallet extends Bip39HDWallet
|
|||
}
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> allTransactions = [];
|
||||
final List<Map<String, dynamic>> allTransactions = [];
|
||||
|
||||
// some lelantus transactions aren't fetched via wallet addresses so they
|
||||
// will never show as confirmed in the gui.
|
||||
|
@ -177,7 +178,7 @@ class FiroWallet extends Bip39HDWallet
|
|||
bool isMint = false;
|
||||
bool isJMint = false;
|
||||
bool isSparkMint = false;
|
||||
bool isMasterNodePayment = false;
|
||||
final bool isMasterNodePayment = false;
|
||||
final bool isSparkSpend = txData["type"] == 9 && txData["version"] == 3;
|
||||
final bool isMySpark = sparkTxids.contains(txData["txid"] as String);
|
||||
|
||||
|
@ -548,8 +549,12 @@ class FiroWallet extends Bip39HDWallet
|
|||
}
|
||||
|
||||
@override
|
||||
Future<({String? blockedReason, bool blocked, String? utxoLabel})>
|
||||
checkBlockUTXO(
|
||||
Future<
|
||||
({
|
||||
String? blockedReason,
|
||||
bool blocked,
|
||||
String? utxoLabel,
|
||||
})> checkBlockUTXO(
|
||||
Map<String, dynamic> jsonUTXO,
|
||||
String? scriptPubKeyHex,
|
||||
Map<String, dynamic>? jsonTX,
|
||||
|
@ -557,30 +562,26 @@ class FiroWallet extends Bip39HDWallet
|
|||
) async {
|
||||
bool blocked = false;
|
||||
String? blockedReason;
|
||||
//
|
||||
// if (jsonTX != null) {
|
||||
// // check for bip47 notification
|
||||
// final outputs = jsonTX["vout"] as List;
|
||||
// for (final output in outputs) {
|
||||
// List<String>? scriptChunks =
|
||||
// (output['scriptPubKey']?['asm'] as String?)?.split(" ");
|
||||
// if (scriptChunks?.length == 2 && scriptChunks?[0] == "OP_RETURN") {
|
||||
// final blindedPaymentCode = scriptChunks![1];
|
||||
// final bytes = blindedPaymentCode.toUint8ListFromHex;
|
||||
//
|
||||
// // https://en.bitcoin.it/wiki/BIP_0047#Sending
|
||||
// if (bytes.length == 80 && bytes.first == 1) {
|
||||
// blocked = true;
|
||||
// blockedReason = "Paynym notification output. Incautious "
|
||||
// "handling of outputs from notification transactions "
|
||||
// "may cause unintended loss of privacy.";
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
return (blockedReason: blockedReason, blocked: blocked, utxoLabel: null);
|
||||
String? label;
|
||||
|
||||
if (jsonUTXO["value"] is int) {
|
||||
// TODO: [prio=med] use special electrumx call to verify the 1000 Firo output is masternode
|
||||
blocked = Amount.fromDecimal(
|
||||
Decimal.fromInt(
|
||||
1000, // 1000 firo output is a possible master node
|
||||
),
|
||||
fractionDigits: cryptoCurrency.fractionDigits,
|
||||
).raw ==
|
||||
BigInt.from(jsonUTXO["value"] as int);
|
||||
|
||||
if (blocked) {
|
||||
blockedReason = "Possible masternode output. "
|
||||
"Unlock and spend at your own risk.";
|
||||
label = "Possible masternode";
|
||||
}
|
||||
}
|
||||
|
||||
return (blockedReason: blockedReason, blocked: blocked, utxoLabel: label);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -632,9 +633,11 @@ class FiroWallet extends Bip39HDWallet
|
|||
level: LogLevel.Info,
|
||||
);
|
||||
|
||||
final canBatch = await serverCanBatch;
|
||||
|
||||
for (final type in cryptoCurrency.supportedDerivationPathTypes) {
|
||||
receiveFutures.add(
|
||||
serverCanBatch
|
||||
canBatch
|
||||
? checkGapsBatched(
|
||||
txCountBatchSize,
|
||||
root,
|
||||
|
@ -656,7 +659,7 @@ class FiroWallet extends Bip39HDWallet
|
|||
);
|
||||
for (final type in cryptoCurrency.supportedDerivationPathTypes) {
|
||||
changeFutures.add(
|
||||
serverCanBatch
|
||||
canBatch
|
||||
? checkGapsBatched(
|
||||
txCountBatchSize,
|
||||
root,
|
||||
|
|
|
@ -92,16 +92,8 @@ class EthTokenWallet extends Wallet {
|
|||
);
|
||||
}
|
||||
|
||||
// String? mnemonicString = await ethWallet.getMnemonic();
|
||||
//
|
||||
// //Get private key for given mnemonic
|
||||
// String privateKey = getPrivateKey(
|
||||
// mnemonicString,
|
||||
// (await ethWallet.getMnemonicPassphrase()),
|
||||
// );
|
||||
// _credentials = web3dart.EthPrivateKey.fromHex(privateKey);
|
||||
|
||||
try {
|
||||
// try parse abi and extract transfer function
|
||||
_deployedContract = web3dart.DeployedContract(
|
||||
ContractAbiExtensions.fromJsonList(
|
||||
jsonList: tokenContract.abi!,
|
||||
|
@ -109,90 +101,51 @@ class EthTokenWallet extends Wallet {
|
|||
),
|
||||
contractAddress,
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
|
||||
try {
|
||||
_sendFunction = _deployedContract.function('transfer');
|
||||
} catch (_) {
|
||||
//====================================================================
|
||||
// final list = List<Map<String, dynamic>>.from(
|
||||
// jsonDecode(tokenContract.abi!) as List);
|
||||
// final functionNames = list.map((e) => e["name"] as String);
|
||||
//
|
||||
// if (!functionNames.contains("balanceOf")) {
|
||||
// list.add(
|
||||
// {
|
||||
// "encoding": "0x70a08231",
|
||||
// "inputs": [
|
||||
// {"name": "account", "type": "address"}
|
||||
// ],
|
||||
// "name": "balanceOf",
|
||||
// "outputs": [
|
||||
// {"name": "val_0", "type": "uint256"}
|
||||
// ],
|
||||
// "signature": "balanceOf(address)",
|
||||
// "type": "function"
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// if (!functionNames.contains("transfer")) {
|
||||
// list.add(
|
||||
// {
|
||||
// "encoding": "0xa9059cbb",
|
||||
// "inputs": [
|
||||
// {"name": "dst", "type": "address"},
|
||||
// {"name": "rawAmount", "type": "uint256"}
|
||||
// ],
|
||||
// "name": "transfer",
|
||||
// "outputs": [
|
||||
// {"name": "val_0", "type": "bool"}
|
||||
// ],
|
||||
// "signature": "transfer(address,uint256)",
|
||||
// "type": "function"
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
//--------------------------------------------------------------------
|
||||
//====================================================================
|
||||
|
||||
// function not found so likely a proxy so we need to fetch the impl
|
||||
//====================================================================
|
||||
// final updatedToken = tokenContract.copyWith(abi: jsonEncode(list));
|
||||
// // Store updated contract
|
||||
// final id = await MainDB.instance.putEthContract(updatedToken);
|
||||
// _tokenContract = updatedToken..id = id;
|
||||
//--------------------------------------------------------------------
|
||||
final contractAddressResponse =
|
||||
await EthereumAPI.getProxyTokenImplementationAddress(
|
||||
contractAddress.hex);
|
||||
|
||||
if (contractAddressResponse.value != null) {
|
||||
_tokenContract = await _updateTokenABI(
|
||||
forContract: tokenContract,
|
||||
usingContractAddress: contractAddressResponse.value!,
|
||||
);
|
||||
} else {
|
||||
throw contractAddressResponse.exception!;
|
||||
}
|
||||
//====================================================================
|
||||
}
|
||||
|
||||
try {
|
||||
_deployedContract = web3dart.DeployedContract(
|
||||
ContractAbiExtensions.fromJsonList(
|
||||
jsonList: tokenContract.abi!,
|
||||
name: tokenContract.name,
|
||||
),
|
||||
contractAddress,
|
||||
// some failure so first try to make sure we have the latest abi
|
||||
_tokenContract = await _updateTokenABI(
|
||||
forContract: tokenContract,
|
||||
usingContractAddress: contractAddress.hex,
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
|
||||
_sendFunction = _deployedContract.function('transfer');
|
||||
try {
|
||||
// try again to parse abi and extract transfer function
|
||||
_deployedContract = web3dart.DeployedContract(
|
||||
ContractAbiExtensions.fromJsonList(
|
||||
jsonList: tokenContract.abi!,
|
||||
name: tokenContract.name,
|
||||
),
|
||||
contractAddress,
|
||||
);
|
||||
_sendFunction = _deployedContract.function('transfer');
|
||||
} catch (_) {
|
||||
// if it fails again we check if there is a proxy token impl and
|
||||
// then try one last time to update and parse the abi
|
||||
final contractAddressResponse =
|
||||
await EthereumAPI.getProxyTokenImplementationAddress(
|
||||
contractAddress.hex);
|
||||
|
||||
if (contractAddressResponse.value != null) {
|
||||
_tokenContract = await _updateTokenABI(
|
||||
forContract: tokenContract,
|
||||
usingContractAddress: contractAddressResponse.value!,
|
||||
);
|
||||
} else {
|
||||
throw contractAddressResponse.exception!;
|
||||
}
|
||||
|
||||
_deployedContract = web3dart.DeployedContract(
|
||||
ContractAbiExtensions.fromJsonList(
|
||||
jsonList: tokenContract.abi!,
|
||||
name: tokenContract.name,
|
||||
),
|
||||
contractAddress,
|
||||
);
|
||||
|
||||
_sendFunction = _deployedContract.function('transfer');
|
||||
}
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"$runtimeType wallet failed init(): $e\n$s",
|
||||
|
|
|
@ -35,11 +35,20 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
|||
|
||||
static const _kServerBatchCutoffVersion = [1, 6];
|
||||
List<int>? _serverVersion;
|
||||
bool get serverCanBatch {
|
||||
Future<bool> get serverCanBatch async {
|
||||
// Firo server added batching without incrementing version number...
|
||||
if (cryptoCurrency is Firo) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
_serverVersion ??= _parseServerVersion((await electrumXClient
|
||||
.getServerFeatures()
|
||||
.timeout(const Duration(seconds: 2)))["server_version"] as String);
|
||||
} catch (_) {
|
||||
// ignore failure as it doesn't matter
|
||||
}
|
||||
|
||||
if (_serverVersion != null && _serverVersion!.length > 2) {
|
||||
if (_serverVersion![0] > _kServerBatchCutoffVersion[0]) {
|
||||
return true;
|
||||
|
@ -193,8 +202,8 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
|||
.log('utxoObjectsToUse: $utxoObjectsToUse', level: LogLevel.Info);
|
||||
|
||||
// numberOfOutputs' length must always be equal to that of recipientsArray and recipientsAmtArray
|
||||
List<String> recipientsArray = [recipientAddress];
|
||||
List<int> recipientsAmtArray = [satoshiAmountToSend];
|
||||
final List<String> recipientsArray = [recipientAddress];
|
||||
final List<int> recipientsAmtArray = [satoshiAmountToSend];
|
||||
|
||||
// gather required signing data
|
||||
final utxoSigningData = await fetchBuildTxData(utxoObjectsToUse);
|
||||
|
@ -325,7 +334,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
|||
feeForOneOutput + cryptoCurrency.dustLimit.raw.toInt()) {
|
||||
// Here, we know that theoretically, we may be able to include another output(change) but we first need to
|
||||
// factor in the value of this output in satoshis.
|
||||
int changeOutputSize =
|
||||
final int changeOutputSize =
|
||||
satoshisBeingUsed - satoshiAmountToSend - feeForTwoOutputs;
|
||||
// We check to see if the user can pay for the new transaction with 2 outputs instead of one. If they can and
|
||||
// the second output's size > cryptoCurrency.dustLimit satoshis, we perform the mechanics required to properly generate and use a new
|
||||
|
@ -370,7 +379,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
|||
|
||||
// make sure minimum fee is accurate if that is being used
|
||||
if (txn.vSize! - feeBeingPaid == 1) {
|
||||
int changeOutputSize =
|
||||
final int changeOutputSize =
|
||||
satoshisBeingUsed - satoshiAmountToSend - txn.vSize!;
|
||||
feeBeingPaid =
|
||||
satoshisBeingUsed - satoshiAmountToSend - changeOutputSize;
|
||||
|
@ -526,7 +535,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
|||
List<UTXO> utxosToUse,
|
||||
) async {
|
||||
// return data
|
||||
List<SigningData> signingData = [];
|
||||
final List<SigningData> signingData = [];
|
||||
|
||||
try {
|
||||
// Populating the addresses to check
|
||||
|
@ -879,7 +888,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
|||
DerivePathType type,
|
||||
int chain,
|
||||
) async {
|
||||
List<Address> addressArray = [];
|
||||
final List<Address> addressArray = [];
|
||||
int gapCounter = 0;
|
||||
int highestIndexWithHistory = 0;
|
||||
|
||||
|
@ -891,7 +900,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
|||
"index: $index, \t GapCounter $chain ${type.name}: $gapCounter",
|
||||
level: LogLevel.Info);
|
||||
|
||||
List<String> txCountCallArgs = [];
|
||||
final List<String> txCountCallArgs = [];
|
||||
|
||||
for (int j = 0; j < txCountBatchSize; j++) {
|
||||
final derivePath = cryptoCurrency.constructDerivePath(
|
||||
|
@ -960,7 +969,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
|||
DerivePathType type,
|
||||
int chain,
|
||||
) async {
|
||||
List<Address> addressArray = [];
|
||||
final List<Address> addressArray = [];
|
||||
int gapCounter = 0;
|
||||
int index = 0;
|
||||
for (;
|
||||
|
@ -1023,9 +1032,9 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
|||
Iterable<String> allAddresses,
|
||||
) async {
|
||||
try {
|
||||
List<Map<String, dynamic>> allTxHashes = [];
|
||||
final List<Map<String, dynamic>> allTxHashes = [];
|
||||
|
||||
if (serverCanBatch) {
|
||||
if (await serverCanBatch) {
|
||||
final Map<int, List<List<dynamic>>> batches = {};
|
||||
final Map<int, List<String>> batchIndexToAddressListMap = {};
|
||||
const batchSizeMax = 100;
|
||||
|
@ -1080,7 +1089,10 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
|||
|
||||
return allTxHashes;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("_fetchHistory: $e\n$s", level: LogLevel.Error);
|
||||
Logging.instance.log(
|
||||
"$runtimeType._fetchHistory: $e\n$s",
|
||||
level: LogLevel.Error,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
@ -1363,9 +1375,11 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
|||
level: LogLevel.Info,
|
||||
);
|
||||
|
||||
final canBatch = await serverCanBatch;
|
||||
|
||||
for (final type in cryptoCurrency.supportedDerivationPathTypes) {
|
||||
receiveFutures.add(
|
||||
serverCanBatch
|
||||
canBatch
|
||||
? checkGapsBatched(
|
||||
txCountBatchSize,
|
||||
root,
|
||||
|
@ -1387,7 +1401,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
|||
);
|
||||
for (final type in cryptoCurrency.supportedDerivationPathTypes) {
|
||||
changeFutures.add(
|
||||
serverCanBatch
|
||||
canBatch
|
||||
? checkGapsBatched(
|
||||
txCountBatchSize,
|
||||
root,
|
||||
|
@ -1510,7 +1524,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
|||
try {
|
||||
final fetchedUtxoList = <List<Map<String, dynamic>>>[];
|
||||
|
||||
if (serverCanBatch) {
|
||||
if (await serverCanBatch) {
|
||||
final Map<int, List<List<dynamic>>> batchArgs = {};
|
||||
const batchSizeMax = 10;
|
||||
int batchNumber = 0;
|
||||
|
|
108
lib/widgets/date_picker/date_picker.dart
Normal file
108
lib/widgets/date_picker/date_picker.dart
Normal file
|
@ -0,0 +1,108 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:calendar_date_picker2/calendar_date_picker2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stackwallet/themes/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
|
||||
part 'sw_date_picker.dart';
|
||||
|
||||
Future<DateTime?> showSWDatePicker(BuildContext context) async {
|
||||
final Size size;
|
||||
if (Util.isDesktop) {
|
||||
size = const Size(450, 450);
|
||||
} else {
|
||||
final _size = MediaQuery.of(context).size;
|
||||
size = Size(
|
||||
_size.width - 32,
|
||||
_size.height >= 550 ? 450 : _size.height - 32,
|
||||
);
|
||||
}
|
||||
print("=====================================");
|
||||
print(size);
|
||||
|
||||
final now = DateTime.now();
|
||||
|
||||
final date = await _showDatePickerDialog(
|
||||
context: context,
|
||||
value: [now],
|
||||
dialogSize: size,
|
||||
config: CalendarDatePicker2WithActionButtonsConfig(
|
||||
firstDate: DateTime(2007),
|
||||
lastDate: now,
|
||||
currentDate: now,
|
||||
buttonPadding: const EdgeInsets.only(
|
||||
right: 16,
|
||||
),
|
||||
centerAlignModePicker: true,
|
||||
selectedDayHighlightColor:
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||
daySplashColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark
|
||||
.withOpacity(0.6),
|
||||
),
|
||||
);
|
||||
return date?.first;
|
||||
}
|
||||
|
||||
Future<List<DateTime?>?> _showDatePickerDialog({
|
||||
required BuildContext context,
|
||||
required CalendarDatePicker2WithActionButtonsConfig config,
|
||||
required Size dialogSize,
|
||||
List<DateTime?> value = const [],
|
||||
bool useRootNavigator = true,
|
||||
bool barrierDismissible = true,
|
||||
Color? barrierColor = Colors.black54,
|
||||
bool useSafeArea = true,
|
||||
RouteSettings? routeSettings,
|
||||
String? barrierLabel,
|
||||
TransitionBuilder? builder,
|
||||
}) {
|
||||
final dialog = Dialog(
|
||||
insetPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 16,
|
||||
),
|
||||
backgroundColor: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius * 2,
|
||||
),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: SizedBox(
|
||||
width: dialogSize.width,
|
||||
height: max(dialogSize.height, 410),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
_SWDatePicker(
|
||||
value: value,
|
||||
config: config.copyWith(openedFromDialog: true),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return showDialog<List<DateTime?>>(
|
||||
context: context,
|
||||
useRootNavigator: useRootNavigator,
|
||||
routeSettings: routeSettings,
|
||||
builder: (BuildContext context) {
|
||||
return builder == null ? dialog : builder(context, dialog);
|
||||
},
|
||||
barrierDismissible: barrierDismissible,
|
||||
barrierColor: barrierColor,
|
||||
barrierLabel: barrierLabel,
|
||||
useSafeArea: useSafeArea,
|
||||
);
|
||||
}
|
184
lib/widgets/date_picker/sw_date_picker.dart
Normal file
184
lib/widgets/date_picker/sw_date_picker.dart
Normal file
|
@ -0,0 +1,184 @@
|
|||
part of 'date_picker.dart';
|
||||
|
||||
class _SWDatePicker extends StatefulWidget {
|
||||
const _SWDatePicker({
|
||||
super.key,
|
||||
required this.value,
|
||||
required this.config,
|
||||
this.onValueChanged,
|
||||
this.onDisplayedMonthChanged,
|
||||
this.onCancelTapped,
|
||||
this.onOkTapped,
|
||||
});
|
||||
final List<DateTime?> value;
|
||||
|
||||
/// Called when the user taps 'OK' button
|
||||
final ValueChanged<List<DateTime?>>? onValueChanged;
|
||||
|
||||
/// Called when the user navigates to a new month/year in the picker.
|
||||
final ValueChanged<DateTime>? onDisplayedMonthChanged;
|
||||
|
||||
/// The calendar configurations including action buttons
|
||||
final CalendarDatePicker2WithActionButtonsConfig config;
|
||||
|
||||
/// The callback when cancel button is tapped
|
||||
final Function? onCancelTapped;
|
||||
|
||||
/// The callback when ok button is tapped
|
||||
final Function? onOkTapped;
|
||||
@override
|
||||
State<_SWDatePicker> createState() => _SWDatePickerState();
|
||||
}
|
||||
|
||||
class _SWDatePickerState extends State<_SWDatePicker> {
|
||||
List<DateTime?> _values = [];
|
||||
List<DateTime?> _editCache = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_values = widget.value;
|
||||
_editCache = widget.value;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant _SWDatePicker oldWidget) {
|
||||
var isValueSame = oldWidget.value.length == widget.value.length;
|
||||
|
||||
if (isValueSame) {
|
||||
for (int i = 0; i < oldWidget.value.length; i++) {
|
||||
final isSame =
|
||||
(oldWidget.value[i] == null && widget.value[i] == null) ||
|
||||
DateUtils.isSameDay(oldWidget.value[i], widget.value[i]);
|
||||
if (!isSame) {
|
||||
isValueSame = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValueSame) {
|
||||
_values = widget.value;
|
||||
_editCache = widget.value;
|
||||
}
|
||||
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
hoverColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
focusColor: Colors.transparent,
|
||||
colorScheme: Theme.of(context).colorScheme.copyWith(
|
||||
background: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
onBackground:
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||
surface: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
surfaceVariant:
|
||||
Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
onSurface:
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||
onSurfaceVariant:
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||
surfaceTint: Colors.transparent,
|
||||
shadow: Colors.transparent,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
MediaQuery.removePadding(
|
||||
context: context,
|
||||
child: CalendarDatePicker2(
|
||||
value: [..._editCache],
|
||||
config: widget.config,
|
||||
onValueChanged: (values) => _editCache = values,
|
||||
onDisplayedMonthChanged: widget.onDisplayedMonthChanged,
|
||||
),
|
||||
),
|
||||
SizedBox(height: widget.config.gapBetweenCalendarAndButtons ?? 10),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if (!Util.isDesktop)
|
||||
SizedBox(
|
||||
width: widget.config.buttonPadding?.right ?? 0,
|
||||
),
|
||||
ConditionalParent(
|
||||
condition: !Util.isDesktop,
|
||||
builder: (child) => Expanded(
|
||||
child: child,
|
||||
),
|
||||
child: Padding(
|
||||
padding: widget.config.buttonPadding ?? EdgeInsets.zero,
|
||||
child: ConditionalParent(
|
||||
condition: Util.isDesktop,
|
||||
builder: (child) => SizedBox(
|
||||
width: 140,
|
||||
child: child,
|
||||
),
|
||||
child: SecondaryButton(
|
||||
label: "Cancel",
|
||||
buttonHeight: Util.isDesktop ? ButtonHeight.m : null,
|
||||
onPressed: () {
|
||||
setState(
|
||||
() {
|
||||
_editCache = _values;
|
||||
widget.onCancelTapped?.call();
|
||||
if ((widget.config.openedFromDialog ?? false) &&
|
||||
(widget.config.closeDialogOnCancelTapped ??
|
||||
true)) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if ((widget.config.gapBetweenCalendarAndButtons ?? 0) > 0)
|
||||
SizedBox(width: widget.config.gapBetweenCalendarAndButtons),
|
||||
ConditionalParent(
|
||||
condition: !Util.isDesktop,
|
||||
builder: (child) => Expanded(
|
||||
child: child,
|
||||
),
|
||||
child: Padding(
|
||||
padding: widget.config.buttonPadding ?? EdgeInsets.zero,
|
||||
child: ConditionalParent(
|
||||
condition: Util.isDesktop,
|
||||
builder: (child) => SizedBox(
|
||||
width: 140,
|
||||
child: child,
|
||||
),
|
||||
child: PrimaryButton(
|
||||
buttonHeight: Util.isDesktop ? ButtonHeight.m : null,
|
||||
label: "Ok",
|
||||
onPressed: () {
|
||||
setState(
|
||||
() {
|
||||
_values = _editCache;
|
||||
widget.onValueChanged?.call(_values);
|
||||
widget.onOkTapped?.call();
|
||||
if ((widget.config.openedFromDialog ?? false) &&
|
||||
(widget.config.closeDialogOnOkTapped ?? true)) {
|
||||
Navigator.pop(context, _values);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License in the LICENSE file, or at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
@ -1,342 +0,0 @@
|
|||
/*
|
||||
* This file is part of Stack Wallet.
|
||||
*
|
||||
* Copyright (c) 2023 Cypher Stack
|
||||
* All Rights Reserved.
|
||||
* The code is distributed under GPLv3 license, see LICENSE file for details.
|
||||
* Generated by Cypher Stack on 2023-05-26
|
||||
*
|
||||
*/
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/semantics.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_rounded_date_picker/flutter_rounded_date_picker.dart';
|
||||
import 'package:flutter_rounded_date_picker/src/flutter_rounded_button_action.dart';
|
||||
import 'package:flutter_rounded_date_picker/src/material_rounded_date_picker_style.dart';
|
||||
import 'package:flutter_rounded_date_picker/src/material_rounded_year_picker_style.dart';
|
||||
import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_date_picker_header.dart';
|
||||
import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_day_picker.dart';
|
||||
import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_month_picker.dart';
|
||||
import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_year_picker.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
||||
///
|
||||
/// This file uses code taken from https://github.com/benznest/flutter_rounded_date_picker
|
||||
///
|
||||
|
||||
class FlutterRoundedDatePickerDialog extends StatefulWidget {
|
||||
const FlutterRoundedDatePickerDialog(
|
||||
{Key? key,
|
||||
this.height,
|
||||
required this.initialDate,
|
||||
required this.firstDate,
|
||||
required this.lastDate,
|
||||
this.selectableDayPredicate,
|
||||
required this.initialDatePickerMode,
|
||||
required this.era,
|
||||
this.locale,
|
||||
required this.borderRadius,
|
||||
this.imageHeader,
|
||||
this.description = "",
|
||||
this.fontFamily,
|
||||
this.textNegativeButton,
|
||||
this.textPositiveButton,
|
||||
this.textActionButton,
|
||||
this.onTapActionButton,
|
||||
this.styleDatePicker,
|
||||
this.styleYearPicker,
|
||||
this.customWeekDays,
|
||||
this.builderDay,
|
||||
this.listDateDisabled,
|
||||
this.onTapDay,
|
||||
this.onMonthChange})
|
||||
: super(key: key);
|
||||
|
||||
final DateTime initialDate;
|
||||
final DateTime firstDate;
|
||||
final DateTime lastDate;
|
||||
final SelectableDayPredicate? selectableDayPredicate;
|
||||
final DatePickerMode initialDatePickerMode;
|
||||
|
||||
/// double height.
|
||||
final double? height;
|
||||
|
||||
/// Custom era year.
|
||||
final EraMode era;
|
||||
final Locale? locale;
|
||||
|
||||
/// Border
|
||||
final double borderRadius;
|
||||
|
||||
/// Header;
|
||||
final ImageProvider? imageHeader;
|
||||
final String description;
|
||||
|
||||
/// Font
|
||||
final String? fontFamily;
|
||||
|
||||
/// Button
|
||||
final String? textNegativeButton;
|
||||
final String? textPositiveButton;
|
||||
final String? textActionButton;
|
||||
|
||||
final VoidCallback? onTapActionButton;
|
||||
|
||||
/// Style
|
||||
final MaterialRoundedDatePickerStyle? styleDatePicker;
|
||||
final MaterialRoundedYearPickerStyle? styleYearPicker;
|
||||
|
||||
/// Custom Weekday
|
||||
final List<String>? customWeekDays;
|
||||
|
||||
final BuilderDayOfDatePicker? builderDay;
|
||||
|
||||
final List<DateTime>? listDateDisabled;
|
||||
final OnTapDay? onTapDay;
|
||||
|
||||
final Function? onMonthChange;
|
||||
|
||||
@override
|
||||
_FlutterRoundedDatePickerDialogState createState() =>
|
||||
_FlutterRoundedDatePickerDialogState();
|
||||
}
|
||||
|
||||
class _FlutterRoundedDatePickerDialogState
|
||||
extends State<FlutterRoundedDatePickerDialog> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_selectedDate = widget.initialDate;
|
||||
_mode = widget.initialDatePickerMode;
|
||||
}
|
||||
|
||||
bool _announcedInitialDate = false;
|
||||
|
||||
late MaterialLocalizations localizations;
|
||||
late TextDirection textDirection;
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
localizations = MaterialLocalizations.of(context);
|
||||
textDirection = Directionality.of(context);
|
||||
if (!_announcedInitialDate) {
|
||||
_announcedInitialDate = true;
|
||||
SemanticsService.announce(
|
||||
localizations.formatFullDate(_selectedDate),
|
||||
textDirection,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
late DateTime _selectedDate;
|
||||
late DatePickerMode _mode;
|
||||
final GlobalKey _pickerKey = GlobalKey();
|
||||
|
||||
void _vibrate() {
|
||||
switch (Theme.of(context).platform) {
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
HapticFeedback.vibrate();
|
||||
break;
|
||||
case TargetPlatform.iOS:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _handleModeChanged(DatePickerMode mode) {
|
||||
_vibrate();
|
||||
setState(() {
|
||||
_mode = mode;
|
||||
if (_mode == DatePickerMode.day) {
|
||||
SemanticsService.announce(
|
||||
localizations.formatMonthYear(_selectedDate),
|
||||
textDirection,
|
||||
);
|
||||
} else {
|
||||
SemanticsService.announce(
|
||||
localizations.formatYear(_selectedDate),
|
||||
textDirection,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _handleYearChanged(DateTime value) async {
|
||||
if (value.isBefore(widget.firstDate)) {
|
||||
value = widget.firstDate;
|
||||
} else if (value.isAfter(widget.lastDate)) {
|
||||
value = widget.lastDate;
|
||||
}
|
||||
if (value == _selectedDate) return;
|
||||
|
||||
if (widget.onMonthChange != null) await widget.onMonthChange!(value);
|
||||
|
||||
_vibrate();
|
||||
setState(() {
|
||||
_mode = DatePickerMode.day;
|
||||
_selectedDate = value;
|
||||
});
|
||||
}
|
||||
|
||||
void _handleDayChanged(DateTime value) {
|
||||
_vibrate();
|
||||
setState(() {
|
||||
_selectedDate = value;
|
||||
});
|
||||
}
|
||||
|
||||
void _handleCancel() {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
void _handleOk() {
|
||||
Navigator.of(context).pop(_selectedDate);
|
||||
}
|
||||
|
||||
Widget _buildPicker() {
|
||||
switch (_mode) {
|
||||
case DatePickerMode.year:
|
||||
return FlutterRoundedYearPicker(
|
||||
key: _pickerKey,
|
||||
selectedDate: _selectedDate,
|
||||
onChanged: (DateTime date) async => await _handleYearChanged(date),
|
||||
firstDate: widget.firstDate,
|
||||
lastDate: widget.lastDate,
|
||||
era: widget.era,
|
||||
fontFamily: widget.fontFamily,
|
||||
style: widget.styleYearPicker,
|
||||
);
|
||||
case DatePickerMode.day:
|
||||
default:
|
||||
return FlutterRoundedMonthPicker(
|
||||
key: _pickerKey,
|
||||
selectedDate: _selectedDate,
|
||||
onChanged: _handleDayChanged,
|
||||
firstDate: widget.firstDate,
|
||||
lastDate: widget.lastDate,
|
||||
era: widget.era,
|
||||
locale: widget.locale,
|
||||
selectableDayPredicate: widget.selectableDayPredicate,
|
||||
fontFamily: widget.fontFamily,
|
||||
style: widget.styleDatePicker,
|
||||
borderRadius: widget.borderRadius,
|
||||
customWeekDays: widget.customWeekDays,
|
||||
builderDay: widget.builderDay,
|
||||
listDateDisabled: widget.listDateDisabled,
|
||||
onTapDay: widget.onTapDay,
|
||||
onMonthChange: widget.onMonthChange);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final Widget picker = _buildPicker();
|
||||
final isDesktop = Util.isDesktop;
|
||||
|
||||
final Widget actions = FlutterRoundedButtonAction(
|
||||
textButtonNegative: widget.textNegativeButton,
|
||||
textButtonPositive: widget.textPositiveButton,
|
||||
onTapButtonNegative: _handleCancel,
|
||||
onTapButtonPositive: _handleOk,
|
||||
textActionButton: widget.textActionButton,
|
||||
onTapButtonAction: widget.onTapActionButton,
|
||||
localizations: localizations,
|
||||
textStyleButtonNegative: widget.styleDatePicker?.textStyleButtonNegative,
|
||||
textStyleButtonPositive: widget.styleDatePicker?.textStyleButtonPositive,
|
||||
textStyleButtonAction: widget.styleDatePicker?.textStyleButtonAction,
|
||||
borderRadius: widget.borderRadius,
|
||||
paddingActionBar: widget.styleDatePicker?.paddingActionBar,
|
||||
background: widget.styleDatePicker?.backgroundActionBar,
|
||||
);
|
||||
|
||||
Color backgroundPicker = theme.dialogBackgroundColor;
|
||||
if (_mode == DatePickerMode.day) {
|
||||
backgroundPicker = widget.styleDatePicker?.backgroundPicker ??
|
||||
theme.dialogBackgroundColor;
|
||||
} else {
|
||||
backgroundPicker = widget.styleYearPicker?.backgroundPicker ??
|
||||
theme.dialogBackgroundColor;
|
||||
}
|
||||
|
||||
final Dialog dialog = Dialog(
|
||||
child: OrientationBuilder(
|
||||
builder: (BuildContext context, Orientation orientation) {
|
||||
final Widget header = FlutterRoundedDatePickerHeader(
|
||||
selectedDate: _selectedDate,
|
||||
mode: _mode,
|
||||
onModeChanged: _handleModeChanged,
|
||||
orientation: orientation,
|
||||
era: widget.era,
|
||||
borderRadius: widget.borderRadius,
|
||||
imageHeader: widget.imageHeader,
|
||||
description: widget.description,
|
||||
fontFamily: widget.fontFamily,
|
||||
style: widget.styleDatePicker);
|
||||
switch (orientation) {
|
||||
case Orientation.landscape:
|
||||
return Container(
|
||||
height: isDesktop ? 600 : null,
|
||||
width: isDesktop ? 700 : null,
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundPicker,
|
||||
borderRadius: BorderRadius.circular(widget.borderRadius),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
Flexible(flex: 1, child: header),
|
||||
Flexible(
|
||||
flex: 2, // have the picker take up 2/3 of the dialog width
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
height: isDesktop ? 530 : null,
|
||||
width: isDesktop ? 700 : null,
|
||||
child: picker),
|
||||
actions,
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
case Orientation.portrait:
|
||||
default:
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundPicker,
|
||||
borderRadius: BorderRadius.circular(widget.borderRadius),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
header,
|
||||
if (widget.height == null)
|
||||
Flexible(child: picker)
|
||||
else
|
||||
SizedBox(
|
||||
height: widget.height,
|
||||
child: picker,
|
||||
),
|
||||
actions,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
return Theme(
|
||||
data: theme.copyWith(dialogBackgroundColor: Colors.transparent),
|
||||
child: dialog,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,226 +0,0 @@
|
|||
/*
|
||||
* This file is part of Stack Wallet.
|
||||
*
|
||||
* Copyright (c) 2023 Cypher Stack
|
||||
* All Rights Reserved.
|
||||
* The code is distributed under GPLv3 license, see LICENSE file for details.
|
||||
* Generated by Cypher Stack on 2023-05-26
|
||||
*
|
||||
*/
|
||||
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
// import 'package:flutter_rounded_date_picker/src/dialogs/flutter_rounded_date_picker_dialog.dart';
|
||||
import 'package:flutter_rounded_date_picker/src/era_mode.dart';
|
||||
import 'package:flutter_rounded_date_picker/src/material_rounded_date_picker_style.dart';
|
||||
import 'package:flutter_rounded_date_picker/src/material_rounded_year_picker_style.dart';
|
||||
import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_day_picker.dart';
|
||||
import 'package:stackwallet/widgets/rounded_date_picker/flutter_rounded_date_picker_dialog.dart';
|
||||
|
||||
///
|
||||
/// This file uses code taken from https://github.com/benznest/flutter_rounded_date_picker
|
||||
///
|
||||
|
||||
// Examples can assume:
|
||||
// BuildContext context;
|
||||
|
||||
/// Initial display mode of the date picker dialog.
|
||||
///
|
||||
/// Date picker UI mode for either showing a list of available years or a
|
||||
/// monthly calendar initially in the dialog shown by calling [showDatePicker].
|
||||
///
|
||||
|
||||
// Shows the selected date in large font and toggles between year and day mode
|
||||
|
||||
/// Signature for predicating dates for enabled date selections.
|
||||
///
|
||||
/// See [showDatePicker].
|
||||
typedef SelectableDayPredicate = bool Function(DateTime day);
|
||||
|
||||
/// Shows a dialog containing a material design date picker.
|
||||
///
|
||||
/// The returned [Future] resolves to the date selected by the user when the
|
||||
/// user closes the dialog. If the user cancels the dialog, null is returned.
|
||||
///
|
||||
/// An optional [selectableDayPredicate] function can be passed in to customize
|
||||
/// the days to enable for selection. If provided, only the days that
|
||||
/// [selectableDayPredicate] returned true for will be selectable.
|
||||
///
|
||||
/// An optional [initialDatePickerMode] argument can be used to display the
|
||||
/// date picker initially in the year or month+day picker mode. It defaults
|
||||
/// to month+day, and must not be null.
|
||||
///
|
||||
/// An optional [locale] argument can be used to set the locale for the date
|
||||
/// picker. It defaults to the ambient locale provided by [Localizations].
|
||||
///
|
||||
/// An optional [textDirection] argument can be used to set the text direction
|
||||
/// (RTL or LTR) for the date picker. It defaults to the ambient text direction
|
||||
/// provided by [Directionality]. If both [locale] and [textDirection] are not
|
||||
/// null, [textDirection] overrides the direction chosen for the [locale].
|
||||
///
|
||||
/// The [context] argument is passed to [showDialog], the documentation for
|
||||
/// which discusses how it is used.
|
||||
///
|
||||
/// The [builder] parameter can be used to wrap the dialog widget
|
||||
/// to add inherited widgets like [Theme].
|
||||
///
|
||||
/// {@tool sample}
|
||||
/// Show a date picker with the dark theme.
|
||||
///
|
||||
/// ```dart
|
||||
/// Future<DateTime> selectedDate = showDatePicker(
|
||||
/// context: context,
|
||||
/// initialDate: DateTime.now(),
|
||||
/// firstDate: DateTime(2018),
|
||||
/// lastDate: DateTime(2030),
|
||||
/// builder: (BuildContext context, Widget child) {
|
||||
/// return Theme(
|
||||
/// data: ThemeData.dark(),
|
||||
/// child: child,
|
||||
/// );
|
||||
/// },
|
||||
/// );
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// The [context], [initialDate], [firstDate], and [lastDate] parameters must
|
||||
/// not be null.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [showTimePicker], which shows a dialog that contains a material design
|
||||
/// time picker.
|
||||
/// * [DayPicker], which displays the days of a given month and allows
|
||||
/// choosing a day.
|
||||
/// * [MonthPicker], which displays a scrollable list of months to allow
|
||||
/// picking a month.
|
||||
/// * [YearPicker], which displays a scrollable list of years to allow picking
|
||||
/// a year.
|
||||
///
|
||||
|
||||
Future<DateTime?> showRoundedDatePicker(
|
||||
{required BuildContext context,
|
||||
double? height,
|
||||
DateTime? initialDate,
|
||||
DateTime? firstDate,
|
||||
DateTime? lastDate,
|
||||
SelectableDayPredicate? selectableDayPredicate,
|
||||
DatePickerMode initialDatePickerMode = DatePickerMode.day,
|
||||
Locale? locale,
|
||||
TextDirection? textDirection,
|
||||
ThemeData? theme,
|
||||
double borderRadius = 16,
|
||||
EraMode era = EraMode.CHRIST_YEAR,
|
||||
ImageProvider? imageHeader,
|
||||
String description = "",
|
||||
String? fontFamily,
|
||||
bool barrierDismissible = false,
|
||||
Color background = Colors.transparent,
|
||||
String? textNegativeButton,
|
||||
String? textPositiveButton,
|
||||
String? textActionButton,
|
||||
VoidCallback? onTapActionButton,
|
||||
MaterialRoundedDatePickerStyle? styleDatePicker,
|
||||
MaterialRoundedYearPickerStyle? styleYearPicker,
|
||||
List<String>? customWeekDays,
|
||||
BuilderDayOfDatePicker? builderDay,
|
||||
List<DateTime>? listDateDisabled,
|
||||
OnTapDay? onTapDay,
|
||||
Function? onMonthChange}) async {
|
||||
initialDate ??= DateTime.now();
|
||||
firstDate ??= DateTime(initialDate.year - 1);
|
||||
lastDate ??= DateTime(initialDate.year + 1);
|
||||
theme ??= ThemeData();
|
||||
|
||||
assert(
|
||||
!initialDate.isBefore(firstDate),
|
||||
'initialDate must be on or after firstDate',
|
||||
);
|
||||
assert(
|
||||
!initialDate.isAfter(lastDate),
|
||||
'initialDate must be on or before lastDate',
|
||||
);
|
||||
assert(
|
||||
!firstDate.isAfter(lastDate),
|
||||
'lastDate must be on or after firstDate',
|
||||
);
|
||||
assert(
|
||||
selectableDayPredicate == null || selectableDayPredicate(initialDate),
|
||||
'Provided initialDate must satisfy provided selectableDayPredicate',
|
||||
);
|
||||
assert(
|
||||
(onTapActionButton != null && textActionButton != null) ||
|
||||
onTapActionButton == null,
|
||||
"If you provide onLeftBtn, you must provide leftBtn",
|
||||
);
|
||||
assert(debugCheckHasMaterialLocalizations(context));
|
||||
|
||||
Widget child = GestureDetector(
|
||||
onTap: () {
|
||||
if (!barrierDismissible) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
color: background,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
//
|
||||
},
|
||||
child: FlutterRoundedDatePickerDialog(
|
||||
height: height,
|
||||
initialDate: initialDate,
|
||||
firstDate: firstDate,
|
||||
lastDate: lastDate,
|
||||
selectableDayPredicate: selectableDayPredicate,
|
||||
initialDatePickerMode: initialDatePickerMode,
|
||||
era: era,
|
||||
locale: locale,
|
||||
borderRadius: borderRadius,
|
||||
imageHeader: imageHeader,
|
||||
description: description,
|
||||
fontFamily: fontFamily,
|
||||
textNegativeButton: textNegativeButton,
|
||||
textPositiveButton: textPositiveButton,
|
||||
textActionButton: textActionButton,
|
||||
onTapActionButton: onTapActionButton,
|
||||
styleDatePicker: styleDatePicker,
|
||||
styleYearPicker: styleYearPicker,
|
||||
customWeekDays: customWeekDays,
|
||||
builderDay: builderDay,
|
||||
listDateDisabled: listDateDisabled,
|
||||
onTapDay: onTapDay,
|
||||
onMonthChange: onMonthChange,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (textDirection != null) {
|
||||
child = Directionality(
|
||||
textDirection: textDirection,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
if (locale != null) {
|
||||
child = Localizations.override(
|
||||
context: context,
|
||||
locale: locale,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
return await showDialog<DateTime>(
|
||||
context: context,
|
||||
barrierDismissible: barrierDismissible,
|
||||
builder: (_) => Theme(data: theme!, child: child),
|
||||
);
|
||||
}
|
|
@ -22,10 +22,10 @@ import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart';
|
|||
|
||||
class WalletInfoRowBalance extends ConsumerWidget {
|
||||
const WalletInfoRowBalance({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.walletId,
|
||||
this.contractAddress,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
final String walletId;
|
||||
final String? contractAddress;
|
||||
|
@ -45,8 +45,11 @@ class WalletInfoRowBalance extends ConsumerWidget {
|
|||
} else {
|
||||
contract = MainDB.instance.getEthContractSync(contractAddress!)!;
|
||||
totalBalance = ref
|
||||
.watch(pTokenBalance(
|
||||
(contractAddress: contractAddress!, walletId: walletId)))
|
||||
.watch(
|
||||
pTokenBalance(
|
||||
(walletId: walletId, contractAddress: contractAddress!),
|
||||
),
|
||||
)
|
||||
.total;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,29 +8,36 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:stackwallet/themes/theme_providers.dart';
|
||||
import 'package:stackwallet/themes/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
|
||||
class FrostSignNavIcon extends ConsumerWidget {
|
||||
const FrostSignNavIcon({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return SvgPicture.file(
|
||||
File(
|
||||
ref.watch(
|
||||
themeProvider.select(
|
||||
// TODO: [prio=high] update themes with icon asset
|
||||
(value) => value.assets.stackIcon,
|
||||
),
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.bottomNavIconIcon
|
||||
.withOpacity(0.4),
|
||||
borderRadius: BorderRadius.circular(
|
||||
24,
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6.0),
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.pencil,
|
||||
width: 12,
|
||||
height: 12,
|
||||
color: Theme.of(context).extension<StackColors>()!.bottomNavIconIcon,
|
||||
),
|
||||
),
|
||||
width: 24,
|
||||
height: 24,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
24
pubspec.lock
24
pubspec.lock
|
@ -238,6 +238,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.6.2"
|
||||
calendar_date_picker2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: calendar_date_picker2
|
||||
sha256: "7ff3f372faff6814a2ba69427d116fb9a3d52e28644b9de4b06db6638fdac798"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -681,8 +689,8 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "65a6676e37f1bcaf2e293afbd50e50c81394276c"
|
||||
resolved-ref: "65a6676e37f1bcaf2e293afbd50e50c81394276c"
|
||||
ref: "439727b278250c61a291f5335c298c0f2d952517"
|
||||
resolved-ref: "439727b278250c61a291f5335c298c0f2d952517"
|
||||
url: "https://github.com/cypherstack/flutter_libsparkmobile.git"
|
||||
source: git
|
||||
version: "0.0.1"
|
||||
|
@ -750,14 +758,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
flutter_rounded_date_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_rounded_date_picker
|
||||
sha256: e6aa2dc5d3b44e8bbe85ef901be69eac59ba4136427f11f4c8b2a303e1e774e7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.4"
|
||||
flutter_secure_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -2111,5 +2111,5 @@ packages:
|
|||
source: hosted
|
||||
version: "1.0.0"
|
||||
sdks:
|
||||
dart: ">=3.3.3 <4.0.0"
|
||||
flutter: ">=3.19.5"
|
||||
dart: ">=3.3.4 <4.0.0"
|
||||
flutter: ">=3.19.6"
|
||||
|
|
|
@ -14,8 +14,8 @@ description: Stack Wallet
|
|||
version: 2.0.0+220
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.3 <4.0.0"
|
||||
flutter: ^3.19.5
|
||||
sdk: ">=3.3.4 <4.0.0"
|
||||
flutter: ^3.19.6
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
@ -33,7 +33,7 @@ dependencies:
|
|||
flutter_libsparkmobile:
|
||||
git:
|
||||
url: https://github.com/cypherstack/flutter_libsparkmobile.git
|
||||
ref: 65a6676e37f1bcaf2e293afbd50e50c81394276c
|
||||
ref: 439727b278250c61a291f5335c298c0f2d952517
|
||||
|
||||
flutter_libmonero:
|
||||
path: ./crypto_plugins/flutter_libmonero
|
||||
|
@ -124,7 +124,6 @@ dependencies:
|
|||
decimal: ^2.1.0
|
||||
event_bus: ^2.0.0
|
||||
uuid: ^3.0.5
|
||||
flutter_rounded_date_picker: ^3.0.1
|
||||
crypto: ^3.0.2
|
||||
barcode_scan2: ^4.2.3
|
||||
wakelock: ^0.6.2
|
||||
|
@ -178,6 +177,7 @@ dependencies:
|
|||
url: https://github.com/cypherstack/espresso-cash-public.git
|
||||
ref: a83e375678eb22fe544dc125d29bbec0fb833882
|
||||
path: packages/solana
|
||||
calendar_date_picker2: ^1.0.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
Loading…
Reference in a new issue