diff --git a/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart b/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart index 45180c842..23b7d4155 100644 --- a/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart +++ b/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart @@ -1,85 +1,347 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart'; import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/next_button.dart'; +import 'package:stackwallet/pages_desktop_specific/desktop_app_bar.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; +import 'package:stackwallet/widgets/rounded_white_container.dart'; +import 'package:stackwallet/widgets/stack_text_field.dart'; +import 'package:stackwallet/widgets/textfield_icon_button.dart'; -class AddWalletView extends StatelessWidget { +class AddWalletView extends StatefulWidget { const AddWalletView({Key? key}) : super(key: key); static const routeName = "/addWallet"; @override - Widget build(BuildContext context) { - List coins = [...Coin.values]; - coins.remove(Coin.firoTestNet); - return Scaffold( - appBar: AppBar( - leading: AppBarBackButton( - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ), - body: Container( - color: CFColors.almostWhite, - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text( - "Add wallet", - textAlign: TextAlign.center, - style: STextStyles.pageTitleH1, - ), - const SizedBox( - height: 16, - ), - Text( - "Select wallet currency", - textAlign: TextAlign.center, - style: STextStyles.subtitle, - ), - const SizedBox( - height: 16, - ), - Expanded( - child: Consumer( - builder: (_, ref, __) { - bool showTestNet = ref.watch( - prefsChangeNotifierProvider - .select((value) => value.showTestNetCoins), - ); + State createState() => _AddWalletViewState(); +} - return ListView.builder( - itemCount: showTestNet - ? coins.length - : coins.length - (kTestNetCoinCount), - itemBuilder: (ctx, index) { - return Padding( - padding: const EdgeInsets.all(4), - child: CoinSelectItem( - coin: coins[index], - ), - ); - }, - ); - }, - ), +class _AddWalletViewState extends State { + late final TextEditingController _searchFieldController; + late final FocusNode _searchFocusNode; + + String _searchTerm = ""; + + final List coins = [...Coin.values]; + + @override + void initState() { + _searchFieldController = TextEditingController(); + _searchFocusNode = FocusNode(); + coins.remove(Coin.firoTestNet); + super.initState(); + } + + @override + void dispose() { + _searchFieldController.dispose(); + _searchFocusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + debugPrint("BUILD: $runtimeType"); + + if (Platform.isLinux || Platform.isMacOS || Platform.isWindows) { + return Material( + color: CFColors.background, + child: Column( + children: [ + DesktopAppBar( + isCompactHeight: false, + leading: AppBarBackButton( + onPressed: () { + Navigator.of(context).pop(); + }, ), - const SizedBox( - height: 16, + ), + Expanded( + child: Column( + children: [ + const AddWalletText( + isDesktop: true, + ), + const SizedBox( + height: 16, + ), + Expanded( + child: SizedBox( + width: 480, + child: RoundedWhiteContainer( + radiusMultiplier: 2, + padding: const EdgeInsets.only( + left: 16, + top: 16, + right: 16, + bottom: 0, + ), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(4.0), + child: ClipRRect( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + child: TextField( + controller: _searchFieldController, + focusNode: _searchFocusNode, + onChanged: (value) { + setState(() { + _searchTerm = value; + }); + }, + style: STextStyles.desktopTextMedium.copyWith( + height: 2, + ), + decoration: standardInputDecoration( + "Search", + _searchFocusNode, + ).copyWith( + contentPadding: const EdgeInsets.symmetric( + vertical: 10, + ), + prefixIcon: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16, + // vertical: 20, + ), + child: SvgPicture.asset( + Assets.svg.search, + width: 24, + height: 24, + color: CFColors + .textFieldDefaultSearchIconLeft, + ), + ), + suffixIcon: + _searchFieldController.text.isNotEmpty + ? Padding( + padding: const EdgeInsets.only( + right: 10), + child: UnconstrainedBox( + child: Row( + children: [ + TextFieldIconButton( + child: const XIcon( + width: 24, + height: 24, + ), + onTap: () async { + setState(() { + _searchFieldController + .text = ""; + _searchTerm = ""; + }); + }, + ), + ], + ), + ), + ) + : null, + ), + ), + ), + ), + Expanded( + child: SearchableCoinList( + coins: coins, + isDesktop: true, + searchTerm: _searchTerm, + ), + ), + ], + ), + ), + ), + ), + const SizedBox( + height: 16, + ), + const SizedBox( + height: 70, + width: 480, + child: AddWalletNextButton(), + ), + const SizedBox( + height: 32, + ), + ], ), - const AddWalletNextButton(), - ], + ), + ], + ), + ); + } else { + return Scaffold( + appBar: AppBar( + leading: AppBarBackButton( + onPressed: () { + Navigator.of(context).pop(); + }, ), ), - ), + body: Container( + color: CFColors.almostWhite, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const AddWalletText( + isDesktop: false, + ), + const SizedBox( + height: 16, + ), + Expanded( + child: MobileCoinList( + coins: coins, + isDesktop: false, + ), + ), + const SizedBox( + height: 16, + ), + const AddWalletNextButton(), + ], + ), + ), + ), + ); + } + } +} + +class AddWalletText extends StatelessWidget { + const AddWalletText({Key? key, required this.isDesktop}) : super(key: key); + + final bool isDesktop; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text( + "Add wallet", + textAlign: TextAlign.center, + style: isDesktop ? STextStyles.desktopH2 : STextStyles.pageTitleH1, + ), + const SizedBox( + height: 16, + ), + Text( + "Select wallet currency", + textAlign: TextAlign.center, + style: + isDesktop ? STextStyles.desktopSubtitleH2 : STextStyles.subtitle, + ), + ], + ); + } +} + +class MobileCoinList extends StatelessWidget { + const MobileCoinList({ + Key? key, + required this.coins, + required this.isDesktop, + }) : super(key: key); + + final List coins; + final bool isDesktop; + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (_, ref, __) { + bool showTestNet = ref.watch( + prefsChangeNotifierProvider.select((value) => value.showTestNetCoins), + ); + + return ListView.builder( + itemCount: + showTestNet ? coins.length : coins.length - (kTestNetCoinCount), + itemBuilder: (ctx, index) { + return Padding( + padding: const EdgeInsets.all(4), + child: CoinSelectItem( + coin: coins[index], + ), + ); + }, + ); + }, + ); + } +} + +class SearchableCoinList extends StatelessWidget { + const SearchableCoinList({ + Key? key, + required this.coins, + required this.isDesktop, + required this.searchTerm, + }) : super(key: key); + + final List coins; + final bool isDesktop; + final String searchTerm; + + List filterCoins(String text, bool showTestNetCoins) { + final _coins = [...coins]; + if (text.isNotEmpty) { + final lowercaseTerm = text.toLowerCase(); + _coins.retainWhere((e) => + e.ticker.toLowerCase().contains(lowercaseTerm) || + e.prettyName.toLowerCase().contains(lowercaseTerm) || + e.name.toLowerCase().contains(lowercaseTerm)); + } + if (!showTestNetCoins) { + _coins.removeWhere((e) => e.name.endsWith("TestNet")); + } + // remove firo testnet regardless + _coins.remove(Coin.firoTestNet); + + return _coins; + } + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (_, ref, __) { + bool showTestNet = ref.watch( + prefsChangeNotifierProvider.select((value) => value.showTestNetCoins), + ); + + final _coins = filterCoins(searchTerm, showTestNet); + + return ListView.builder( + itemCount: _coins.length, + itemBuilder: (ctx, index) { + return Padding( + padding: const EdgeInsets.all(4), + child: CoinSelectItem( + coin: _coins[index], + ), + ); + }, + ); + }, ); } } diff --git a/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart index 8ab1a4ffe..5ff80bbc8 100644 --- a/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart +++ b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; @@ -20,40 +22,70 @@ class CoinSelectItem extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { debugPrint("BUILD: CoinSelectItem for ${coin.name}"); final selectedCoin = ref.watch(addWalletSelectedCoinStateProvider); + + final isDesktop = + Platform.isLinux || Platform.isMacOS || Platform.isWindows; + return Container( decoration: BoxDecoration( // color: selectedCoin == coin ? CFColors.selection : CFColors.white, - color: selectedCoin == coin ? CFColors.selected2 : CFColors.white, + color: selectedCoin == coin + ? CFColors.textFieldActive + : CFColors.popupBackground, borderRadius: BorderRadius.circular(Constants.size.circularBorderRadius), ), child: MaterialButton( // splashColor: CFColors.splashLight, key: Key("coinSelectItemButtonKey_${coin.name}"), - padding: const EdgeInsets.all(12), + padding: isDesktop + ? const EdgeInsets.only(left: 24) + : const EdgeInsets.all(12), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(Constants.size.circularBorderRadius), ), - child: Row( - children: [ - SvgPicture.asset( - Assets.svg.iconFor(coin: coin), - width: 26, - height: 26, - ), - const SizedBox( - width: 10, - ), - Text( - coin.prettyName, - style: STextStyles.subtitle.copyWith( - fontWeight: FontWeight.w600, - fontSize: 14, + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: isDesktop ? 70 : 0, + ), + child: Row( + children: [ + SvgPicture.asset( + Assets.svg.iconFor(coin: coin), + width: 26, + height: 26, ), - ), - ], + SizedBox( + width: isDesktop ? 12 : 10, + ), + Text( + coin.prettyName, + style: isDesktop + ? STextStyles.desktopTextMedium + : STextStyles.subtitle.copyWith( + fontWeight: FontWeight.w600, + fontSize: 14, + ), + ), + if (isDesktop && selectedCoin == coin) const Spacer(), + if (isDesktop && selectedCoin == coin) + Padding( + padding: const EdgeInsets.only( + right: 18, + ), + child: SizedBox( + width: 24, + height: 24, + child: SvgPicture.asset( + Assets.svg.check, + color: CFColors.borderNormal, + ), + ), + ), + ], + ), ), onPressed: () => ref.read(addWalletSelectedCoinStateProvider.state).state = coin, diff --git a/lib/pages_desktop_specific/home/desktop_home_view.dart b/lib/pages_desktop_specific/home/desktop_home_view.dart index eaeea75a8..c6960fb94 100644 --- a/lib/pages_desktop_specific/home/desktop_home_view.dart +++ b/lib/pages_desktop_specific/home/desktop_home_view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages_desktop_specific/home/desktop_menu.dart'; import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/my_stack_view.dart'; +import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/utilities/cfcolors.dart'; class DesktopHomeView extends ConsumerStatefulWidget { @@ -16,9 +17,13 @@ class DesktopHomeView extends ConsumerStatefulWidget { class _DesktopHomeViewState extends ConsumerState { int currentViewIndex = 0; final List contentViews = [ - const MyStackView( - key: Key("myStackViewKey"), + const Navigator( + onGenerateRoute: RouteGenerator.generateRoute, + initialRoute: MyStackView.routeName, ), + // const MyStackView( + // key: Key("myStackViewKey"), + // ), Container( color: Colors.green, ), @@ -57,7 +62,9 @@ class _DesktopHomeViewState extends ConsumerState { DesktopMenu( onSelectionChanged: onMenuSelectionChanged, ), - Expanded(child: contentViews[currentViewIndex]), + Expanded( + child: contentViews[currentViewIndex], + ), ], ), ); diff --git a/lib/pages_desktop_specific/home/my_stack_view/my_stack_view.dart b/lib/pages_desktop_specific/home/my_stack_view/my_stack_view.dart index cd0111abe..ef026cbc4 100644 --- a/lib/pages_desktop_specific/home/my_stack_view/my_stack_view.dart +++ b/lib/pages_desktop_specific/home/my_stack_view/my_stack_view.dart @@ -11,6 +11,9 @@ import 'package:stackwallet/utilities/text_styles.dart'; class MyStackView extends ConsumerStatefulWidget { const MyStackView({Key? key}) : super(key: key); + + static const String routeName = "/myStackDesktop"; + @override ConsumerState createState() => _MyStackViewState(); } diff --git a/lib/route_generator.dart b/lib/route_generator.dart index e7b6c0da8..5ceae480c 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -77,6 +77,7 @@ import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/pages/wallets_view/wallets_view.dart'; import 'package:stackwallet/pages_desktop_specific/create_password/create_password_view.dart'; import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart'; +import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/my_stack_view.dart'; import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart'; import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart'; @@ -891,7 +892,13 @@ class RouteGenerator { builder: (_) => const DesktopHomeView(), settings: RouteSettings(name: settings.name)); - // == End of desktop specific routes ======================================= + case MyStackView.routeName: + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const MyStackView(), + settings: RouteSettings(name: settings.name)); + + // == End of desktop specific routes ===================================== default: return _routeError(""); diff --git a/lib/utilities/cfcolors.dart b/lib/utilities/cfcolors.dart index f5785a8c9..ad137de6a 100644 --- a/lib/utilities/cfcolors.dart +++ b/lib/utilities/cfcolors.dart @@ -155,6 +155,8 @@ abstract class CFColors { static const Color textSubtitle1 = Color(0xFF8E9192); static const Color textSubtitle2 = Color(0xFFA9ACAC); + static const Color borderNormal = Color(0xFF111111); + static const Color buttonTextSecondary = Color(0xFF232323); static const Color buttonTextPrimary = Color(0xFFFFFFFF); @@ -166,6 +168,8 @@ abstract class CFColors { static const Color buttonBackPrimaryDisabled = Color(0xFFD7D7D7); + static const Color textFieldDefaultSearchIconLeft = Color(0xFFA9ACAC); + // button color themes static ButtonStyle? getPrimaryEnabledButtonColor(BuildContext context) => diff --git a/lib/widgets/rounded_container.dart b/lib/widgets/rounded_container.dart index 91d23aa4e..8e5b94e98 100644 --- a/lib/widgets/rounded_container.dart +++ b/lib/widgets/rounded_container.dart @@ -1,5 +1,4 @@ import 'package:flutter/cupertino.dart'; - import 'package:stackwallet/utilities/constants.dart'; class RoundedContainer extends StatelessWidget { @@ -8,11 +7,13 @@ class RoundedContainer extends StatelessWidget { this.child, required this.color, this.padding = const EdgeInsets.all(12), + this.radiusMultiplier = 1.0, }) : super(key: key); final Widget? child; final Color color; final EdgeInsets padding; + final double radiusMultiplier; @override Widget build(BuildContext context) { @@ -20,7 +21,7 @@ class RoundedContainer extends StatelessWidget { decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, + Constants.size.circularBorderRadius * radiusMultiplier, ), ), child: Padding( diff --git a/lib/widgets/rounded_white_container.dart b/lib/widgets/rounded_white_container.dart index 836789c4d..7f511a040 100644 --- a/lib/widgets/rounded_white_container.dart +++ b/lib/widgets/rounded_white_container.dart @@ -7,16 +7,19 @@ class RoundedWhiteContainer extends StatelessWidget { Key? key, this.child, this.padding = const EdgeInsets.all(12), + this.radiusMultiplier = 1.0, }) : super(key: key); final Widget? child; final EdgeInsets padding; + final double radiusMultiplier; @override Widget build(BuildContext context) { return RoundedContainer( color: CFColors.white, padding: padding, + radiusMultiplier: radiusMultiplier, child: child, ); }