add wallet desktop view

This commit is contained in:
julian 2022-09-16 17:54:46 -06:00
parent 47a5dc2a2c
commit 95d37c9c28
8 changed files with 406 additions and 87 deletions

View file

@ -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<Coin> 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<AddWalletView> 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<AddWalletView> {
late final TextEditingController _searchFieldController;
late final FocusNode _searchFocusNode;
String _searchTerm = "";
final List<Coin> 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<Coin> 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<Coin> coins;
final bool isDesktop;
final String searchTerm;
List<Coin> 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],
),
);
},
);
},
);
}
}

View file

@ -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,

View file

@ -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<DesktopHomeView> {
int currentViewIndex = 0;
final List<Widget> 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<DesktopHomeView> {
DesktopMenu(
onSelectionChanged: onMenuSelectionChanged,
),
Expanded(child: contentViews[currentViewIndex]),
Expanded(
child: contentViews[currentViewIndex],
),
],
),
);

View file

@ -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<MyStackView> createState() => _MyStackViewState();
}

View file

@ -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("");

View file

@ -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) =>

View file

@ -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(

View file

@ -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,
);
}