mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-02-02 03:06:29 +00:00
Merge pull request #853 from cypherstack/testing_julian
various tweaks and fixes
This commit is contained in:
commit
ec084d1a9e
19 changed files with 710 additions and 628 deletions
|
@ -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';
|
||||
|
@ -134,9 +135,9 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> {
|
|||
_coins.remove(Coin.wownero);
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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:
|
||||
|
@ -757,14 +765,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:
|
||||
|
@ -1740,8 +1740,8 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: f31f8f857665d85338824ae171aba4c629c3ba6f
|
||||
resolved-ref: f31f8f857665d85338824ae171aba4c629c3ba6f
|
||||
ref: "13fa937ea9a9fc34caf047e068df9535f65c27ad"
|
||||
resolved-ref: "13fa937ea9a9fc34caf047e068df9535f65c27ad"
|
||||
url: "https://github.com/cypherstack/tezart.git"
|
||||
source: git
|
||||
version: "2.0.5"
|
||||
|
@ -2109,5 +2109,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+219
|
||||
|
||||
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:
|
||||
|
@ -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