diff --git a/lib/pages_desktop_specific/cashfusion/desktop_cashfusion_view.dart b/lib/pages_desktop_specific/cashfusion/desktop_cashfusion_view.dart index 9bb9f725b..e96cfa032 100644 --- a/lib/pages_desktop_specific/cashfusion/desktop_cashfusion_view.dart +++ b/lib/pages_desktop_specific/cashfusion/desktop_cashfusion_view.dart @@ -8,11 +8,24 @@ * */ +import 'dart:async'; + +import 'package:dropdown_button2/dropdown_button2.dart'; +import 'package:event_bus/event_bus.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_native_splash/cli_commands.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/pages_desktop_specific/desktop_menu.dart'; +import 'package:stackwallet/pages_desktop_specific/settings/settings_menu.dart'; +import 'package:stackwallet/providers/desktop/current_desktop_menu_item.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/providers/ui/check_box_state_provider.dart'; +import 'package:stackwallet/services/event_bus/events/global/tor_connection_status_changed_event.dart'; +import 'package:stackwallet/services/event_bus/global_event_bus.dart'; +import 'package:stackwallet/services/mixins/fusion_wallet_interface.dart'; +import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/services/mixins/fusion_wallet_interface.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; @@ -20,11 +33,18 @@ import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.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_dialog.dart'; +import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; +enum FusionRounds { + Continuous, + Custom; +} + class DesktopCashFusionView extends ConsumerStatefulWidget { const DesktopCashFusionView({ super.key, @@ -52,10 +72,70 @@ class _DesktopCashFusion extends ConsumerState { bool _trusted = false; int? port; late bool enableSSLCheckbox; - late final bool enableAuthFields; - void _updateState() {} + FusionRounds _roundType = FusionRounds.Continuous; + + /// The global event bus. + late final EventBus eventBus; + + /// The subscription to the TorConnectionStatusChangedEvent. + late final StreamSubscription + _torConnectionStatusSubscription; + + /// The current status of the Tor connection. + late TorConnectionStatus _torConnectionStatus = + TorConnectionStatus.disconnected; + + /// Build the connect/disconnect button + /// pushes to Tor settings + Widget _buildConnectButton(TorConnectionStatus status) { + switch (status) { + case TorConnectionStatus.disconnected: + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () { + ref.read(currentDesktopMenuItemProvider.state).state = + DesktopMenuItemId.settings; + ref.watch(selectedSettingsMenuItemStateProvider.state).state = 4; + }, + child: Text( + "Connect", + style: STextStyles.richLink(context).copyWith( + fontSize: 14, + ), + ), + ), + ); + case TorConnectionStatus.connecting: + return AbsorbPointer( + child: Text( + "Connecting", + style: STextStyles.richLink(context).copyWith( + fontSize: 14, + ), + ), + ); + case TorConnectionStatus.connected: + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () { + ref.read(currentDesktopMenuItemProvider.state).state = + DesktopMenuItemId.settings; + ref.watch(selectedSettingsMenuItemStateProvider.state).state = 4; + }, + child: Text( + "Disconnect", + style: STextStyles.richLink(context).copyWith( + fontSize: 14, + ), + ), + ), + ); + } + } @override void initState() { @@ -67,6 +147,23 @@ class _DesktopCashFusion extends ConsumerState { enableSSLCheckbox = true; + // Initialize the global event bus. + eventBus = GlobalEventBus.instance; + + // Initialize the TorConnectionStatus. + _torConnectionStatus = ref.read(pTorService).status; + + // Subscribe to the TorConnectionStatusChangedEvent. + _torConnectionStatusSubscription = + eventBus.on().listen( + (event) async { + // Rebuild the widget. + setState(() { + _torConnectionStatus = event.newStatus; + }); + }, + ); + super.initState(); } @@ -155,6 +252,67 @@ class _DesktopCashFusion extends ConsumerState { style: STextStyles.richLink(context).copyWith( fontSize: 16, ), + recognizer: TapGestureRecognizer() + ..onTap = () { + showDialog( + context: context, + useSafeArea: false, + barrierDismissible: true, + builder: (context) { + return DesktopDialog( + maxWidth: 580, + maxHeight: double.infinity, + child: Padding( + padding: const EdgeInsets.only( + top: 10, + left: 20, + bottom: 20, + right: 10, + ), + child: Column( + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( + "What is CashFusion?", + style: STextStyles.desktopH2( + context), + ), + DesktopDialogCloseButton( + onPressedOverride: () => + Navigator.of(context) + .pop(true), + ), + ], + ), + const SizedBox( + height: 16, + ), + Text( + "A fully decentralized privacy protocol that allows " + "anyone to create multi-party transactions with other " + "network participants. This process obscures your real " + "spending and makes it difficult for chain-analysis " + "companies to track your coins.", + style: + STextStyles.desktopTextMedium( + context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark3, + ), + ), + ], + ), + ), + ); + }, + ); + }, ), ), ], @@ -313,60 +471,58 @@ class _DesktopCashFusion extends ConsumerState { const SizedBox( height: 10, ), - Stack( - children: [ - TextField( - autocorrect: false, - enableSuggestions: false, - readOnly: true, - textInputAction: TextInputAction.none, - style: STextStyles.desktopTextFieldLabel(context) - .copyWith( - fontSize: 16, - ), - decoration: const InputDecoration( - contentPadding: EdgeInsets.symmetric( - vertical: 18, - horizontal: 16, - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12, - ), - child: RawMaterialButton( - splashColor: Theme.of(context) - .extension()! - .highlight, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, + DropdownButtonHideUnderline( + child: DropdownButton2( + value: _roundType, + items: [ + ...FusionRounds.values.map( + (e) => DropdownMenuItem( + value: e, + child: Text( + e.name, + style: + STextStyles.desktopTextMedium(context), ), ), - onPressed: () {}, - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - "Continuous", - style: - STextStyles.itemSubtitle12(context), - ), - SvgPicture.asset( - Assets.svg.chevronDown, - width: 8, - height: 4, - color: Theme.of(context) - .extension()! - .textSubtitle2, - ), - ], + ), + ], + onChanged: (value) { + if (value is FusionRounds) { + setState(() { + _roundType = value; + }); + } + }, + isExpanded: true, + iconStyleData: IconStyleData( + icon: SvgPicture.asset( + Assets.svg.chevronDown, + width: 12, + height: 6, + color: Theme.of(context) + .extension()! + .textFieldActiveSearchIconRight, + ), + ), + dropdownStyleData: DropdownStyleData( + offset: const Offset(0, -10), + elevation: 0, + decoration: BoxDecoration( + color: Theme.of(context) + .extension()! + .textFieldActiveBG, + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, ), ), ), - ], + menuItemStyleData: const MenuItemStyleData( + padding: EdgeInsets.symmetric( + horizontal: 16, + vertical: 8, + ), + ), + ), ), const SizedBox( height: 20, @@ -379,12 +535,7 @@ class _DesktopCashFusion extends ConsumerState { style: STextStyles.desktopTextExtraExtraSmall( context), ), - Text( - "Disconnect", - style: STextStyles.richLink(context).copyWith( - fontSize: 14, - ), - ), + _buildConnectButton(_torConnectionStatus), ], ), const SizedBox( @@ -394,8 +545,32 @@ class _DesktopCashFusion extends ConsumerState { borderColor: Theme.of(context) .extension()! .shadow, - child: const Row( - children: [], + child: Row( + children: [ + SvgPicture.asset( + Assets.svg.circleTor, + width: 48, + height: 48, + ), + const SizedBox( + width: 10, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Tor Network", + style: STextStyles.itemSubtitle12(context), + ), + const SizedBox( + height: 4, + ), + Text(_torConnectionStatus.name.capitalize(), + style: STextStyles + .desktopTextExtraExtraSmall(context)), + ], + ) + ], ), ), const SizedBox( diff --git a/lib/pages_desktop_specific/settings/settings_menu/tor_settings/tor_settings.dart b/lib/pages_desktop_specific/settings/settings_menu/tor_settings/tor_settings.dart index ff507b79e..28b585c75 100644 --- a/lib/pages_desktop_specific/settings/settings_menu/tor_settings/tor_settings.dart +++ b/lib/pages_desktop_specific/settings/settings_menu/tor_settings/tor_settings.dart @@ -215,40 +215,37 @@ class _TorSettingsState extends ConsumerState { return DesktopDialog( maxWidth: 580, maxHeight: double.infinity, - child: Column( - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Padding( - padding: - const EdgeInsets.only( - left: 32, - ), - child: Text( + child: Padding( + padding: const EdgeInsets.only( + top: 10, + left: 20, + bottom: 20, + right: 10, + ), + child: Column( + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( "What is Tor?", style: STextStyles.desktopH2( context), ), - ), - DesktopDialogCloseButton( - onPressedOverride: () => - Navigator.of(context) - .pop(true), - ), - ], - ), - Padding( - padding: const EdgeInsets.only( - top: 12, - left: 32, - bottom: 32, - right: 32, + DesktopDialogCloseButton( + onPressedOverride: () => + Navigator.of(context) + .pop(true), + ), + ], ), - child: Text( + const SizedBox( + height: 16, + ), + Text( "Short for \"The Onion Router\", is an open-source software that enables internet communication" " to remain anonymous by routing internet traffic through a series of layered nodes," " to obscure the origin and destination of data.", @@ -261,8 +258,8 @@ class _TorSettingsState extends ConsumerState { .textDark3, ), ), - ), - ], + ], + ), ), ); }, @@ -287,43 +284,49 @@ class _TorSettingsState extends ConsumerState { ), Padding( padding: const EdgeInsets.all(10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Tor killswitch", - style: STextStyles.desktopTextExtraExtraSmall( - context) - .copyWith( - color: Theme.of(context) - .extension()! - .textDark), - ), - const SizedBox( - height: 8, - ), - RichText( - textAlign: TextAlign.start, - text: TextSpan( - text: "What is Tor killswitch?", - style: STextStyles.richLink(context).copyWith( - fontSize: 14, - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - showDialog( - context: context, - useSafeArea: false, - barrierDismissible: true, - builder: (context) { - return DesktopDialog( - maxWidth: 580, - maxHeight: double.infinity, + child: Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Tor killswitch", + style: STextStyles.desktopTextExtraExtraSmall( + context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark), + ), + const SizedBox( + height: 8, + ), + RichText( + textAlign: TextAlign.start, + text: TextSpan( + text: "What is Tor killswitch?", + style: STextStyles.richLink(context).copyWith( + fontSize: 14, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + showDialog( + context: context, + useSafeArea: false, + barrierDismissible: true, + builder: (context) { + return DesktopDialog( + maxWidth: 580, + maxHeight: double.infinity, + child: Padding( + padding: const EdgeInsets.only( + top: 10, + left: 20, + bottom: 20, + right: 10, + ), child: Column( children: [ Row( @@ -331,16 +334,11 @@ class _TorSettingsState extends ConsumerState { MainAxisAlignment .spaceBetween, children: [ - Padding( - padding: - const EdgeInsets.only( - left: 32, - ), - child: Text( - "What is Tor killswitch?", - style: STextStyles - .desktopH2(context), - ), + Text( + "What is Tor killswitch?", + style: + STextStyles.desktopH2( + context), ), DesktopDialogCloseButton( onPressedOverride: () => @@ -349,44 +347,36 @@ class _TorSettingsState extends ConsumerState { ), ], ), - Padding( - padding: - const EdgeInsets.only( - top: 12, - left: 32, - bottom: 32, - right: 32, - ), - child: Text( - "A security feature that protects your information from accidental exposure by" - " disconnecting your device from the Tor network if the" - " connection is disrupted or compromised.", - style: STextStyles - .desktopTextMedium( - context) - .copyWith( - color: Theme.of(context) - .extension< - StackColors>()! - .textDark3, - ), + const SizedBox( + height: 16, + ), + Text( + "A security feature that protects your information from accidental exposure by" + " disconnecting your device from the Tor network if the" + " connection is disrupted or compromised.", + style: STextStyles + .desktopTextMedium( + context) + .copyWith( + color: Theme.of(context) + .extension< + StackColors>()! + .textDark3, ), ), ], ), - ); - }, - ); - }, - ), + ), + ); + }, + ); + }, ), - ], - ), - ], - ), - Padding( - padding: const EdgeInsets.only(right: 8.0), - child: SizedBox( + ), + ], + ), + const Spacer(), + SizedBox( height: 20, width: 40, child: DraggableSwitchButton( @@ -401,13 +391,13 @@ class _TorSettingsState extends ConsumerState { }, ), ), - ), - ], + const SizedBox( + height: 10, + ), + ], + ), ), ), - const SizedBox( - height: 10, - ), ], ), ),