mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-23 11:59:30 +00:00
use frost step scaffold for frost send/sign flow
This commit is contained in:
parent
92d0733005
commit
48e05919d5
35 changed files with 1422 additions and 1657 deletions
|
@ -16,6 +16,11 @@ import 'package:stackwallet/pages/add_wallet_views/frost_ms/reshare/frost_reshar
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_3c.dart';
|
import 'package:stackwallet/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_3c.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_4.dart';
|
import 'package:stackwallet/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_4.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_5.dart';
|
import 'package:stackwallet/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_5.dart';
|
||||||
|
import 'package:stackwallet/pages/send_view/frost_ms/send_steps/frost_send_step_1a.dart';
|
||||||
|
import 'package:stackwallet/pages/send_view/frost_ms/send_steps/frost_send_step_1b.dart';
|
||||||
|
import 'package:stackwallet/pages/send_view/frost_ms/send_steps/frost_send_step_2.dart';
|
||||||
|
import 'package:stackwallet/pages/send_view/frost_ms/send_steps/frost_send_step_3.dart';
|
||||||
|
import 'package:stackwallet/pages/send_view/frost_ms/send_steps/frost_send_step_4.dart';
|
||||||
import 'package:stackwallet/route_generator.dart';
|
import 'package:stackwallet/route_generator.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/intermediate/frost_currency.dart';
|
import 'package:stackwallet/wallets/crypto_currency/intermediate/frost_currency.dart';
|
||||||
|
|
||||||
|
@ -85,6 +90,20 @@ abstract class FrostRouteGenerator {
|
||||||
(routeName: FrostReshareStep5.routeName, title: FrostReshareStep5.title),
|
(routeName: FrostReshareStep5.routeName, title: FrostReshareStep5.title),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
static const List<FrostStepRoute> sendFrostTxStepRoutes = [
|
||||||
|
(routeName: FrostSendStep1a.routeName, title: FrostSendStep1a.title),
|
||||||
|
(routeName: FrostSendStep2.routeName, title: FrostSendStep2.title),
|
||||||
|
(routeName: FrostSendStep3.routeName, title: FrostSendStep3.title),
|
||||||
|
(routeName: FrostSendStep4.routeName, title: FrostSendStep4.title),
|
||||||
|
];
|
||||||
|
|
||||||
|
static const List<FrostStepRoute> signFrostTxStepRoutes = [
|
||||||
|
(routeName: FrostSendStep1b.routeName, title: FrostSendStep1b.title),
|
||||||
|
(routeName: FrostSendStep2.routeName, title: FrostSendStep2.title),
|
||||||
|
(routeName: FrostSendStep3.routeName, title: FrostSendStep3.title),
|
||||||
|
(routeName: FrostSendStep4.routeName, title: FrostSendStep4.title),
|
||||||
|
];
|
||||||
|
|
||||||
static Route<dynamic> generateRoute(RouteSettings settings) {
|
static Route<dynamic> generateRoute(RouteSettings settings) {
|
||||||
final args = settings.arguments;
|
final args = settings.arguments;
|
||||||
|
|
||||||
|
@ -194,6 +213,41 @@ abstract class FrostRouteGenerator {
|
||||||
settings: settings,
|
settings: settings,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
case FrostSendStep1a.routeName:
|
||||||
|
return RouteGenerator.getRoute(
|
||||||
|
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||||
|
builder: (_) => const FrostSendStep1a(),
|
||||||
|
settings: settings,
|
||||||
|
);
|
||||||
|
|
||||||
|
case FrostSendStep1b.routeName:
|
||||||
|
return RouteGenerator.getRoute(
|
||||||
|
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||||
|
builder: (_) => const FrostSendStep1b(),
|
||||||
|
settings: settings,
|
||||||
|
);
|
||||||
|
|
||||||
|
case FrostSendStep2.routeName:
|
||||||
|
return RouteGenerator.getRoute(
|
||||||
|
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||||
|
builder: (_) => const FrostSendStep2(),
|
||||||
|
settings: settings,
|
||||||
|
);
|
||||||
|
|
||||||
|
case FrostSendStep3.routeName:
|
||||||
|
return RouteGenerator.getRoute(
|
||||||
|
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||||
|
builder: (_) => const FrostSendStep3(),
|
||||||
|
settings: settings,
|
||||||
|
);
|
||||||
|
|
||||||
|
case FrostSendStep4.routeName:
|
||||||
|
return RouteGenerator.getRoute(
|
||||||
|
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||||
|
builder: (_) => const FrostSendStep4(),
|
||||||
|
settings: settings,
|
||||||
|
);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return _routeError("");
|
return _routeError("");
|
||||||
}
|
}
|
|
@ -3,9 +3,8 @@ import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/frost_scaffold.dart';
|
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
|
||||||
import 'package:stackwallet/pages/home_view/home_view.dart';
|
import 'package:stackwallet/pages/home_view/home_view.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
|
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
|
@ -24,6 +23,7 @@ import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
import 'package:stackwallet/widgets/dialogs/simple_mobile_dialog.dart';
|
import 'package:stackwallet/widgets/dialogs/simple_mobile_dialog.dart';
|
||||||
import 'package:stackwallet/widgets/frost_mascot.dart';
|
import 'package:stackwallet/widgets/frost_mascot.dart';
|
||||||
|
import 'package:stackwallet/widgets/frost_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,8 @@ import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/frost_scaffold.dart';
|
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
|
||||||
import 'package:stackwallet/pages/home_view/home_view.dart';
|
import 'package:stackwallet/pages/home_view/home_view.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
|
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
|
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
|
||||||
|
@ -22,6 +21,7 @@ import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
import 'package:stackwallet/widgets/dialogs/simple_mobile_dialog.dart';
|
import 'package:stackwallet/widgets/dialogs/simple_mobile_dialog.dart';
|
||||||
|
import 'package:stackwallet/widgets/frost_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
|
|
||||||
class SelectNewFrostImportTypeView extends ConsumerStatefulWidget {
|
class SelectNewFrostImportTypeView extends ConsumerStatefulWidget {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:qr_flutter/qr_flutter.dart';
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
import 'package:stackwallet/services/frost.dart';
|
import 'package:stackwallet/services/frost.dart';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
import 'package:stackwallet/services/frost.dart';
|
import 'package:stackwallet/services/frost.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
import 'package:stackwallet/services/frost.dart';
|
import 'package:stackwallet/services/frost.dart';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
import 'package:stackwallet/services/frost.dart';
|
import 'package:stackwallet/services/frost.dart';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
import 'package:stackwallet/utilities/util.dart';
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
||||||
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:qr_flutter/qr_flutter.dart';
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:frostdart/frostdart.dart';
|
import 'package:frostdart/frostdart.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
import 'package:stackwallet/utilities/show_loading.dart';
|
import 'package:stackwallet/utilities/show_loading.dart';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:qr_flutter/qr_flutter.dart';
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
import 'package:stackwallet/services/frost.dart';
|
import 'package:stackwallet/services/frost.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:ffi';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:qr_flutter/qr_flutter.dart';
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
import 'package:stackwallet/services/frost.dart';
|
import 'package:stackwallet/services/frost.dart';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:qr_flutter/qr_flutter.dart';
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
import 'package:stackwallet/themes/stack_colors.dart';
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:ffi';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:qr_flutter/qr_flutter.dart';
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
|
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/home_view/home_view.dart';
|
import 'package:stackwallet/pages/home_view/home_view.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
||||||
|
@ -30,8 +30,7 @@ class FrostReshareStep5 extends ConsumerStatefulWidget {
|
||||||
static const String title = "Verify";
|
static const String title = "Verify";
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ConsumerState<FrostReshareStep5> createState() =>
|
ConsumerState<FrostReshareStep5> createState() => _FrostReshareStep5State();
|
||||||
_FrostReshareStep5State();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FrostReshareStep5State extends ConsumerState<FrostReshareStep5> {
|
class _FrostReshareStep5State extends ConsumerState<FrostReshareStep5> {
|
||||||
|
|
|
@ -1,404 +0,0 @@
|
||||||
import 'package:barcode_scan2/barcode_scan2.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
import 'package:qr_flutter/qr_flutter.dart';
|
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/frost_continue_sign_config_view.dart';
|
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
|
||||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
|
||||||
import 'package:stackwallet/services/frost.dart';
|
|
||||||
import 'package:stackwallet/themes/stack_colors.dart';
|
|
||||||
import 'package:stackwallet/utilities/constants.dart';
|
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
|
||||||
import 'package:stackwallet/utilities/util.dart';
|
|
||||||
import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
|
||||||
import 'package:stackwallet/widgets/background.dart';
|
|
||||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
|
||||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/detail_item.dart';
|
|
||||||
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
|
|
||||||
import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
|
|
||||||
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
|
||||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
|
||||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
|
||||||
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
|
||||||
|
|
||||||
class FrostAttemptSignConfigView extends ConsumerStatefulWidget {
|
|
||||||
const FrostAttemptSignConfigView({
|
|
||||||
super.key,
|
|
||||||
required this.walletId,
|
|
||||||
});
|
|
||||||
|
|
||||||
static const String routeName = "/frostAttemptSignConfigView";
|
|
||||||
|
|
||||||
final String walletId;
|
|
||||||
|
|
||||||
@override
|
|
||||||
ConsumerState<FrostAttemptSignConfigView> createState() =>
|
|
||||||
_FrostAttemptSignConfigViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FrostAttemptSignConfigViewState
|
|
||||||
extends ConsumerState<FrostAttemptSignConfigView> {
|
|
||||||
final List<TextEditingController> controllers = [];
|
|
||||||
final List<FocusNode> focusNodes = [];
|
|
||||||
|
|
||||||
late final String myName;
|
|
||||||
late final List<String> participantsWithoutMe;
|
|
||||||
late final String myPreprocess;
|
|
||||||
late final int myIndex;
|
|
||||||
late final int threshold;
|
|
||||||
|
|
||||||
final List<bool> fieldIsEmptyFlags = [];
|
|
||||||
|
|
||||||
bool hasEnoughPreprocesses() {
|
|
||||||
// own preprocess is not included in controllers and must be set here
|
|
||||||
int count = 1;
|
|
||||||
|
|
||||||
for (final controller in controllers) {
|
|
||||||
if (controller.text.isNotEmpty) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count >= threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
final wallet =
|
|
||||||
ref.read(pWallets).getWallet(widget.walletId) as BitcoinFrostWallet;
|
|
||||||
final frostInfo = wallet.frostInfo;
|
|
||||||
|
|
||||||
myName = frostInfo.myName;
|
|
||||||
threshold = frostInfo.threshold;
|
|
||||||
participantsWithoutMe = List.from(frostInfo.participants); // Copy so it isn't fixed-length.
|
|
||||||
myIndex = participantsWithoutMe.indexOf(frostInfo.myName);
|
|
||||||
myPreprocess = ref.read(pFrostAttemptSignData.state).state!.preprocess;
|
|
||||||
|
|
||||||
participantsWithoutMe.removeAt(myIndex);
|
|
||||||
|
|
||||||
for (int i = 0; i < participantsWithoutMe.length; i++) {
|
|
||||||
controllers.add(TextEditingController());
|
|
||||||
focusNodes.add(FocusNode());
|
|
||||||
fieldIsEmptyFlags.add(true);
|
|
||||||
}
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
for (int i = 0; i < controllers.length; i++) {
|
|
||||||
controllers[i].dispose();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < focusNodes.length; i++) {
|
|
||||||
focusNodes[i].dispose();
|
|
||||||
}
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ConditionalParent(
|
|
||||||
condition: Util.isDesktop,
|
|
||||||
builder: (child) => DesktopScaffold(
|
|
||||||
background: Theme.of(context).extension<StackColors>()!.background,
|
|
||||||
appBar: const DesktopAppBar(
|
|
||||||
isCompactHeight: false,
|
|
||||||
leading: AppBarBackButton(),
|
|
||||||
),
|
|
||||||
body: SizedBox(
|
|
||||||
width: 480,
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: ConditionalParent(
|
|
||||||
condition: !Util.isDesktop,
|
|
||||||
builder: (child) => Background(
|
|
||||||
child: Scaffold(
|
|
||||||
backgroundColor:
|
|
||||||
Theme.of(context).extension<StackColors>()!.background,
|
|
||||||
appBar: AppBar(
|
|
||||||
leading: AppBarBackButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
"Preprocesses",
|
|
||||||
style: STextStyles.navBarTitle(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: SafeArea(
|
|
||||||
child: LayoutBuilder(
|
|
||||||
builder: (context, constraints) {
|
|
||||||
return SingleChildScrollView(
|
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
minHeight: constraints.maxHeight,
|
|
||||||
),
|
|
||||||
child: IntrinsicHeight(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: 220,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
QrImageView(
|
|
||||||
data: myPreprocess,
|
|
||||||
size: 220,
|
|
||||||
backgroundColor:
|
|
||||||
Theme.of(context).extension<StackColors>()!.background,
|
|
||||||
foregroundColor: Theme.of(context)
|
|
||||||
.extension<StackColors>()!
|
|
||||||
.accentColorDark,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const _Div(),
|
|
||||||
DetailItem(
|
|
||||||
title: "My name",
|
|
||||||
detail: myName,
|
|
||||||
),
|
|
||||||
const _Div(),
|
|
||||||
DetailItem(
|
|
||||||
title: "My preprocess",
|
|
||||||
detail: myPreprocess,
|
|
||||||
button: Util.isDesktop
|
|
||||||
? IconCopyButton(
|
|
||||||
data: myPreprocess,
|
|
||||||
)
|
|
||||||
: SimpleCopyButton(
|
|
||||||
data: myPreprocess,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const _Div(),
|
|
||||||
Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
for (int i = 0; i < participantsWithoutMe.length; i++)
|
|
||||||
Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
Constants.size.circularBorderRadius,
|
|
||||||
),
|
|
||||||
child: TextField(
|
|
||||||
key: Key("frostPreprocessesTextFieldKey_$i"),
|
|
||||||
controller: controllers[i],
|
|
||||||
focusNode: focusNodes[i],
|
|
||||||
readOnly: false,
|
|
||||||
autocorrect: false,
|
|
||||||
enableSuggestions: false,
|
|
||||||
style: STextStyles.field(context),
|
|
||||||
onChanged: (_) {
|
|
||||||
setState(() {
|
|
||||||
fieldIsEmptyFlags[i] =
|
|
||||||
controllers[i].text.isEmpty;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
decoration: standardInputDecoration(
|
|
||||||
"Enter ${participantsWithoutMe[i]}'s preprocess",
|
|
||||||
focusNodes[i],
|
|
||||||
context,
|
|
||||||
).copyWith(
|
|
||||||
contentPadding: const EdgeInsets.only(
|
|
||||||
left: 16,
|
|
||||||
top: 6,
|
|
||||||
bottom: 8,
|
|
||||||
right: 5,
|
|
||||||
),
|
|
||||||
suffixIcon: Padding(
|
|
||||||
padding: fieldIsEmptyFlags[i]
|
|
||||||
? const EdgeInsets.only(right: 8)
|
|
||||||
: const EdgeInsets.only(right: 0),
|
|
||||||
child: UnconstrainedBox(
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceAround,
|
|
||||||
children: [
|
|
||||||
!fieldIsEmptyFlags[i]
|
|
||||||
? TextFieldIconButton(
|
|
||||||
semanticsLabel:
|
|
||||||
"Clear Button. Clears The Preprocess Field Input.",
|
|
||||||
key: Key(
|
|
||||||
"frostPreprocessesClearButtonKey_$i",
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
controllers[i].text = "";
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
fieldIsEmptyFlags[i] = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: const XIcon(),
|
|
||||||
)
|
|
||||||
: TextFieldIconButton(
|
|
||||||
semanticsLabel:
|
|
||||||
"Paste Button. Pastes From Clipboard To Preprocess Field Input.",
|
|
||||||
key: Key(
|
|
||||||
"frostPreprocessesPasteButtonKey_$i",
|
|
||||||
),
|
|
||||||
onTap: () async {
|
|
||||||
final ClipboardData? data =
|
|
||||||
await Clipboard.getData(
|
|
||||||
Clipboard.kTextPlain);
|
|
||||||
if (data?.text != null &&
|
|
||||||
data!.text!.isNotEmpty) {
|
|
||||||
controllers[i].text =
|
|
||||||
data.text!.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
fieldIsEmptyFlags[i] =
|
|
||||||
controllers[i]
|
|
||||||
.text
|
|
||||||
.isEmpty;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: fieldIsEmptyFlags[i]
|
|
||||||
? const ClipboardIcon()
|
|
||||||
: const XIcon(),
|
|
||||||
),
|
|
||||||
if (fieldIsEmptyFlags[i])
|
|
||||||
TextFieldIconButton(
|
|
||||||
semanticsLabel:
|
|
||||||
"Scan QR Button. Opens Camera For Scanning QR Code.",
|
|
||||||
key: Key(
|
|
||||||
"frostPreprocessesScanQrButtonKey_$i",
|
|
||||||
),
|
|
||||||
onTap: () async {
|
|
||||||
try {
|
|
||||||
if (FocusScope.of(context)
|
|
||||||
.hasFocus) {
|
|
||||||
FocusScope.of(context)
|
|
||||||
.unfocus();
|
|
||||||
await Future<void>.delayed(
|
|
||||||
const Duration(
|
|
||||||
milliseconds: 75));
|
|
||||||
}
|
|
||||||
|
|
||||||
final qrResult =
|
|
||||||
await BarcodeScanner.scan();
|
|
||||||
|
|
||||||
controllers[i].text =
|
|
||||||
qrResult.rawContent;
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
fieldIsEmptyFlags[i] =
|
|
||||||
controllers[i].text.isEmpty;
|
|
||||||
});
|
|
||||||
} on PlatformException catch (e, s) {
|
|
||||||
Logging.instance.log(
|
|
||||||
"Failed to get camera permissions while trying to scan qr code: $e\n$s",
|
|
||||||
level: LogLevel.Warning,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: const QrCodeIcon(),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
if (!Util.isDesktop) const Spacer(),
|
|
||||||
const _Div(),
|
|
||||||
PrimaryButton(
|
|
||||||
label: "Continue signing",
|
|
||||||
enabled: hasEnoughPreprocesses(),
|
|
||||||
onPressed: () async {
|
|
||||||
// collect Preprocess strings (not including my own)
|
|
||||||
final preprocesses = controllers.map((e) => e.text).toList();
|
|
||||||
|
|
||||||
// collect participants who are involved in this transaction
|
|
||||||
final List<String> requiredParticipantsUnordered = [];
|
|
||||||
for (int i = 0; i < participantsWithoutMe.length; i++) {
|
|
||||||
if (preprocesses[i].isNotEmpty) {
|
|
||||||
requiredParticipantsUnordered.add(participantsWithoutMe[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ref.read(pFrostSelectParticipantsUnordered.notifier).state =
|
|
||||||
requiredParticipantsUnordered;
|
|
||||||
|
|
||||||
// insert an empty string at my index
|
|
||||||
preprocesses.insert(myIndex, "");
|
|
||||||
|
|
||||||
try {
|
|
||||||
ref.read(pFrostContinueSignData.notifier).state =
|
|
||||||
Frost.continueSigning(
|
|
||||||
machinePtr:
|
|
||||||
ref.read(pFrostAttemptSignData.state).state!.machinePtr,
|
|
||||||
preprocesses: preprocesses,
|
|
||||||
);
|
|
||||||
|
|
||||||
await Navigator.of(context).pushNamed(
|
|
||||||
FrostContinueSignView.routeName,
|
|
||||||
arguments: widget.walletId,
|
|
||||||
);
|
|
||||||
} catch (e, s) {
|
|
||||||
Logging.instance.log(
|
|
||||||
"$e\n$s",
|
|
||||||
level: LogLevel.Fatal,
|
|
||||||
);
|
|
||||||
|
|
||||||
return await showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => StackOkDialog(
|
|
||||||
title: "Failed to continue signing",
|
|
||||||
desktopPopRootNavigator: Util.isDesktop,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _Div extends StatelessWidget {
|
|
||||||
const _Div({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const SizedBox(
|
|
||||||
height: 12,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,206 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
import 'package:qr_flutter/qr_flutter.dart';
|
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
|
||||||
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
|
||||||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/my_stack_view.dart';
|
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
|
||||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
|
||||||
import 'package:stackwallet/themes/stack_colors.dart';
|
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
|
||||||
import 'package:stackwallet/utilities/show_loading.dart';
|
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
|
||||||
import 'package:stackwallet/utilities/util.dart';
|
|
||||||
import 'package:stackwallet/widgets/background.dart';
|
|
||||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
|
||||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/detail_item.dart';
|
|
||||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
|
||||||
|
|
||||||
class FrostCompleteSignView extends ConsumerStatefulWidget {
|
|
||||||
const FrostCompleteSignView({
|
|
||||||
super.key,
|
|
||||||
required this.walletId,
|
|
||||||
});
|
|
||||||
|
|
||||||
static const String routeName = "/frostCompleteSignView";
|
|
||||||
|
|
||||||
final String walletId;
|
|
||||||
|
|
||||||
@override
|
|
||||||
ConsumerState<FrostCompleteSignView> createState() =>
|
|
||||||
_FrostCompleteSignViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FrostCompleteSignViewState extends ConsumerState<FrostCompleteSignView> {
|
|
||||||
bool _broadcastLock = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ConditionalParent(
|
|
||||||
condition: Util.isDesktop,
|
|
||||||
builder: (child) => DesktopScaffold(
|
|
||||||
background: Theme.of(context).extension<StackColors>()!.background,
|
|
||||||
appBar: const DesktopAppBar(
|
|
||||||
isCompactHeight: false,
|
|
||||||
leading: AppBarBackButton(),
|
|
||||||
),
|
|
||||||
body: SizedBox(
|
|
||||||
width: 480,
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: ConditionalParent(
|
|
||||||
condition: !Util.isDesktop,
|
|
||||||
builder: (child) => Background(
|
|
||||||
child: Scaffold(
|
|
||||||
backgroundColor:
|
|
||||||
Theme.of(context).extension<StackColors>()!.background,
|
|
||||||
appBar: AppBar(
|
|
||||||
leading: AppBarBackButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
"Preview transaction",
|
|
||||||
style: STextStyles.navBarTitle(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: SafeArea(
|
|
||||||
child: LayoutBuilder(
|
|
||||||
builder: (context, constraints) {
|
|
||||||
return SingleChildScrollView(
|
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
minHeight: constraints.maxHeight,
|
|
||||||
),
|
|
||||||
child: IntrinsicHeight(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: 220,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
QrImageView(
|
|
||||||
data: ref.watch(pFrostTxData.state).state!.raw!,
|
|
||||||
size: 220,
|
|
||||||
backgroundColor:
|
|
||||||
Theme.of(context).extension<StackColors>()!.background,
|
|
||||||
foregroundColor: Theme.of(context)
|
|
||||||
.extension<StackColors>()!
|
|
||||||
.accentColorDark,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const _Div(),
|
|
||||||
DetailItem(
|
|
||||||
title: "Raw transaction hex",
|
|
||||||
detail: ref.watch(pFrostTxData.state).state!.raw!,
|
|
||||||
button: Util.isDesktop
|
|
||||||
? IconCopyButton(
|
|
||||||
data: ref.watch(pFrostTxData.state).state!.raw!,
|
|
||||||
)
|
|
||||||
: SimpleCopyButton(
|
|
||||||
data: ref.watch(pFrostTxData.state).state!.raw!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const _Div(),
|
|
||||||
if (!Util.isDesktop) const Spacer(),
|
|
||||||
const _Div(),
|
|
||||||
PrimaryButton(
|
|
||||||
label: "Broadcast Transaction",
|
|
||||||
onPressed: () async {
|
|
||||||
if (_broadcastLock) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_broadcastLock = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Exception? ex;
|
|
||||||
final txData = await showLoading(
|
|
||||||
whileFuture: ref
|
|
||||||
.read(pWallets)
|
|
||||||
.getWallet(widget.walletId)
|
|
||||||
.confirmSend(
|
|
||||||
txData: ref.read(pFrostTxData.state).state!,
|
|
||||||
),
|
|
||||||
context: context,
|
|
||||||
message: "Broadcasting transaction to network",
|
|
||||||
isDesktop: Util.isDesktop,
|
|
||||||
onException: (e) {
|
|
||||||
ex = e;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (ex != null) {
|
|
||||||
throw ex!;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mounted) {
|
|
||||||
if (txData != null) {
|
|
||||||
ref.read(pFrostTxData.state).state = txData;
|
|
||||||
Navigator.of(context).popUntil(
|
|
||||||
ModalRoute.withName(
|
|
||||||
Util.isDesktop
|
|
||||||
? MyStackView.routeName
|
|
||||||
: WalletView.routeName,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e, s) {
|
|
||||||
Logging.instance.log(
|
|
||||||
"$e\n$s",
|
|
||||||
level: LogLevel.Fatal,
|
|
||||||
);
|
|
||||||
|
|
||||||
return await showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => StackOkDialog(
|
|
||||||
title: "Broadcast error",
|
|
||||||
message: e.toString(),
|
|
||||||
desktopPopRootNavigator: Util.isDesktop,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
_broadcastLock = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _Div extends StatelessWidget {
|
|
||||||
const _Div({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const SizedBox(
|
|
||||||
height: 12,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,445 +0,0 @@
|
||||||
import 'package:barcode_scan2/barcode_scan2.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
import 'package:qr_flutter/qr_flutter.dart';
|
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/frost_complete_sign_view.dart';
|
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
|
||||||
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
|
||||||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
|
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
|
||||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
|
||||||
import 'package:stackwallet/services/frost.dart';
|
|
||||||
import 'package:stackwallet/themes/stack_colors.dart';
|
|
||||||
import 'package:stackwallet/utilities/constants.dart';
|
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
|
||||||
import 'package:stackwallet/utilities/util.dart';
|
|
||||||
import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
|
||||||
import 'package:stackwallet/widgets/background.dart';
|
|
||||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
|
||||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/detail_item.dart';
|
|
||||||
import 'package:stackwallet/widgets/dialogs/frost/frost_interruption_dialog.dart';
|
|
||||||
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
|
|
||||||
import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
|
|
||||||
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
|
||||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
|
||||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
|
||||||
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
|
||||||
|
|
||||||
class FrostContinueSignView extends ConsumerStatefulWidget {
|
|
||||||
const FrostContinueSignView({
|
|
||||||
super.key,
|
|
||||||
required this.walletId,
|
|
||||||
});
|
|
||||||
|
|
||||||
static const String routeName = "/frostContinueSignView";
|
|
||||||
|
|
||||||
final String walletId;
|
|
||||||
|
|
||||||
@override
|
|
||||||
ConsumerState<FrostContinueSignView> createState() =>
|
|
||||||
_FrostContinueSignViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FrostContinueSignViewState extends ConsumerState<FrostContinueSignView> {
|
|
||||||
final List<TextEditingController> controllers = [];
|
|
||||||
final List<FocusNode> focusNodes = [];
|
|
||||||
|
|
||||||
late final String myName;
|
|
||||||
late final List<String> participantsWithoutMe;
|
|
||||||
late final List<String> participantsAll;
|
|
||||||
late final String myShare;
|
|
||||||
late final int myIndex;
|
|
||||||
|
|
||||||
final List<bool> fieldIsEmptyFlags = [];
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
final wallet =
|
|
||||||
ref.read(pWallets).getWallet(widget.walletId) as BitcoinFrostWallet;
|
|
||||||
|
|
||||||
final frostInfo = wallet.frostInfo;
|
|
||||||
|
|
||||||
myName = frostInfo.myName;
|
|
||||||
participantsAll = frostInfo.participants;
|
|
||||||
myIndex = frostInfo.participants.indexOf(frostInfo.myName);
|
|
||||||
myShare = ref.read(pFrostContinueSignData.state).state!.share;
|
|
||||||
|
|
||||||
participantsWithoutMe = frostInfo.participants
|
|
||||||
.toSet()
|
|
||||||
.intersection(
|
|
||||||
ref.read(pFrostSelectParticipantsUnordered.state).state!.toSet())
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
participantsWithoutMe.remove(myName);
|
|
||||||
|
|
||||||
for (int i = 0; i < participantsWithoutMe.length; i++) {
|
|
||||||
controllers.add(TextEditingController());
|
|
||||||
focusNodes.add(FocusNode());
|
|
||||||
fieldIsEmptyFlags.add(true);
|
|
||||||
}
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
for (int i = 0; i < controllers.length; i++) {
|
|
||||||
controllers[i].dispose();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < focusNodes.length; i++) {
|
|
||||||
focusNodes[i].dispose();
|
|
||||||
}
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return WillPopScope(
|
|
||||||
onWillPop: () async {
|
|
||||||
await showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => FrostInterruptionDialog(
|
|
||||||
type: FrostInterruptionDialogType.transactionCreation,
|
|
||||||
popUntilOnYesRouteName: Util.isDesktop
|
|
||||||
? DesktopWalletView.routeName
|
|
||||||
: WalletView.routeName,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
child: ConditionalParent(
|
|
||||||
condition: Util.isDesktop,
|
|
||||||
builder: (child) => DesktopScaffold(
|
|
||||||
background: Theme.of(context).extension<StackColors>()!.background,
|
|
||||||
appBar: DesktopAppBar(
|
|
||||||
isCompactHeight: false,
|
|
||||||
leading: AppBarBackButton(
|
|
||||||
onPressed: () async {
|
|
||||||
await showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => const FrostInterruptionDialog(
|
|
||||||
type: FrostInterruptionDialogType.transactionCreation,
|
|
||||||
popUntilOnYesRouteName: DesktopWalletView.routeName,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: SizedBox(
|
|
||||||
width: 480,
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: ConditionalParent(
|
|
||||||
condition: !Util.isDesktop,
|
|
||||||
builder: (child) => Background(
|
|
||||||
child: Scaffold(
|
|
||||||
backgroundColor:
|
|
||||||
Theme.of(context).extension<StackColors>()!.background,
|
|
||||||
appBar: AppBar(
|
|
||||||
leading: AppBarBackButton(
|
|
||||||
onPressed: () async {
|
|
||||||
await showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => const FrostInterruptionDialog(
|
|
||||||
type: FrostInterruptionDialogType.transactionCreation,
|
|
||||||
popUntilOnYesRouteName: WalletView.routeName,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
"Shares",
|
|
||||||
style: STextStyles.navBarTitle(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: SafeArea(
|
|
||||||
child: LayoutBuilder(
|
|
||||||
builder: (context, constraints) {
|
|
||||||
return SingleChildScrollView(
|
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
minHeight: constraints.maxHeight,
|
|
||||||
),
|
|
||||||
child: IntrinsicHeight(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: 220,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
QrImageView(
|
|
||||||
data: myShare,
|
|
||||||
size: 220,
|
|
||||||
backgroundColor: Theme.of(context)
|
|
||||||
.extension<StackColors>()!
|
|
||||||
.background,
|
|
||||||
foregroundColor: Theme.of(context)
|
|
||||||
.extension<StackColors>()!
|
|
||||||
.accentColorDark,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const _Div(),
|
|
||||||
DetailItem(
|
|
||||||
title: "My name",
|
|
||||||
detail: myName,
|
|
||||||
),
|
|
||||||
const _Div(),
|
|
||||||
DetailItem(
|
|
||||||
title: "My shares",
|
|
||||||
detail: myShare,
|
|
||||||
button: Util.isDesktop
|
|
||||||
? IconCopyButton(
|
|
||||||
data: myShare,
|
|
||||||
)
|
|
||||||
: SimpleCopyButton(
|
|
||||||
data: myShare,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const _Div(),
|
|
||||||
Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
for (int i = 0; i < participantsWithoutMe.length; i++)
|
|
||||||
Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
Constants.size.circularBorderRadius,
|
|
||||||
),
|
|
||||||
child: TextField(
|
|
||||||
key: Key("frostSharesTextFieldKey_$i"),
|
|
||||||
controller: controllers[i],
|
|
||||||
focusNode: focusNodes[i],
|
|
||||||
readOnly: false,
|
|
||||||
autocorrect: false,
|
|
||||||
enableSuggestions: false,
|
|
||||||
style: STextStyles.field(context),
|
|
||||||
decoration: standardInputDecoration(
|
|
||||||
"Enter ${participantsWithoutMe[i]}'s share",
|
|
||||||
focusNodes[i],
|
|
||||||
context,
|
|
||||||
).copyWith(
|
|
||||||
contentPadding: const EdgeInsets.only(
|
|
||||||
left: 16,
|
|
||||||
top: 6,
|
|
||||||
bottom: 8,
|
|
||||||
right: 5,
|
|
||||||
),
|
|
||||||
suffixIcon: Padding(
|
|
||||||
padding: fieldIsEmptyFlags[i]
|
|
||||||
? const EdgeInsets.only(right: 8)
|
|
||||||
: const EdgeInsets.only(right: 0),
|
|
||||||
child: UnconstrainedBox(
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceAround,
|
|
||||||
children: [
|
|
||||||
!fieldIsEmptyFlags[i]
|
|
||||||
? TextFieldIconButton(
|
|
||||||
semanticsLabel:
|
|
||||||
"Clear Button. Clears "
|
|
||||||
"The Share Field Input.",
|
|
||||||
key: Key(
|
|
||||||
"frostSharesClearButtonKey_$i",
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
controllers[i].text = "";
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
fieldIsEmptyFlags[i] = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: const XIcon(),
|
|
||||||
)
|
|
||||||
: TextFieldIconButton(
|
|
||||||
semanticsLabel:
|
|
||||||
"Paste Button. Pastes From "
|
|
||||||
"Clipboard To Share Field Input.",
|
|
||||||
key: Key(
|
|
||||||
"frostSharesPasteButtonKey_$i"),
|
|
||||||
onTap: () async {
|
|
||||||
final ClipboardData? data =
|
|
||||||
await Clipboard.getData(
|
|
||||||
Clipboard.kTextPlain);
|
|
||||||
if (data?.text != null &&
|
|
||||||
data!.text!.isNotEmpty) {
|
|
||||||
controllers[i].text =
|
|
||||||
data.text!.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
fieldIsEmptyFlags[i] =
|
|
||||||
controllers[i]
|
|
||||||
.text
|
|
||||||
.isEmpty;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: fieldIsEmptyFlags[i]
|
|
||||||
? const ClipboardIcon()
|
|
||||||
: const XIcon(),
|
|
||||||
),
|
|
||||||
if (fieldIsEmptyFlags[i])
|
|
||||||
TextFieldIconButton(
|
|
||||||
semanticsLabel:
|
|
||||||
"Scan QR Button. Opens Camera "
|
|
||||||
"For Scanning QR Code.",
|
|
||||||
key: Key(
|
|
||||||
"frostSharesScanQrButtonKey_$i",
|
|
||||||
),
|
|
||||||
onTap: () async {
|
|
||||||
try {
|
|
||||||
if (FocusScope.of(context)
|
|
||||||
.hasFocus) {
|
|
||||||
FocusScope.of(context)
|
|
||||||
.unfocus();
|
|
||||||
await Future<void>.delayed(
|
|
||||||
const Duration(
|
|
||||||
milliseconds: 75));
|
|
||||||
}
|
|
||||||
|
|
||||||
final qrResult =
|
|
||||||
await BarcodeScanner.scan();
|
|
||||||
|
|
||||||
controllers[i].text =
|
|
||||||
qrResult.rawContent;
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
fieldIsEmptyFlags[i] =
|
|
||||||
controllers[i]
|
|
||||||
.text
|
|
||||||
.isEmpty;
|
|
||||||
});
|
|
||||||
} on PlatformException catch (e, s) {
|
|
||||||
Logging.instance.log(
|
|
||||||
"Failed to get camera permissions "
|
|
||||||
"while trying to scan qr code: $e\n$s",
|
|
||||||
level: LogLevel.Warning,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: const QrCodeIcon(),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
if (!Util.isDesktop) const Spacer(),
|
|
||||||
const _Div(),
|
|
||||||
PrimaryButton(
|
|
||||||
label: "Complete signing",
|
|
||||||
onPressed: () async {
|
|
||||||
// check for empty shares
|
|
||||||
if (controllers
|
|
||||||
.map((e) => e.text.isEmpty)
|
|
||||||
.reduce((value, element) => value |= element)) {
|
|
||||||
return await showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => StackOkDialog(
|
|
||||||
title: "Missing Shares",
|
|
||||||
desktopPopRootNavigator: Util.isDesktop,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// collect Share strings
|
|
||||||
final sharesCollected =
|
|
||||||
controllers.map((e) => e.text).toList();
|
|
||||||
|
|
||||||
final List<String> shares = [];
|
|
||||||
for (final participant in participantsAll) {
|
|
||||||
if (participantsWithoutMe.contains(participant)) {
|
|
||||||
shares.add(sharesCollected[
|
|
||||||
participantsWithoutMe.indexOf(participant)]);
|
|
||||||
} else {
|
|
||||||
shares.add("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
final rawTx = Frost.completeSigning(
|
|
||||||
machinePtr: ref
|
|
||||||
.read(pFrostContinueSignData.state)
|
|
||||||
.state!
|
|
||||||
.machinePtr,
|
|
||||||
shares: shares,
|
|
||||||
);
|
|
||||||
|
|
||||||
ref.read(pFrostTxData.state).state =
|
|
||||||
ref.read(pFrostTxData.state).state!.copyWith(
|
|
||||||
raw: rawTx,
|
|
||||||
);
|
|
||||||
|
|
||||||
await Navigator.of(context).pushNamed(
|
|
||||||
FrostCompleteSignView.routeName,
|
|
||||||
arguments: widget.walletId,
|
|
||||||
);
|
|
||||||
} catch (e, s) {
|
|
||||||
Logging.instance.log(
|
|
||||||
"$e\n$s",
|
|
||||||
level: LogLevel.Fatal,
|
|
||||||
);
|
|
||||||
|
|
||||||
return await showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => StackOkDialog(
|
|
||||||
title: "Failed to complete signing process",
|
|
||||||
desktopPopRootNavigator: Util.isDesktop,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _Div extends StatelessWidget {
|
|
||||||
const _Div({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const SizedBox(
|
|
||||||
height: 12,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,185 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
import 'package:qr_flutter/qr_flutter.dart';
|
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart';
|
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
|
||||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
|
||||||
import 'package:stackwallet/themes/stack_colors.dart';
|
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
|
||||||
import 'package:stackwallet/utilities/util.dart';
|
|
||||||
import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
|
||||||
import 'package:stackwallet/widgets/background.dart';
|
|
||||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
|
||||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/detail_item.dart';
|
|
||||||
|
|
||||||
class FrostCreateSignConfigView extends ConsumerStatefulWidget {
|
|
||||||
const FrostCreateSignConfigView({
|
|
||||||
super.key,
|
|
||||||
required this.walletId,
|
|
||||||
});
|
|
||||||
|
|
||||||
static const String routeName = "/frostCreateSignConfigView";
|
|
||||||
|
|
||||||
final String walletId;
|
|
||||||
|
|
||||||
@override
|
|
||||||
ConsumerState<FrostCreateSignConfigView> createState() =>
|
|
||||||
_FrostCreateSignConfigViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FrostCreateSignConfigViewState
|
|
||||||
extends ConsumerState<FrostCreateSignConfigView> {
|
|
||||||
bool _attemptSignLock = false;
|
|
||||||
|
|
||||||
Future<void> _attemptSign() async {
|
|
||||||
if (_attemptSignLock) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_attemptSignLock = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
final wallet =
|
|
||||||
ref.read(pWallets).getWallet(widget.walletId) as BitcoinFrostWallet;
|
|
||||||
|
|
||||||
final attemptSignRes = await wallet.frostAttemptSignConfig(
|
|
||||||
config: ref.read(pFrostTxData.state).state!.frostMSConfig!,
|
|
||||||
);
|
|
||||||
|
|
||||||
ref.read(pFrostAttemptSignData.notifier).state = attemptSignRes;
|
|
||||||
|
|
||||||
await Navigator.of(context).pushNamed(
|
|
||||||
FrostAttemptSignConfigView.routeName,
|
|
||||||
arguments: widget.walletId,
|
|
||||||
);
|
|
||||||
} catch (e, s) {
|
|
||||||
Logging.instance.log(
|
|
||||||
"$e\n$s",
|
|
||||||
level: LogLevel.Error,
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
_attemptSignLock = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
double qrImageSize =
|
|
||||||
Util.isDesktop ? 360 : MediaQuery.of(context).size.width - 32;
|
|
||||||
return ConditionalParent(
|
|
||||||
condition: Util.isDesktop,
|
|
||||||
builder: (child) => DesktopScaffold(
|
|
||||||
background: Theme.of(context).extension<StackColors>()!.background,
|
|
||||||
appBar: const DesktopAppBar(
|
|
||||||
isCompactHeight: false,
|
|
||||||
leading: AppBarBackButton(),
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
child: SizedBox(
|
|
||||||
width: 600, // Was 480, may look better but overflows the bottom.
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: ConditionalParent(
|
|
||||||
condition: !Util.isDesktop,
|
|
||||||
builder: (child) => Background(
|
|
||||||
child: Scaffold(
|
|
||||||
backgroundColor:
|
|
||||||
Theme.of(context).extension<StackColors>()!.background,
|
|
||||||
appBar: AppBar(
|
|
||||||
leading: AppBarBackButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
"Sign config",
|
|
||||||
style: STextStyles.navBarTitle(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: SafeArea(
|
|
||||||
child: LayoutBuilder(
|
|
||||||
builder: (context, constraints) {
|
|
||||||
return SingleChildScrollView(
|
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
minHeight: constraints.maxHeight,
|
|
||||||
),
|
|
||||||
child: IntrinsicHeight(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
if (!Util.isDesktop) const Spacer(),
|
|
||||||
SizedBox(
|
|
||||||
height: qrImageSize,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
QrImageView(
|
|
||||||
data: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
|
|
||||||
size: qrImageSize,
|
|
||||||
backgroundColor:
|
|
||||||
Theme.of(context).extension<StackColors>()!.background,
|
|
||||||
foregroundColor: Theme.of(context)
|
|
||||||
.extension<StackColors>()!
|
|
||||||
.accentColorDark,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (!Util.isDesktop)
|
|
||||||
const SizedBox(
|
|
||||||
height: 32,
|
|
||||||
),
|
|
||||||
DetailItem(
|
|
||||||
title: "Encoded config",
|
|
||||||
detail: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
|
|
||||||
button: Util.isDesktop
|
|
||||||
? IconCopyButton(
|
|
||||||
data: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
|
|
||||||
)
|
|
||||||
: SimpleCopyButton(
|
|
||||||
data: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: Util.isDesktop ? 20 : 16,
|
|
||||||
),
|
|
||||||
if (!Util.isDesktop)
|
|
||||||
const Spacer(
|
|
||||||
flex: 2,
|
|
||||||
),
|
|
||||||
PrimaryButton(
|
|
||||||
label: "Attempt sign",
|
|
||||||
onPressed: () {
|
|
||||||
_attemptSign();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,332 +0,0 @@
|
||||||
import 'package:barcode_scan2/barcode_scan2.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
import 'package:isar/isar.dart';
|
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart';
|
|
||||||
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
|
||||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
|
||||||
import 'package:stackwallet/services/frost.dart';
|
|
||||||
import 'package:stackwallet/themes/stack_colors.dart';
|
|
||||||
import 'package:stackwallet/utilities/constants.dart';
|
|
||||||
import 'package:stackwallet/utilities/format.dart';
|
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
|
||||||
import 'package:stackwallet/utilities/util.dart';
|
|
||||||
import 'package:stackwallet/wallets/models/tx_data.dart';
|
|
||||||
import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
|
||||||
import 'package:stackwallet/widgets/background.dart';
|
|
||||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
|
||||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
|
|
||||||
import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
|
|
||||||
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
|
||||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
|
||||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
|
||||||
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
|
||||||
|
|
||||||
class FrostImportSignConfigView extends ConsumerStatefulWidget {
|
|
||||||
const FrostImportSignConfigView({
|
|
||||||
super.key,
|
|
||||||
required this.walletId,
|
|
||||||
});
|
|
||||||
|
|
||||||
static const String routeName = "/frostImportSignConfigView";
|
|
||||||
|
|
||||||
final String walletId;
|
|
||||||
|
|
||||||
@override
|
|
||||||
ConsumerState<FrostImportSignConfigView> createState() =>
|
|
||||||
_FrostImportSignConfigViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FrostImportSignConfigViewState
|
|
||||||
extends ConsumerState<FrostImportSignConfigView> {
|
|
||||||
late final TextEditingController configFieldController;
|
|
||||||
late final FocusNode configFocusNode;
|
|
||||||
|
|
||||||
bool _configEmpty = true;
|
|
||||||
|
|
||||||
bool _attemptSignLock = false;
|
|
||||||
|
|
||||||
Future<void> _attemptSign() async {
|
|
||||||
if (_attemptSignLock) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_attemptSignLock = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (FocusScope.of(context).hasFocus) {
|
|
||||||
FocusScope.of(context).unfocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
final config = configFieldController.text;
|
|
||||||
final wallet =
|
|
||||||
ref.read(pWallets).getWallet(widget.walletId) as BitcoinFrostWallet;
|
|
||||||
|
|
||||||
final data = Frost.extractDataFromSignConfig(
|
|
||||||
signConfig: config,
|
|
||||||
coin: wallet.cryptoCurrency,
|
|
||||||
);
|
|
||||||
|
|
||||||
final utxos = await ref
|
|
||||||
.read(mainDBProvider)
|
|
||||||
.getUTXOs(wallet.walletId)
|
|
||||||
.filter()
|
|
||||||
.anyOf(
|
|
||||||
data.inputs,
|
|
||||||
(q, e) => q
|
|
||||||
.txidEqualTo(Format.uint8listToString(e.hash))
|
|
||||||
.and()
|
|
||||||
.valueEqualTo(e.value)
|
|
||||||
.and()
|
|
||||||
.voutEqualTo(e.vout))
|
|
||||||
.findAll();
|
|
||||||
|
|
||||||
// TODO add more data from 'data' and display to user ?
|
|
||||||
ref.read(pFrostTxData.notifier).state = TxData(
|
|
||||||
frostMSConfig: config,
|
|
||||||
recipients: data.recipients
|
|
||||||
.map((e) => (address: e.address, amount: e.amount, isChange: false))
|
|
||||||
.toList(),
|
|
||||||
utxos: utxos.toSet(),
|
|
||||||
);
|
|
||||||
|
|
||||||
final attemptSignRes = await wallet.frostAttemptSignConfig(
|
|
||||||
config: ref.read(pFrostTxData.state).state!.frostMSConfig!,
|
|
||||||
);
|
|
||||||
|
|
||||||
ref.read(pFrostAttemptSignData.notifier).state = attemptSignRes;
|
|
||||||
|
|
||||||
await Navigator.of(context).pushNamed(
|
|
||||||
FrostAttemptSignConfigView.routeName,
|
|
||||||
arguments: widget.walletId,
|
|
||||||
);
|
|
||||||
} catch (e, s) {
|
|
||||||
Logging.instance.log(
|
|
||||||
"$e\n$s",
|
|
||||||
level: LogLevel.Error,
|
|
||||||
);
|
|
||||||
await showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => StackOkDialog(
|
|
||||||
title: "Import and attempt sign config failed",
|
|
||||||
message: e.toString(),
|
|
||||||
desktopPopRootNavigator: Util.isDesktop,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
_attemptSignLock = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
configFieldController = TextEditingController();
|
|
||||||
configFocusNode = FocusNode();
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
configFieldController.dispose();
|
|
||||||
configFocusNode.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ConditionalParent(
|
|
||||||
condition: Util.isDesktop,
|
|
||||||
builder: (child) => DesktopScaffold(
|
|
||||||
background: Theme.of(context).extension<StackColors>()!.background,
|
|
||||||
appBar: const DesktopAppBar(
|
|
||||||
isCompactHeight: false,
|
|
||||||
leading: AppBarBackButton(),
|
|
||||||
),
|
|
||||||
body: SizedBox(
|
|
||||||
width: 480,
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: ConditionalParent(
|
|
||||||
condition: !Util.isDesktop,
|
|
||||||
builder: (child) => Background(
|
|
||||||
child: Scaffold(
|
|
||||||
backgroundColor:
|
|
||||||
Theme.of(context).extension<StackColors>()!.background,
|
|
||||||
appBar: AppBar(
|
|
||||||
leading: AppBarBackButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
"Import FROST sign config",
|
|
||||||
style: STextStyles.navBarTitle(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: SafeArea(
|
|
||||||
child: LayoutBuilder(
|
|
||||||
builder: (context, constraints) {
|
|
||||||
return SingleChildScrollView(
|
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
minHeight: constraints.maxHeight,
|
|
||||||
),
|
|
||||||
child: IntrinsicHeight(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
Constants.size.circularBorderRadius,
|
|
||||||
),
|
|
||||||
child: TextField(
|
|
||||||
key: const Key("frConfigTextFieldKey"),
|
|
||||||
controller: configFieldController,
|
|
||||||
onChanged: (_) {
|
|
||||||
setState(() {
|
|
||||||
_configEmpty = configFieldController.text.isEmpty;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
focusNode: configFocusNode,
|
|
||||||
readOnly: false,
|
|
||||||
autocorrect: false,
|
|
||||||
enableSuggestions: false,
|
|
||||||
style: STextStyles.field(context),
|
|
||||||
decoration: standardInputDecoration(
|
|
||||||
"Enter config",
|
|
||||||
configFocusNode,
|
|
||||||
context,
|
|
||||||
).copyWith(
|
|
||||||
contentPadding: const EdgeInsets.only(
|
|
||||||
left: 16,
|
|
||||||
top: 6,
|
|
||||||
bottom: 8,
|
|
||||||
right: 5,
|
|
||||||
),
|
|
||||||
suffixIcon: Padding(
|
|
||||||
padding: _configEmpty
|
|
||||||
? const EdgeInsets.only(right: 8)
|
|
||||||
: const EdgeInsets.only(right: 0),
|
|
||||||
child: UnconstrainedBox(
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
children: [
|
|
||||||
!_configEmpty
|
|
||||||
? TextFieldIconButton(
|
|
||||||
semanticsLabel:
|
|
||||||
"Clear Button. Clears The Config Field.",
|
|
||||||
key: const Key("frConfigClearButtonKey"),
|
|
||||||
onTap: () {
|
|
||||||
configFieldController.text = "";
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
_configEmpty = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: const XIcon(),
|
|
||||||
)
|
|
||||||
: TextFieldIconButton(
|
|
||||||
semanticsLabel:
|
|
||||||
"Paste Button. Pastes From Clipboard To Config Field Input.",
|
|
||||||
key: const Key("frConfigPasteButtonKey"),
|
|
||||||
onTap: () async {
|
|
||||||
final ClipboardData? data =
|
|
||||||
await Clipboard.getData(
|
|
||||||
Clipboard.kTextPlain);
|
|
||||||
if (data?.text != null &&
|
|
||||||
data!.text!.isNotEmpty) {
|
|
||||||
configFieldController.text =
|
|
||||||
data.text!.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
_configEmpty =
|
|
||||||
configFieldController.text.isEmpty;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: _configEmpty
|
|
||||||
? const ClipboardIcon()
|
|
||||||
: const XIcon(),
|
|
||||||
),
|
|
||||||
if (_configEmpty)
|
|
||||||
TextFieldIconButton(
|
|
||||||
semanticsLabel:
|
|
||||||
"Scan QR Button. Opens Camera For Scanning QR Code.",
|
|
||||||
key: const Key("frConfigScanQrButtonKey"),
|
|
||||||
onTap: () async {
|
|
||||||
try {
|
|
||||||
if (FocusScope.of(context).hasFocus) {
|
|
||||||
FocusScope.of(context).unfocus();
|
|
||||||
await Future<void>.delayed(
|
|
||||||
const Duration(milliseconds: 75));
|
|
||||||
}
|
|
||||||
|
|
||||||
final qrResult = await BarcodeScanner.scan();
|
|
||||||
|
|
||||||
configFieldController.text =
|
|
||||||
qrResult.rawContent;
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
_configEmpty =
|
|
||||||
configFieldController.text.isEmpty;
|
|
||||||
});
|
|
||||||
} on PlatformException catch (e, s) {
|
|
||||||
Logging.instance.log(
|
|
||||||
"Failed to get camera permissions while trying to scan qr code: $e\n$s",
|
|
||||||
level: LogLevel.Warning,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: const QrCodeIcon(),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
if (!Util.isDesktop) const Spacer(),
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
PrimaryButton(
|
|
||||||
label: "Start signing",
|
|
||||||
enabled: !_configEmpty,
|
|
||||||
onPressed: () {
|
|
||||||
_attemptSign();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,9 +14,9 @@ import 'dart:io';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||||
import 'package:stackwallet/pages/coin_control/coin_control_view.dart';
|
import 'package:stackwallet/pages/coin_control/coin_control_view.dart';
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/frost_create_sign_config_view.dart';
|
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/recipient.dart';
|
import 'package:stackwallet/pages/send_view/frost_ms/recipient.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
import 'package:stackwallet/providers/providers.dart';
|
import 'package:stackwallet/providers/providers.dart';
|
||||||
|
@ -38,6 +38,7 @@ import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||||
import 'package:stackwallet/widgets/fee_slider.dart';
|
import 'package:stackwallet/widgets/fee_slider.dart';
|
||||||
|
import 'package:stackwallet/widgets/frost_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
||||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||||
|
@ -120,12 +121,29 @@ class _FrostSendViewState extends ConsumerState<FrostSendView> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final wallet =
|
||||||
|
ref.read(pWallets).getWallet(walletId) as BitcoinFrostWallet;
|
||||||
|
|
||||||
if (mounted && txData != null) {
|
if (mounted && txData != null) {
|
||||||
ref.read(pFrostTxData.notifier).state = txData;
|
ref.read(pFrostTxData.notifier).state = txData;
|
||||||
|
|
||||||
|
ref.read(pFrostScaffoldArgs.state).state = (
|
||||||
|
info: (
|
||||||
|
walletName: wallet.info.name,
|
||||||
|
frostCurrency: wallet.cryptoCurrency,
|
||||||
|
),
|
||||||
|
walletId: walletId,
|
||||||
|
stepRoutes: FrostRouteGenerator.sendFrostTxStepRoutes,
|
||||||
|
onSuccess: () {
|
||||||
|
// successful completion of steps
|
||||||
|
// TODO ?
|
||||||
|
|
||||||
|
ref.read(pFrostScaffoldArgs.state).state = null;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
await Navigator.of(context).pushNamed(
|
await Navigator.of(context).pushNamed(
|
||||||
FrostCreateSignConfigView.routeName,
|
FrostStepScaffold.routeName,
|
||||||
arguments: widget.walletId,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
196
lib/pages/send_view/frost_ms/send_steps/frost_send_step_1a.dart
Normal file
196
lib/pages/send_view/frost_ms/send_steps/frost_send_step_1a.dart
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
|
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||||
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
|
import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
||||||
|
import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/detail_item.dart';
|
||||||
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
|
|
||||||
|
class FrostSendStep1a extends ConsumerStatefulWidget {
|
||||||
|
const FrostSendStep1a({super.key});
|
||||||
|
|
||||||
|
static const String routeName = "/FrostSendStep1a";
|
||||||
|
static const String title = "FROST transaction";
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<FrostSendStep1a> createState() => _FrostSendStep1aState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FrostSendStep1aState extends ConsumerState<FrostSendStep1a> {
|
||||||
|
static const steps2to4 = [
|
||||||
|
"Wait for them to import the transaction config.",
|
||||||
|
"Verify that everyone has filled out their forms before continuing. If you "
|
||||||
|
"try to continue before everyone is ready, the process will be "
|
||||||
|
"canceled.",
|
||||||
|
"Check the box and press “Attempt sign”.",
|
||||||
|
];
|
||||||
|
|
||||||
|
bool _attemptSignLock = false;
|
||||||
|
|
||||||
|
Future<void> _attemptSign() async {
|
||||||
|
if (_attemptSignLock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_attemptSignLock = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final wallet = ref.read(pWallets).getWallet(
|
||||||
|
ref.read(pFrostScaffoldArgs)!.walletId!,
|
||||||
|
) as BitcoinFrostWallet;
|
||||||
|
|
||||||
|
final attemptSignRes = await wallet.frostAttemptSignConfig(
|
||||||
|
config: ref.read(pFrostTxData.state).state!.frostMSConfig!,
|
||||||
|
);
|
||||||
|
|
||||||
|
ref.read(pFrostAttemptSignData.notifier).state = attemptSignRes;
|
||||||
|
|
||||||
|
ref.read(pFrostCreateCurrentStep.state).state = 2;
|
||||||
|
await Navigator.of(context).pushNamed(
|
||||||
|
ref
|
||||||
|
.read(pFrostScaffoldArgs)!
|
||||||
|
.stepRoutes[ref.read(pFrostCreateCurrentStep) - 1]
|
||||||
|
.routeName,
|
||||||
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"$e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
_attemptSignLock = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final double qrImageSize =
|
||||||
|
Util.isDesktop ? 360 : MediaQuery.of(context).size.width - 32;
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
RoundedWhiteContainer(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"1.",
|
||||||
|
style: STextStyles.w500_12(context),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 4,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text:
|
||||||
|
"Share this config with the group members. ",
|
||||||
|
style: STextStyles.w600_12(context),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text:
|
||||||
|
"You must have the threshold number of signatures (including yours) to send the transaction.",
|
||||||
|
style: STextStyles.w600_12(context).copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.customTextButtonEnabledText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
for (int i = 0; i < steps2to4.length; i++)
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"${i + 2}.",
|
||||||
|
style: STextStyles.w500_12(context),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 4,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
steps2to4[i],
|
||||||
|
style: STextStyles.w500_12(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: Util.isDesktop ? 20 : 16,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: qrImageSize,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
QrImageView(
|
||||||
|
data: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
|
||||||
|
size: qrImageSize,
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).extension<StackColors>()!.background,
|
||||||
|
foregroundColor: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.accentColorDark,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (!Util.isDesktop)
|
||||||
|
const SizedBox(
|
||||||
|
height: 32,
|
||||||
|
),
|
||||||
|
DetailItem(
|
||||||
|
title: "Encoded config",
|
||||||
|
detail: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
|
||||||
|
button: Util.isDesktop
|
||||||
|
? IconCopyButton(
|
||||||
|
data: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
|
||||||
|
)
|
||||||
|
: SimpleCopyButton(
|
||||||
|
data: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: Util.isDesktop ? 20 : 16,
|
||||||
|
),
|
||||||
|
if (!Util.isDesktop)
|
||||||
|
const Spacer(
|
||||||
|
flex: 2,
|
||||||
|
),
|
||||||
|
PrimaryButton(
|
||||||
|
label: "Attempt sign",
|
||||||
|
onPressed: () {
|
||||||
|
_attemptSign();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
180
lib/pages/send_view/frost_ms/send_steps/frost_send_step_1b.dart
Normal file
180
lib/pages/send_view/frost_ms/send_steps/frost_send_step_1b.dart
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
|
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||||
|
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
||||||
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
|
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||||
|
import 'package:stackwallet/services/frost.dart';
|
||||||
|
import 'package:stackwallet/utilities/format.dart';
|
||||||
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
|
import 'package:stackwallet/wallets/models/tx_data.dart';
|
||||||
|
import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/frost_step_user_steps.dart';
|
||||||
|
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||||
|
import 'package:stackwallet/widgets/textfields/frost_step_field.dart';
|
||||||
|
|
||||||
|
class FrostSendStep1b extends ConsumerStatefulWidget {
|
||||||
|
const FrostSendStep1b({super.key});
|
||||||
|
|
||||||
|
static const String routeName = "/FrostSendStep1b";
|
||||||
|
static const String title = "Sign FROST transaction";
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<FrostSendStep1b> createState() => _FrostSendStep1bState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FrostSendStep1bState extends ConsumerState<FrostSendStep1b> {
|
||||||
|
static const info = [
|
||||||
|
"Scan the config QR code or paste the code provided by the member "
|
||||||
|
"initiating this transaction.",
|
||||||
|
"Wait for other members to finish entering their information.",
|
||||||
|
"Verify that everyone has filled out their forms before continuing. If you "
|
||||||
|
"try to continue before everyone is ready, the process will be "
|
||||||
|
"canceled.",
|
||||||
|
"Check the box and press “Start signing”.",
|
||||||
|
];
|
||||||
|
|
||||||
|
late final TextEditingController configFieldController;
|
||||||
|
late final FocusNode configFocusNode;
|
||||||
|
|
||||||
|
bool _configEmpty = true;
|
||||||
|
|
||||||
|
bool _attemptSignLock = false;
|
||||||
|
|
||||||
|
Future<void> _attemptSign() async {
|
||||||
|
if (_attemptSignLock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_attemptSignLock = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (FocusScope.of(context).hasFocus) {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
final config = configFieldController.text;
|
||||||
|
final wallet = ref.read(pWallets).getWallet(
|
||||||
|
ref.read(pFrostScaffoldArgs)!.walletId!,
|
||||||
|
) as BitcoinFrostWallet;
|
||||||
|
|
||||||
|
final data = Frost.extractDataFromSignConfig(
|
||||||
|
signConfig: config,
|
||||||
|
coin: wallet.cryptoCurrency,
|
||||||
|
);
|
||||||
|
|
||||||
|
final utxos = await ref
|
||||||
|
.read(mainDBProvider)
|
||||||
|
.getUTXOs(wallet.walletId)
|
||||||
|
.filter()
|
||||||
|
.anyOf(
|
||||||
|
data.inputs,
|
||||||
|
(q, e) => q
|
||||||
|
.txidEqualTo(Format.uint8listToString(e.hash))
|
||||||
|
.and()
|
||||||
|
.valueEqualTo(e.value)
|
||||||
|
.and()
|
||||||
|
.voutEqualTo(e.vout))
|
||||||
|
.findAll();
|
||||||
|
|
||||||
|
// TODO add more data from 'data' and display to user ?
|
||||||
|
ref.read(pFrostTxData.notifier).state = TxData(
|
||||||
|
frostMSConfig: config,
|
||||||
|
recipients: data.recipients
|
||||||
|
.map((e) => (address: e.address, amount: e.amount, isChange: false))
|
||||||
|
.toList(),
|
||||||
|
utxos: utxos.toSet(),
|
||||||
|
);
|
||||||
|
|
||||||
|
final attemptSignRes = await wallet.frostAttemptSignConfig(
|
||||||
|
config: ref.read(pFrostTxData.state).state!.frostMSConfig!,
|
||||||
|
);
|
||||||
|
|
||||||
|
ref.read(pFrostAttemptSignData.notifier).state = attemptSignRes;
|
||||||
|
|
||||||
|
ref.read(pFrostCreateCurrentStep.state).state = 2;
|
||||||
|
await Navigator.of(context).pushNamed(
|
||||||
|
ref
|
||||||
|
.read(pFrostScaffoldArgs)!
|
||||||
|
.stepRoutes[ref.read(pFrostCreateCurrentStep) - 1]
|
||||||
|
.routeName,
|
||||||
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"$e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
await showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => StackOkDialog(
|
||||||
|
title: "Import and attempt sign config failed",
|
||||||
|
message: e.toString(),
|
||||||
|
desktopPopRootNavigator: Util.isDesktop,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
_attemptSignLock = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
configFieldController = TextEditingController();
|
||||||
|
configFocusNode = FocusNode();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
configFieldController.dispose();
|
||||||
|
configFocusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
const FrostStepUserSteps(
|
||||||
|
userSteps: info,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
FrostStepField(
|
||||||
|
controller: configFieldController,
|
||||||
|
focusNode: configFocusNode,
|
||||||
|
showQrScanOption: true,
|
||||||
|
label: "Import sign config",
|
||||||
|
hint: "Enter config",
|
||||||
|
onChanged: (_) {
|
||||||
|
setState(() {
|
||||||
|
_configEmpty = configFieldController.text.isEmpty;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
if (!Util.isDesktop) const Spacer(),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
PrimaryButton(
|
||||||
|
label: "Start signing",
|
||||||
|
enabled: !_configEmpty,
|
||||||
|
onPressed: () {
|
||||||
|
_attemptSign();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
407
lib/pages/send_view/frost_ms/send_steps/frost_send_step_2.dart
Normal file
407
lib/pages/send_view/frost_ms/send_steps/frost_send_step_2.dart
Normal file
|
@ -0,0 +1,407 @@
|
||||||
|
import 'package:barcode_scan2/barcode_scan2.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
|
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||||
|
import 'package:stackwallet/services/frost.dart';
|
||||||
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
|
import 'package:stackwallet/utilities/constants.dart';
|
||||||
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
|
import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
||||||
|
import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/detail_item.dart';
|
||||||
|
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
|
||||||
|
import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
|
||||||
|
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
||||||
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
|
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||||
|
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||||
|
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
||||||
|
|
||||||
|
class FrostSendStep2 extends ConsumerStatefulWidget {
|
||||||
|
const FrostSendStep2({super.key});
|
||||||
|
|
||||||
|
static const String routeName = "/FrostSendStep2";
|
||||||
|
static const String title = "Preprocesses";
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<FrostSendStep2> createState() => _FrostSendStep2State();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FrostSendStep2State extends ConsumerState<FrostSendStep2> {
|
||||||
|
final List<TextEditingController> controllers = [];
|
||||||
|
final List<FocusNode> focusNodes = [];
|
||||||
|
|
||||||
|
late final String myName;
|
||||||
|
late final List<String> participantsWithoutMe;
|
||||||
|
late final String myPreprocess;
|
||||||
|
late final int myIndex;
|
||||||
|
late final int threshold;
|
||||||
|
|
||||||
|
final List<bool> fieldIsEmptyFlags = [];
|
||||||
|
|
||||||
|
bool hasEnoughPreprocesses() {
|
||||||
|
// own preprocess is not included in controllers and must be set here
|
||||||
|
int count = 1;
|
||||||
|
|
||||||
|
for (final controller in controllers) {
|
||||||
|
if (controller.text.isNotEmpty) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count >= threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
final wallet = ref.read(pWallets).getWallet(
|
||||||
|
ref.read(pFrostScaffoldArgs)!.walletId!,
|
||||||
|
) as BitcoinFrostWallet;
|
||||||
|
final frostInfo = wallet.frostInfo;
|
||||||
|
|
||||||
|
myName = frostInfo.myName;
|
||||||
|
threshold = frostInfo.threshold;
|
||||||
|
participantsWithoutMe =
|
||||||
|
List.from(frostInfo.participants); // Copy so it isn't fixed-length.
|
||||||
|
myIndex = participantsWithoutMe.indexOf(frostInfo.myName);
|
||||||
|
myPreprocess = ref.read(pFrostAttemptSignData.state).state!.preprocess;
|
||||||
|
|
||||||
|
participantsWithoutMe.removeAt(myIndex);
|
||||||
|
|
||||||
|
for (int i = 0; i < participantsWithoutMe.length; i++) {
|
||||||
|
controllers.add(TextEditingController());
|
||||||
|
focusNodes.add(FocusNode());
|
||||||
|
fieldIsEmptyFlags.add(true);
|
||||||
|
}
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
for (int i = 0; i < controllers.length; i++) {
|
||||||
|
controllers[i].dispose();
|
||||||
|
}
|
||||||
|
for (int i = 0; i < focusNodes.length; i++) {
|
||||||
|
focusNodes[i].dispose();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
RoundedWhiteContainer(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"1.",
|
||||||
|
style: STextStyles.w500_12(context),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 4,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Share your preprocess with other signing group members.",
|
||||||
|
style: STextStyles.w500_12(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"1.",
|
||||||
|
style: STextStyles.w500_12(context),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 4,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text:
|
||||||
|
"Enter their preprocesses into the corresponding fields. ",
|
||||||
|
style: STextStyles.w600_12(context),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: "You must have the threshold number of "
|
||||||
|
"preprocesses (including yours) to send this transaction.",
|
||||||
|
style: STextStyles.w600_12(context).copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.customTextButtonEnabledText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 220,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
QrImageView(
|
||||||
|
data: myPreprocess,
|
||||||
|
size: 220,
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).extension<StackColors>()!.background,
|
||||||
|
foregroundColor: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.accentColorDark,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
DetailItem(
|
||||||
|
title: "My name",
|
||||||
|
detail: myName,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
DetailItem(
|
||||||
|
title: "My preprocess",
|
||||||
|
detail: myPreprocess,
|
||||||
|
button: Util.isDesktop
|
||||||
|
? IconCopyButton(
|
||||||
|
data: myPreprocess,
|
||||||
|
)
|
||||||
|
: SimpleCopyButton(
|
||||||
|
data: myPreprocess,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
for (int i = 0; i < participantsWithoutMe.length; i++)
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
Constants.size.circularBorderRadius,
|
||||||
|
),
|
||||||
|
child: TextField(
|
||||||
|
key: Key("frostPreprocessesTextFieldKey_$i"),
|
||||||
|
controller: controllers[i],
|
||||||
|
focusNode: focusNodes[i],
|
||||||
|
readOnly: false,
|
||||||
|
autocorrect: false,
|
||||||
|
enableSuggestions: false,
|
||||||
|
style: STextStyles.field(context),
|
||||||
|
onChanged: (_) {
|
||||||
|
setState(() {
|
||||||
|
fieldIsEmptyFlags[i] =
|
||||||
|
controllers[i].text.isEmpty;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
decoration: standardInputDecoration(
|
||||||
|
"Enter ${participantsWithoutMe[i]}'s preprocess",
|
||||||
|
focusNodes[i],
|
||||||
|
context,
|
||||||
|
).copyWith(
|
||||||
|
contentPadding: const EdgeInsets.only(
|
||||||
|
left: 16,
|
||||||
|
top: 6,
|
||||||
|
bottom: 8,
|
||||||
|
right: 5,
|
||||||
|
),
|
||||||
|
suffixIcon: Padding(
|
||||||
|
padding: fieldIsEmptyFlags[i]
|
||||||
|
? const EdgeInsets.only(right: 8)
|
||||||
|
: const EdgeInsets.only(right: 0),
|
||||||
|
child: UnconstrainedBox(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
!fieldIsEmptyFlags[i]
|
||||||
|
? TextFieldIconButton(
|
||||||
|
semanticsLabel:
|
||||||
|
"Clear Button. Clears The Preprocess Field Input.",
|
||||||
|
key: Key(
|
||||||
|
"frostPreprocessesClearButtonKey_$i",
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
controllers[i].text = "";
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
fieldIsEmptyFlags[i] = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: const XIcon(),
|
||||||
|
)
|
||||||
|
: TextFieldIconButton(
|
||||||
|
semanticsLabel:
|
||||||
|
"Paste Button. Pastes From Clipboard To Preprocess Field Input.",
|
||||||
|
key: Key(
|
||||||
|
"frostPreprocessesPasteButtonKey_$i",
|
||||||
|
),
|
||||||
|
onTap: () async {
|
||||||
|
final ClipboardData? data =
|
||||||
|
await Clipboard.getData(
|
||||||
|
Clipboard.kTextPlain);
|
||||||
|
if (data?.text != null &&
|
||||||
|
data!.text!.isNotEmpty) {
|
||||||
|
controllers[i].text =
|
||||||
|
data.text!.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
fieldIsEmptyFlags[i] =
|
||||||
|
controllers[i].text.isEmpty;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: fieldIsEmptyFlags[i]
|
||||||
|
? const ClipboardIcon()
|
||||||
|
: const XIcon(),
|
||||||
|
),
|
||||||
|
if (fieldIsEmptyFlags[i])
|
||||||
|
TextFieldIconButton(
|
||||||
|
semanticsLabel:
|
||||||
|
"Scan QR Button. Opens Camera For Scanning QR Code.",
|
||||||
|
key: Key(
|
||||||
|
"frostPreprocessesScanQrButtonKey_$i",
|
||||||
|
),
|
||||||
|
onTap: () async {
|
||||||
|
try {
|
||||||
|
if (FocusScope.of(context)
|
||||||
|
.hasFocus) {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
await Future<void>.delayed(
|
||||||
|
const Duration(
|
||||||
|
milliseconds: 75));
|
||||||
|
}
|
||||||
|
|
||||||
|
final qrResult =
|
||||||
|
await BarcodeScanner.scan();
|
||||||
|
|
||||||
|
controllers[i].text =
|
||||||
|
qrResult.rawContent;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
fieldIsEmptyFlags[i] =
|
||||||
|
controllers[i].text.isEmpty;
|
||||||
|
});
|
||||||
|
} on PlatformException catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Failed to get camera permissions while trying to scan qr code: $e\n$s",
|
||||||
|
level: LogLevel.Warning,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const QrCodeIcon(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (!Util.isDesktop) const Spacer(),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
PrimaryButton(
|
||||||
|
label: "Continue signing",
|
||||||
|
enabled: hasEnoughPreprocesses(),
|
||||||
|
onPressed: () async {
|
||||||
|
// collect Preprocess strings (not including my own)
|
||||||
|
final preprocesses = controllers.map((e) => e.text).toList();
|
||||||
|
|
||||||
|
// collect participants who are involved in this transaction
|
||||||
|
final List<String> requiredParticipantsUnordered = [];
|
||||||
|
for (int i = 0; i < participantsWithoutMe.length; i++) {
|
||||||
|
if (preprocesses[i].isNotEmpty) {
|
||||||
|
requiredParticipantsUnordered.add(participantsWithoutMe[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ref.read(pFrostSelectParticipantsUnordered.notifier).state =
|
||||||
|
requiredParticipantsUnordered;
|
||||||
|
|
||||||
|
// insert an empty string at my index
|
||||||
|
preprocesses.insert(myIndex, "");
|
||||||
|
|
||||||
|
try {
|
||||||
|
ref.read(pFrostContinueSignData.notifier).state =
|
||||||
|
Frost.continueSigning(
|
||||||
|
machinePtr:
|
||||||
|
ref.read(pFrostAttemptSignData.state).state!.machinePtr,
|
||||||
|
preprocesses: preprocesses,
|
||||||
|
);
|
||||||
|
|
||||||
|
ref.read(pFrostCreateCurrentStep.state).state = 3;
|
||||||
|
await Navigator.of(context).pushNamed(
|
||||||
|
ref
|
||||||
|
.read(pFrostScaffoldArgs)!
|
||||||
|
.stepRoutes[ref.read(pFrostCreateCurrentStep) - 1]
|
||||||
|
.routeName,
|
||||||
|
);
|
||||||
|
|
||||||
|
// await Navigator.of(context).pushNamed(
|
||||||
|
// FrostContinueSignView.routeName,
|
||||||
|
// arguments: widget.walletId,
|
||||||
|
// );
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"$e\n$s",
|
||||||
|
level: LogLevel.Fatal,
|
||||||
|
);
|
||||||
|
|
||||||
|
return await showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => StackOkDialog(
|
||||||
|
title: "Failed to continue signing",
|
||||||
|
desktopPopRootNavigator: Util.isDesktop,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
345
lib/pages/send_view/frost_ms/send_steps/frost_send_step_3.dart
Normal file
345
lib/pages/send_view/frost_ms/send_steps/frost_send_step_3.dart
Normal file
|
@ -0,0 +1,345 @@
|
||||||
|
import 'package:barcode_scan2/barcode_scan2.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
|
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||||
|
import 'package:stackwallet/services/frost.dart';
|
||||||
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
|
import 'package:stackwallet/utilities/constants.dart';
|
||||||
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
|
import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
||||||
|
import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/detail_item.dart';
|
||||||
|
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
|
||||||
|
import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
|
||||||
|
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
||||||
|
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||||
|
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||||
|
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
||||||
|
|
||||||
|
class FrostSendStep3 extends ConsumerStatefulWidget {
|
||||||
|
const FrostSendStep3({super.key});
|
||||||
|
|
||||||
|
static const String routeName = "/FrostSendStep3";
|
||||||
|
static const String title = "Shares";
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<FrostSendStep3> createState() => _FrostSendStep3State();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FrostSendStep3State extends ConsumerState<FrostSendStep3> {
|
||||||
|
final List<TextEditingController> controllers = [];
|
||||||
|
final List<FocusNode> focusNodes = [];
|
||||||
|
|
||||||
|
late final String myName;
|
||||||
|
late final List<String> participantsWithoutMe;
|
||||||
|
late final List<String> participantsAll;
|
||||||
|
late final String myShare;
|
||||||
|
late final int myIndex;
|
||||||
|
|
||||||
|
final List<bool> fieldIsEmptyFlags = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
final wallet = ref.read(pWallets).getWallet(
|
||||||
|
ref.read(pFrostScaffoldArgs)!.walletId!,
|
||||||
|
) as BitcoinFrostWallet;
|
||||||
|
|
||||||
|
final frostInfo = wallet.frostInfo;
|
||||||
|
|
||||||
|
myName = frostInfo.myName;
|
||||||
|
participantsAll = frostInfo.participants;
|
||||||
|
myIndex = frostInfo.participants.indexOf(frostInfo.myName);
|
||||||
|
myShare = ref.read(pFrostContinueSignData.state).state!.share;
|
||||||
|
|
||||||
|
participantsWithoutMe = frostInfo.participants
|
||||||
|
.toSet()
|
||||||
|
.intersection(
|
||||||
|
ref.read(pFrostSelectParticipantsUnordered.state).state!.toSet())
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
participantsWithoutMe.remove(myName);
|
||||||
|
|
||||||
|
for (int i = 0; i < participantsWithoutMe.length; i++) {
|
||||||
|
controllers.add(TextEditingController());
|
||||||
|
focusNodes.add(FocusNode());
|
||||||
|
fieldIsEmptyFlags.add(true);
|
||||||
|
}
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
for (int i = 0; i < controllers.length; i++) {
|
||||||
|
controllers[i].dispose();
|
||||||
|
}
|
||||||
|
for (int i = 0; i < focusNodes.length; i++) {
|
||||||
|
focusNodes[i].dispose();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 220,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
QrImageView(
|
||||||
|
data: myShare,
|
||||||
|
size: 220,
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).extension<StackColors>()!.background,
|
||||||
|
foregroundColor: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.accentColorDark,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
DetailItem(
|
||||||
|
title: "My name",
|
||||||
|
detail: myName,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
DetailItem(
|
||||||
|
title: "My shares",
|
||||||
|
detail: myShare,
|
||||||
|
button: Util.isDesktop
|
||||||
|
? IconCopyButton(
|
||||||
|
data: myShare,
|
||||||
|
)
|
||||||
|
: SimpleCopyButton(
|
||||||
|
data: myShare,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
for (int i = 0; i < participantsWithoutMe.length; i++)
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
Constants.size.circularBorderRadius,
|
||||||
|
),
|
||||||
|
child: TextField(
|
||||||
|
key: Key("frostSharesTextFieldKey_$i"),
|
||||||
|
controller: controllers[i],
|
||||||
|
focusNode: focusNodes[i],
|
||||||
|
readOnly: false,
|
||||||
|
autocorrect: false,
|
||||||
|
enableSuggestions: false,
|
||||||
|
style: STextStyles.field(context),
|
||||||
|
decoration: standardInputDecoration(
|
||||||
|
"Enter ${participantsWithoutMe[i]}'s share",
|
||||||
|
focusNodes[i],
|
||||||
|
context,
|
||||||
|
).copyWith(
|
||||||
|
contentPadding: const EdgeInsets.only(
|
||||||
|
left: 16,
|
||||||
|
top: 6,
|
||||||
|
bottom: 8,
|
||||||
|
right: 5,
|
||||||
|
),
|
||||||
|
suffixIcon: Padding(
|
||||||
|
padding: fieldIsEmptyFlags[i]
|
||||||
|
? const EdgeInsets.only(right: 8)
|
||||||
|
: const EdgeInsets.only(right: 0),
|
||||||
|
child: UnconstrainedBox(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
!fieldIsEmptyFlags[i]
|
||||||
|
? TextFieldIconButton(
|
||||||
|
semanticsLabel:
|
||||||
|
"Clear Button. Clears "
|
||||||
|
"The Share Field Input.",
|
||||||
|
key: Key(
|
||||||
|
"frostSharesClearButtonKey_$i",
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
controllers[i].text = "";
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
fieldIsEmptyFlags[i] = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: const XIcon(),
|
||||||
|
)
|
||||||
|
: TextFieldIconButton(
|
||||||
|
semanticsLabel:
|
||||||
|
"Paste Button. Pastes From "
|
||||||
|
"Clipboard To Share Field Input.",
|
||||||
|
key: Key(
|
||||||
|
"frostSharesPasteButtonKey_$i"),
|
||||||
|
onTap: () async {
|
||||||
|
final ClipboardData? data =
|
||||||
|
await Clipboard.getData(
|
||||||
|
Clipboard.kTextPlain);
|
||||||
|
if (data?.text != null &&
|
||||||
|
data!.text!.isNotEmpty) {
|
||||||
|
controllers[i].text =
|
||||||
|
data.text!.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
fieldIsEmptyFlags[i] =
|
||||||
|
controllers[i].text.isEmpty;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: fieldIsEmptyFlags[i]
|
||||||
|
? const ClipboardIcon()
|
||||||
|
: const XIcon(),
|
||||||
|
),
|
||||||
|
if (fieldIsEmptyFlags[i])
|
||||||
|
TextFieldIconButton(
|
||||||
|
semanticsLabel:
|
||||||
|
"Scan QR Button. Opens Camera "
|
||||||
|
"For Scanning QR Code.",
|
||||||
|
key: Key(
|
||||||
|
"frostSharesScanQrButtonKey_$i",
|
||||||
|
),
|
||||||
|
onTap: () async {
|
||||||
|
try {
|
||||||
|
if (FocusScope.of(context)
|
||||||
|
.hasFocus) {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
await Future<void>.delayed(
|
||||||
|
const Duration(
|
||||||
|
milliseconds: 75));
|
||||||
|
}
|
||||||
|
|
||||||
|
final qrResult =
|
||||||
|
await BarcodeScanner.scan();
|
||||||
|
|
||||||
|
controllers[i].text =
|
||||||
|
qrResult.rawContent;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
fieldIsEmptyFlags[i] =
|
||||||
|
controllers[i].text.isEmpty;
|
||||||
|
});
|
||||||
|
} on PlatformException catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Failed to get camera permissions "
|
||||||
|
"while trying to scan qr code: $e\n$s",
|
||||||
|
level: LogLevel.Warning,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const QrCodeIcon(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (!Util.isDesktop) const Spacer(),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
PrimaryButton(
|
||||||
|
label: "Complete signing",
|
||||||
|
onPressed: () async {
|
||||||
|
// check for empty shares
|
||||||
|
if (controllers
|
||||||
|
.map((e) => e.text.isEmpty)
|
||||||
|
.reduce((value, element) => value |= element)) {
|
||||||
|
return await showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => StackOkDialog(
|
||||||
|
title: "Missing Shares",
|
||||||
|
desktopPopRootNavigator: Util.isDesktop,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect Share strings
|
||||||
|
final sharesCollected = controllers.map((e) => e.text).toList();
|
||||||
|
|
||||||
|
final List<String> shares = [];
|
||||||
|
for (final participant in participantsAll) {
|
||||||
|
if (participantsWithoutMe.contains(participant)) {
|
||||||
|
shares.add(sharesCollected[
|
||||||
|
participantsWithoutMe.indexOf(participant)]);
|
||||||
|
} else {
|
||||||
|
shares.add("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final rawTx = Frost.completeSigning(
|
||||||
|
machinePtr:
|
||||||
|
ref.read(pFrostContinueSignData.state).state!.machinePtr,
|
||||||
|
shares: shares,
|
||||||
|
);
|
||||||
|
|
||||||
|
ref.read(pFrostTxData.state).state =
|
||||||
|
ref.read(pFrostTxData.state).state!.copyWith(
|
||||||
|
raw: rawTx,
|
||||||
|
);
|
||||||
|
|
||||||
|
ref.read(pFrostCreateCurrentStep.state).state = 4;
|
||||||
|
await Navigator.of(context).pushNamed(
|
||||||
|
ref
|
||||||
|
.read(pFrostScaffoldArgs)!
|
||||||
|
.stepRoutes[ref.read(pFrostCreateCurrentStep) - 1]
|
||||||
|
.routeName,
|
||||||
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"$e\n$s",
|
||||||
|
level: LogLevel.Fatal,
|
||||||
|
);
|
||||||
|
|
||||||
|
return await showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => StackOkDialog(
|
||||||
|
title: "Failed to complete signing process",
|
||||||
|
desktopPopRootNavigator: Util.isDesktop,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
144
lib/pages/send_view/frost_ms/send_steps/frost_send_step_4.dart
Normal file
144
lib/pages/send_view/frost_ms/send_steps/frost_send_step_4.dart
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
|
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
||||||
|
import 'package:stackwallet/pages_desktop_specific/my_stack_view/my_stack_view.dart';
|
||||||
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
|
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||||
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
import 'package:stackwallet/utilities/show_loading.dart';
|
||||||
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
|
import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/detail_item.dart';
|
||||||
|
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||||
|
|
||||||
|
class FrostSendStep4 extends ConsumerStatefulWidget {
|
||||||
|
const FrostSendStep4({super.key});
|
||||||
|
|
||||||
|
static const String routeName = "/FrostSendStep4";
|
||||||
|
static const String title = "Preview transaction";
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<FrostSendStep4> createState() => _FrostSendStep4State();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FrostSendStep4State extends ConsumerState<FrostSendStep4> {
|
||||||
|
bool _broadcastLock = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 220,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
QrImageView(
|
||||||
|
data: ref.watch(pFrostTxData.state).state!.raw!,
|
||||||
|
size: 220,
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).extension<StackColors>()!.background,
|
||||||
|
foregroundColor: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.accentColorDark,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
DetailItem(
|
||||||
|
title: "Raw transaction hex",
|
||||||
|
detail: ref.watch(pFrostTxData.state).state!.raw!,
|
||||||
|
button: Util.isDesktop
|
||||||
|
? IconCopyButton(
|
||||||
|
data: ref.watch(pFrostTxData.state).state!.raw!,
|
||||||
|
)
|
||||||
|
: SimpleCopyButton(
|
||||||
|
data: ref.watch(pFrostTxData.state).state!.raw!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
if (!Util.isDesktop) const Spacer(),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
PrimaryButton(
|
||||||
|
label: "Broadcast Transaction",
|
||||||
|
onPressed: () async {
|
||||||
|
if (_broadcastLock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_broadcastLock = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Exception? ex;
|
||||||
|
final txData = await showLoading(
|
||||||
|
whileFuture: ref
|
||||||
|
.read(pWallets)
|
||||||
|
.getWallet(
|
||||||
|
ref.read(pFrostScaffoldArgs)!.walletId!,
|
||||||
|
)
|
||||||
|
.confirmSend(
|
||||||
|
txData: ref.read(pFrostTxData.state).state!,
|
||||||
|
),
|
||||||
|
context: context,
|
||||||
|
message: "Broadcasting transaction to network",
|
||||||
|
isDesktop: Util.isDesktop,
|
||||||
|
onException: (e) {
|
||||||
|
ex = e;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ex != null) {
|
||||||
|
throw ex!;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
if (txData != null) {
|
||||||
|
ref.read(pFrostTxData.state).state = txData;
|
||||||
|
Navigator.of(context).popUntil(
|
||||||
|
ModalRoute.withName(
|
||||||
|
Util.isDesktop
|
||||||
|
? MyStackView.routeName
|
||||||
|
: WalletView.routeName,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"$e\n$s",
|
||||||
|
level: LogLevel.Fatal,
|
||||||
|
);
|
||||||
|
|
||||||
|
return await showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => StackOkDialog(
|
||||||
|
title: "Broadcast error",
|
||||||
|
message: e.toString(),
|
||||||
|
desktopPopRootNavigator: Util.isDesktop,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
_broadcastLock = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,8 +10,7 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/frost_scaffold.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
|
||||||
import 'package:stackwallet/pages/settings_views/sub_widgets/settings_list_button.dart';
|
import 'package:stackwallet/pages/settings_views/sub_widgets/settings_list_button.dart';
|
||||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/frost_participants_view.dart';
|
import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/frost_participants_view.dart';
|
||||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/initiate_resharing_view.dart';
|
import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/initiate_resharing_view.dart';
|
||||||
|
@ -30,6 +29,7 @@ import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||||
|
import 'package:stackwallet/widgets/frost_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
|
|
||||||
class FrostMSWalletOptionsView extends ConsumerWidget {
|
class FrostMSWalletOptionsView extends ConsumerWidget {
|
||||||
|
|
|
@ -4,8 +4,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:frostdart/frostdart.dart';
|
import 'package:frostdart/frostdart.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/frost_scaffold.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
|
||||||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
|
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
|
||||||
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
||||||
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
|
@ -24,6 +23,7 @@ import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/frost_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
|
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
|
||||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||||
import 'package:stackwallet/pages/buy_view/buy_in_wallet_view.dart';
|
import 'package:stackwallet/pages/buy_view/buy_in_wallet_view.dart';
|
||||||
|
@ -29,7 +30,6 @@ import 'package:stackwallet/pages/ordinals/ordinals_view.dart';
|
||||||
import 'package:stackwallet/pages/paynym/paynym_claim_view.dart';
|
import 'package:stackwallet/pages/paynym/paynym_claim_view.dart';
|
||||||
import 'package:stackwallet/pages/paynym/paynym_home_view.dart';
|
import 'package:stackwallet/pages/paynym/paynym_home_view.dart';
|
||||||
import 'package:stackwallet/pages/receive_view/receive_view.dart';
|
import 'package:stackwallet/pages/receive_view/receive_view.dart';
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/frost_import_sign_config_view.dart';
|
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/frost_send_view.dart';
|
import 'package:stackwallet/pages/send_view/frost_ms/frost_send_view.dart';
|
||||||
import 'package:stackwallet/pages/send_view/send_view.dart';
|
import 'package:stackwallet/pages/send_view/send_view.dart';
|
||||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart';
|
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart';
|
||||||
|
@ -79,6 +79,7 @@ import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||||
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/frost_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/loading_indicator.dart';
|
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||||
import 'package:stackwallet/widgets/small_tor_icon.dart';
|
import 'package:stackwallet/widgets/small_tor_icon.dart';
|
||||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||||
|
@ -359,9 +360,24 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFrostSignPressed(BuildContext context) async {
|
Future<void> _onFrostSignPressed(BuildContext context) async {
|
||||||
|
final wallet = ref.read(pWallets).getWallet(walletId) as BitcoinFrostWallet;
|
||||||
|
ref.read(pFrostScaffoldArgs.state).state = (
|
||||||
|
info: (
|
||||||
|
walletName: wallet.info.name,
|
||||||
|
frostCurrency: wallet.cryptoCurrency,
|
||||||
|
),
|
||||||
|
walletId: walletId,
|
||||||
|
stepRoutes: FrostRouteGenerator.signFrostTxStepRoutes,
|
||||||
|
onSuccess: () {
|
||||||
|
// successful completion of steps
|
||||||
|
// TODO ?
|
||||||
|
|
||||||
|
ref.read(pFrostScaffoldArgs.state).state = null;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
await Navigator.of(context).pushNamed(
|
await Navigator.of(context).pushNamed(
|
||||||
FrostImportSignConfigView.routeName,
|
FrostStepScaffold.routeName,
|
||||||
arguments: walletId,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/frost_import_sign_config_view.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/frost_send_view.dart';
|
import 'package:stackwallet/pages/send_view/frost_ms/frost_send_view.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart';
|
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart';
|
||||||
|
@ -21,14 +21,15 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
||||||
import 'package:stackwallet/widgets/custom_tab_view.dart';
|
import 'package:stackwallet/widgets/custom_tab_view.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/frost_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
|
|
||||||
class MyWallet extends ConsumerStatefulWidget {
|
class MyWallet extends ConsumerStatefulWidget {
|
||||||
const MyWallet({
|
const MyWallet({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.walletId,
|
required this.walletId,
|
||||||
this.contractAddress,
|
this.contractAddress,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final String walletId;
|
final String walletId;
|
||||||
final String? contractAddress;
|
final String? contractAddress;
|
||||||
|
@ -85,10 +86,32 @@ class _MyWalletState extends ConsumerState<MyWallet> {
|
||||||
width: 200,
|
width: 200,
|
||||||
buttonHeight: ButtonHeight.l,
|
buttonHeight: ButtonHeight.l,
|
||||||
label: "Import sign config",
|
label: "Import sign config",
|
||||||
onPressed: () {
|
onPressed: () async {
|
||||||
Navigator.of(context).pushNamed(
|
final wallet = ref
|
||||||
FrostImportSignConfigView.routeName,
|
.read(pWallets)
|
||||||
arguments: widget.walletId,
|
.getWallet(widget.walletId)
|
||||||
|
as BitcoinFrostWallet;
|
||||||
|
ref.read(pFrostScaffoldArgs.state).state =
|
||||||
|
(
|
||||||
|
info: (
|
||||||
|
walletName: wallet.info.name,
|
||||||
|
frostCurrency: wallet.cryptoCurrency,
|
||||||
|
),
|
||||||
|
walletId: widget.walletId,
|
||||||
|
stepRoutes: FrostRouteGenerator
|
||||||
|
.signFrostTxStepRoutes,
|
||||||
|
onSuccess: () {
|
||||||
|
// successful completion of steps
|
||||||
|
// TODO ?
|
||||||
|
|
||||||
|
ref
|
||||||
|
.read(pFrostScaffoldArgs.state)
|
||||||
|
.state = null;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await Navigator.of(context).pushNamed(
|
||||||
|
FrostStepScaffold.routeName,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -26,7 +26,6 @@ import 'package:stackwallet/pages/add_wallet_views/add_token_view/add_custom_tok
|
||||||
import 'package:stackwallet/pages/add_wallet_views/add_token_view/edit_wallet_tokens_view.dart';
|
import 'package:stackwallet/pages/add_wallet_views/add_token_view/edit_wallet_tokens_view.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart';
|
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart';
|
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/frost_scaffold.dart';
|
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart';
|
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/select_new_frost_import_type_view.dart';
|
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/select_new_frost_import_type_view.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart';
|
import 'package:stackwallet/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart';
|
||||||
|
@ -80,9 +79,6 @@ import 'package:stackwallet/pages/receive_view/addresses/wallet_addresses_view.d
|
||||||
import 'package:stackwallet/pages/receive_view/generate_receiving_uri_qr_code_view.dart';
|
import 'package:stackwallet/pages/receive_view/generate_receiving_uri_qr_code_view.dart';
|
||||||
import 'package:stackwallet/pages/receive_view/receive_view.dart';
|
import 'package:stackwallet/pages/receive_view/receive_view.dart';
|
||||||
import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
|
import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart';
|
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/frost_create_sign_config_view.dart';
|
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/frost_import_sign_config_view.dart';
|
|
||||||
import 'package:stackwallet/pages/send_view/frost_ms/frost_send_view.dart';
|
import 'package:stackwallet/pages/send_view/frost_ms/frost_send_view.dart';
|
||||||
import 'package:stackwallet/pages/send_view/send_view.dart';
|
import 'package:stackwallet/pages/send_view/send_view.dart';
|
||||||
import 'package:stackwallet/pages/send_view/token_send_view.dart';
|
import 'package:stackwallet/pages/send_view/token_send_view.dart';
|
||||||
|
@ -197,6 +193,7 @@ import 'package:stackwallet/wallets/crypto_currency/intermediate/frost_currency.
|
||||||
import 'package:stackwallet/wallets/models/tx_data.dart';
|
import 'package:stackwallet/wallets/models/tx_data.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/wallet.dart';
|
import 'package:stackwallet/wallets/wallet/wallet.dart';
|
||||||
import 'package:stackwallet/widgets/choose_coin_view.dart';
|
import 'package:stackwallet/widgets/choose_coin_view.dart';
|
||||||
|
import 'package:stackwallet/widgets/frost_scaffold.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -574,48 +571,6 @@ class RouteGenerator {
|
||||||
}
|
}
|
||||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||||
|
|
||||||
case FrostImportSignConfigView.routeName:
|
|
||||||
if (args is String) {
|
|
||||||
return getRoute(
|
|
||||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
|
||||||
builder: (_) => FrostImportSignConfigView(
|
|
||||||
walletId: args,
|
|
||||||
),
|
|
||||||
settings: RouteSettings(
|
|
||||||
name: settings.name,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
|
||||||
|
|
||||||
case FrostCreateSignConfigView.routeName:
|
|
||||||
if (args is String) {
|
|
||||||
return getRoute(
|
|
||||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
|
||||||
builder: (_) => FrostCreateSignConfigView(
|
|
||||||
walletId: args,
|
|
||||||
),
|
|
||||||
settings: RouteSettings(
|
|
||||||
name: settings.name,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
|
||||||
|
|
||||||
case FrostAttemptSignConfigView.routeName:
|
|
||||||
if (args is String) {
|
|
||||||
return getRoute(
|
|
||||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
|
||||||
builder: (_) => FrostAttemptSignConfigView(
|
|
||||||
walletId: args,
|
|
||||||
),
|
|
||||||
settings: RouteSettings(
|
|
||||||
name: settings.name,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
|
||||||
|
|
||||||
// case MonkeyLoadedView.routeName:
|
// case MonkeyLoadedView.routeName:
|
||||||
// if (args is Tuple2<String, ChangeNotifierProvider<Manager>>) {
|
// if (args is Tuple2<String, ChangeNotifierProvider<Manager>>) {
|
||||||
// return getRoute(
|
// return getRoute(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
|
import 'package:stackwallet/frost_route_generator.dart';
|
||||||
import 'package:stackwallet/themes/stack_colors.dart';
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
import 'package:stackwallet/utilities/util.dart';
|
import 'package:stackwallet/utilities/util.dart';
|
Loading…
Reference in a new issue