Merge branch 'desktop' of https://github.com/cypherstack/stack_wallet into desktop

This commit is contained in:
ryleedavis 2022-10-26 16:30:33 -06:00
commit 747ad30d74
4 changed files with 1046 additions and 643 deletions

View file

@ -0,0 +1,283 @@
import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart';
import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_refresh_button.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart';
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart';
import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/animated_text.dart';
class DesktopWalletSummary extends StatefulWidget {
const DesktopWalletSummary({
Key? key,
required this.walletId,
required this.managerProvider,
required this.initialSyncStatus,
}) : super(key: key);
final String walletId;
final ChangeNotifierProvider<Manager> managerProvider;
final WalletSyncStatus initialSyncStatus;
@override
State<DesktopWalletSummary> createState() => _WDesktopWalletSummaryState();
}
class _WDesktopWalletSummaryState extends State<DesktopWalletSummary> {
late final String walletId;
late final ChangeNotifierProvider<Manager> managerProvider;
void showSheet() {
showModalBottomSheet<dynamic>(
backgroundColor: Colors.transparent,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
builder: (_) => WalletBalanceToggleSheet(walletId: walletId),
);
}
Decimal? _balanceTotalCached;
Decimal? _balanceCached;
@override
void initState() {
walletId = widget.walletId;
managerProvider = widget.managerProvider;
super.initState();
}
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
Consumer(
builder: (_, ref, __) {
final Coin coin =
ref.watch(managerProvider.select((value) => value.coin));
final externalCalls = ref.watch(prefsChangeNotifierProvider
.select((value) => value.externalCalls));
Future<Decimal>? totalBalanceFuture;
Future<Decimal>? availableBalanceFuture;
if (coin == Coin.firo || coin == Coin.firoTestNet) {
final firoWallet =
ref.watch(managerProvider.select((value) => value.wallet))
as FiroWallet;
totalBalanceFuture = firoWallet.availablePublicBalance();
availableBalanceFuture = firoWallet.availablePrivateBalance();
} else {
totalBalanceFuture = ref.watch(
managerProvider.select((value) => value.totalBalance));
availableBalanceFuture = ref.watch(managerProvider
.select((value) => value.availableBalance));
}
final locale = ref.watch(localeServiceChangeNotifierProvider
.select((value) => value.locale));
final baseCurrency = ref.watch(prefsChangeNotifierProvider
.select((value) => value.currency));
final priceTuple = ref.watch(priceAnd24hChangeNotifierProvider
.select((value) => value.getPrice(coin)));
final _showAvailable =
ref.watch(walletBalanceToggleStateProvider.state).state ==
WalletBalanceToggleState.available;
return FutureBuilder(
future: _showAvailable
? availableBalanceFuture
: totalBalanceFuture,
builder: (fbContext, AsyncSnapshot<Decimal> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData &&
snapshot.data != null) {
if (_showAvailable) {
_balanceCached = snapshot.data!;
} else {
_balanceTotalCached = snapshot.data!;
}
}
Decimal? balanceToShow =
_showAvailable ? _balanceCached : _balanceTotalCached;
if (balanceToShow != null) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: showSheet,
child: Row(
children: [
if (coin == Coin.firo ||
coin == Coin.firoTestNet)
Text(
"${_showAvailable ? "Private" : "Public"} Balance",
style: STextStyles.subtitle500(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
),
if (coin != Coin.firo &&
coin != Coin.firoTestNet)
Text(
"${_showAvailable ? "Available" : "Full"} Balance",
style: STextStyles.subtitle500(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
),
const SizedBox(
width: 4,
),
SvgPicture.asset(
Assets.svg.chevronDown,
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
width: 8,
height: 4,
),
],
),
),
FittedBox(
fit: BoxFit.scaleDown,
child: Text(
"${Format.localizedStringAsFixed(
value: balanceToShow,
locale: locale,
decimalPlaces: 8,
)} ${coin.ticker}",
style: STextStyles.desktopH3(context),
),
),
if (externalCalls)
Text(
"${Format.localizedStringAsFixed(
value: priceTuple.item1 * balanceToShow,
locale: locale,
decimalPlaces: 2,
)} $baseCurrency",
style: STextStyles.desktopTextExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
],
);
} else {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: showSheet,
child: Row(
children: [
if (coin == Coin.firo ||
coin == Coin.firoTestNet)
Text(
"${_showAvailable ? "Private" : "Public"} Balance",
style: STextStyles.subtitle500(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
),
if (coin != Coin.firo &&
coin != Coin.firoTestNet)
Text(
"${_showAvailable ? "Available" : "Full"} Balance",
style: STextStyles.subtitle500(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
),
const SizedBox(
width: 4,
),
SvgPicture.asset(
Assets.svg.chevronDown,
width: 8,
height: 4,
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
],
),
),
AnimatedText(
stringsToLoopThrough: const [
"Loading balance ",
"Loading balance. ",
"Loading balance.. ",
"Loading balance..."
],
style: STextStyles.desktopH3(context).copyWith(
fontSize: 24,
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
),
AnimatedText(
stringsToLoopThrough: const [
"Loading balance ",
"Loading balance. ",
"Loading balance.. ",
"Loading balance..."
],
style: STextStyles.desktopTextExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
],
);
}
},
);
},
),
],
),
WalletRefreshButton(
walletId: walletId,
initialSyncStatus: widget.initialSyncStatus,
)
],
);
}
}

View file

@ -1,9 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_summary.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/receive/desktop_receive.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/send/desktop_send.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart';
@ -48,6 +50,8 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
final manager = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManager(walletId)));
final coin = manager.coin;
final managerProvider = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManagerProvider(walletId)));
return DesktopScaffold(
appBar: DesktopAppBar(
@ -120,37 +124,45 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
const SizedBox(
width: 10,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Text(
"TODO: balance",
style: STextStyles.desktopH3(context),
),
const SizedBox(
width: 8,
),
Container(
color: Colors.red,
width: 20,
height: 20,
),
],
),
Text(
"todo: fiat balance",
style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
)
],
DesktopWalletSummary(
walletId: walletId,
managerProvider: managerProvider,
initialSyncStatus: ref.watch(managerProvider
.select((value) => value.isRefreshing))
? WalletSyncStatus.syncing
: WalletSyncStatus.synced,
),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Row(
// children: [
// Text(
// "TODO: balance",
// style: STextStyles.desktopH3(context),
// ),
// const SizedBox(
// width: 8,
// ),
// Container(
// color: Colors.red,
// width: 20,
// height: 20,
// ),
// ],
// ),
// Text(
// "todo: fiat balance",
// style:
// STextStyles.desktopTextExtraSmall(context).copyWith(
// color: Theme.of(context)
// .extension<StackColors>()!
// .textSubtitle1,
// ),
// )
// ],
// ),
const Spacer(),
SecondaryButton(
width: 180,
@ -209,6 +221,8 @@ class MyWallet extends StatefulWidget {
}
class _MyWalletState extends State<MyWallet> {
int _selectedIndex = 0;
@override
Widget build(BuildContext context) {
return Column(
@ -225,53 +239,171 @@ class _MyWalletState extends State<MyWallet> {
const SizedBox(
height: 16,
),
Container(
decoration: BoxDecoration(
color: Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: BorderRadius.vertical(
top: Radius.circular(
Constants.size.circularBorderRadius,
),
),
),
child: SendReceiveTabMenu(
onChanged: (index) {
setState(() {
_selectedIndex = index;
});
},
),
),
Container(
decoration: BoxDecoration(
color: Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(
Constants.size.circularBorderRadius,
),
),
),
child: IndexedStack(
index: _selectedIndex,
children: [
Padding(
key: const Key("desktopSendViewPortKey"),
padding: const EdgeInsets.all(20),
child: DesktopSend(
walletId: widget.walletId,
),
),
Padding(
key: const Key("desktopReceiveViewPortKey"),
padding: const EdgeInsets.all(20),
child: DesktopReceive(
walletId: widget.walletId,
),
),
],
),
),
const Spacer(),
],
);
}
}
class SendReceiveTabMenu extends StatefulWidget {
const SendReceiveTabMenu({
Key? key,
this.initialIndex = 0,
this.onChanged,
}) : super(key: key);
final int initialIndex;
final void Function(int)? onChanged;
@override
State<SendReceiveTabMenu> createState() => _SendReceiveTabMenuState();
}
class _SendReceiveTabMenuState extends State<SendReceiveTabMenu> {
late int _selectedIndex;
void _onChanged(int newIndex) {
if (_selectedIndex != newIndex) {
setState(() {
_selectedIndex = newIndex;
});
widget.onChanged?.call(_selectedIndex);
}
}
@override
void initState() {
_selectedIndex = widget.initialIndex;
super.initState();
}
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
child: DefaultTabController(
length: 2,
child: GestureDetector(
onTap: () => _onChanged(0),
child: Container(
color: Colors.transparent,
child: Column(
children: [
TabBar(
indicatorColor: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
labelStyle: STextStyles.desktopTextExtraSmall(context),
labelColor: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
unselectedLabelColor: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
labelPadding: const EdgeInsets.symmetric(
vertical: 6,
),
splashBorderRadius: BorderRadius.vertical(
top: Radius.circular(
Constants.size.circularBorderRadius,
),
),
tabs: const [
Tab(text: "Send"),
Tab(text: "Receive"),
],
const SizedBox(
height: 16,
),
Expanded(
child: TabBarView(
children: [
Padding(
padding: const EdgeInsets.all(20),
child: DesktopSend(
walletId: widget.walletId,
),
),
Padding(
padding: const EdgeInsets.all(20),
child: DesktopReceive(
walletId: widget.walletId,
),
),
],
Text(
"Send",
style: STextStyles.desktopTextExtraSmall(context).copyWith(
color: _selectedIndex == 0
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
const SizedBox(
height: 19,
),
Container(
height: 2,
decoration: BoxDecoration(
color: _selectedIndex == 0
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.background,
),
),
],
),
),
),
),
Expanded(
child: GestureDetector(
onTap: () => _onChanged(1),
child: Container(
color: Colors.transparent,
child: Column(
children: [
const SizedBox(
height: 16,
),
Text(
"Receive",
style: STextStyles.desktopTextExtraSmall(context).copyWith(
color: _selectedIndex == 1
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
const SizedBox(
height: 19,
),
Container(
height: 2,
decoration: BoxDecoration(
color: _selectedIndex == 1
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.background,
),
),
],

View file

@ -199,15 +199,11 @@ class _DesktopReceiveState extends ConsumerState<DesktopReceive> {
height: 32,
),
Center(
child: SizedBox(
width: 200,
height: 200,
child: QrImage(
data: "${coin.uriScheme}:$receivingAddress",
size: MediaQuery.of(context).size.width / 2,
foregroundColor: Theme.of(context)
.extension<StackColors>()!
.accentColorDark),
child: QrImage(
data: "${coin.uriScheme}:$receivingAddress",
size: 200,
foregroundColor:
Theme.of(context).extension<StackColors>()!.accentColorDark,
),
),
const SizedBox(