wallet card redesign
This commit is contained in:
@@ -229,7 +229,7 @@ RouteBase payoutShellRoute() => ShellRoute(
|
|||||||
_startPayment(context, recipient: null, paymentType: type),
|
_startPayment(context, recipient: null, paymentType: type),
|
||||||
onTopUp: (wallet) => _openWalletTopUp(context, wallet),
|
onTopUp: (wallet) => _openWalletTopUp(context, wallet),
|
||||||
onLedgerAddFunds: (account) => _openLedgerAddFunds(context, account),
|
onLedgerAddFunds: (account) => _openLedgerAddFunds(context, account),
|
||||||
onWalletTap: (wallet) => _openWalletEdit(context, wallet),
|
onWalletTap: (wallet) => _openWalletTopUp(context, wallet),
|
||||||
onLedgerTap: (account) => _openLedgerEdit(context, account),
|
onLedgerTap: (account) => _openLedgerEdit(context, account),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -385,12 +385,6 @@ void _openEditRecipient(BuildContext context, {required Recipient recipient}) {
|
|||||||
context.pushNamed(PayoutRoutes.editRecipient);
|
context.pushNamed(PayoutRoutes.editRecipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _openWalletEdit(BuildContext context, Wallet wallet) {
|
|
||||||
context.read<PaymentSourceController>().selectWallet(wallet);
|
|
||||||
context.read<WalletsController>().selectWallet(wallet);
|
|
||||||
context.pushToEditWallet();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _openLedgerEdit(BuildContext context, LedgerAccount account) {
|
void _openLedgerEdit(BuildContext context, LedgerAccount account) {
|
||||||
context.read<PaymentSourceController>().selectLedgerByRef(
|
context.read<PaymentSourceController>().selectLedgerByRef(
|
||||||
account.ledgerAccountRef,
|
account.ledgerAccountRef,
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class BalanceActionsUiController extends ChangeNotifier {
|
||||||
|
int? _hoveredButtonIndex;
|
||||||
|
|
||||||
|
int? get hoveredButtonIndex => _hoveredButtonIndex;
|
||||||
|
|
||||||
|
bool isExpanded(int index) => _hoveredButtonIndex == index;
|
||||||
|
|
||||||
|
void onHoverChanged(int index, bool hovered) {
|
||||||
|
final next = hovered
|
||||||
|
? index
|
||||||
|
: (_hoveredButtonIndex == index ? null : _hoveredButtonIndex);
|
||||||
|
if (next == _hoveredButtonIndex) return;
|
||||||
|
_hoveredButtonIndex = next;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,22 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import 'package:pshared/controllers/balance_mask/wallets.dart';
|
import 'package:pshared/controllers/balance_mask/wallets.dart';
|
||||||
import 'package:pshared/provider/ledger.dart';
|
import 'package:pshared/provider/ledger.dart';
|
||||||
|
|
||||||
import 'package:pweb/models/dashboard/balance_item.dart';
|
import 'package:pweb/models/dashboard/balance_item.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/config.dart';
|
||||||
|
|
||||||
|
|
||||||
class BalanceCarouselController with ChangeNotifier {
|
class BalanceCarouselController extends ChangeNotifier {
|
||||||
|
BalanceCarouselController()
|
||||||
|
: pageController = PageController(
|
||||||
|
viewportFraction: WalletCardConfig.viewportFraction,
|
||||||
|
);
|
||||||
|
|
||||||
WalletsController? _walletsController;
|
WalletsController? _walletsController;
|
||||||
List<BalanceItem> _items = const <BalanceItem>[BalanceItem.addAction()];
|
List<BalanceItem> _items = const <BalanceItem>[BalanceItem.addAction()];
|
||||||
int _index = 0;
|
int _index = 0;
|
||||||
|
final PageController pageController;
|
||||||
|
|
||||||
List<BalanceItem> get items => _items;
|
List<BalanceItem> get items => _items;
|
||||||
int get index => _index;
|
int get index => _index;
|
||||||
@@ -32,6 +39,7 @@ class BalanceCarouselController with ChangeNotifier {
|
|||||||
|
|
||||||
_items = nextItems;
|
_items = nextItems;
|
||||||
_index = nextIndex;
|
_index = nextIndex;
|
||||||
|
_syncPageController();
|
||||||
|
|
||||||
if (hasItemsChanged || hasIndexChanged) {
|
if (hasItemsChanged || hasIndexChanged) {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@@ -50,9 +58,24 @@ class BalanceCarouselController with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void goBack() => onPageChanged(_index - 1);
|
void goBack() => animateTo(_index - 1);
|
||||||
|
|
||||||
void goForward() => onPageChanged(_index + 1);
|
void goForward() => animateTo(_index + 1);
|
||||||
|
|
||||||
|
void animateTo(int index) {
|
||||||
|
final target = _clampIndex(index, _items.length);
|
||||||
|
if (!pageController.hasClients) {
|
||||||
|
onPageChanged(target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pageController.animateToPage(
|
||||||
|
target,
|
||||||
|
duration: const Duration(milliseconds: 220),
|
||||||
|
curve: Curves.easeOut,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void syncPageController() => _syncPageController();
|
||||||
|
|
||||||
int _resolveNextIndex(
|
int _resolveNextIndex(
|
||||||
List<BalanceItem> nextItems,
|
List<BalanceItem> nextItems,
|
||||||
@@ -126,4 +149,18 @@ class BalanceCarouselController with ChangeNotifier {
|
|||||||
if (walletsController.selectedWallet?.id == wallet.id) return;
|
if (walletsController.selectedWallet?.id == wallet.id) return;
|
||||||
walletsController.selectWallet(wallet);
|
walletsController.selectWallet(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _syncPageController() {
|
||||||
|
if (!pageController.hasClients || _items.isEmpty) return;
|
||||||
|
final current = pageController.page?.round();
|
||||||
|
final target = _clampIndex(_index, _items.length);
|
||||||
|
if (current == target) return;
|
||||||
|
pageController.jumpToPage(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
pageController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/controllers/payment/source.dart';
|
||||||
|
import 'package:pshared/models/payment/type.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/app/router/payout_routes.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class BalanceActionButtonState {
|
||||||
|
final String label;
|
||||||
|
final IconData icon;
|
||||||
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
|
const BalanceActionButtonState({
|
||||||
|
required this.label,
|
||||||
|
required this.icon,
|
||||||
|
required this.onPressed,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class BalanceActionsState {
|
||||||
|
final BalanceActionButtonState topLeading;
|
||||||
|
final BalanceActionButtonState topTrailing;
|
||||||
|
final BalanceActionButtonState bottom;
|
||||||
|
|
||||||
|
const BalanceActionsState({
|
||||||
|
required this.topLeading,
|
||||||
|
required this.topTrailing,
|
||||||
|
required this.bottom,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class BalanceSourceActionsController {
|
||||||
|
const BalanceSourceActionsController();
|
||||||
|
|
||||||
|
BalanceActionsState wallet({
|
||||||
|
required BuildContext context,
|
||||||
|
required String walletRef,
|
||||||
|
required VoidCallback onAddFunds,
|
||||||
|
}) {
|
||||||
|
return BalanceActionsState(
|
||||||
|
topLeading: BalanceActionButtonState(
|
||||||
|
label: 'Operation History',
|
||||||
|
icon: Icons.history_rounded,
|
||||||
|
onPressed: () => _openWalletOperationHistory(context, walletRef),
|
||||||
|
),
|
||||||
|
topTrailing: BalanceActionButtonState(
|
||||||
|
label: 'Send Payout',
|
||||||
|
icon: Icons.send_rounded,
|
||||||
|
onPressed: () => _sendWalletPayout(context, walletRef),
|
||||||
|
),
|
||||||
|
bottom: BalanceActionButtonState(
|
||||||
|
label: 'Wallet Details / Add Funds',
|
||||||
|
icon: Icons.account_balance_wallet_rounded,
|
||||||
|
onPressed: onAddFunds,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BalanceActionsState ledger({
|
||||||
|
required BuildContext context,
|
||||||
|
required String ledgerAccountRef,
|
||||||
|
required VoidCallback onAddFunds,
|
||||||
|
required VoidCallback onWalletDetails,
|
||||||
|
}) {
|
||||||
|
return BalanceActionsState(
|
||||||
|
topLeading: BalanceActionButtonState(
|
||||||
|
label: 'Operation History / Wallet Details',
|
||||||
|
icon: Icons.receipt_long_rounded,
|
||||||
|
onPressed: onWalletDetails,
|
||||||
|
),
|
||||||
|
topTrailing: BalanceActionButtonState(
|
||||||
|
label: 'Send Payout',
|
||||||
|
icon: Icons.send_rounded,
|
||||||
|
onPressed: () => _sendLedgerPayout(context, ledgerAccountRef),
|
||||||
|
),
|
||||||
|
bottom: BalanceActionButtonState(
|
||||||
|
label: 'Add Funds',
|
||||||
|
icon: Icons.add_card_rounded,
|
||||||
|
onPressed: onAddFunds,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _openWalletOperationHistory(BuildContext context, String walletRef) {
|
||||||
|
context.read<PaymentSourceController>().selectWalletByRef(walletRef);
|
||||||
|
context.pushNamed(PayoutRoutes.editWallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _sendWalletPayout(BuildContext context, String walletRef) {
|
||||||
|
context.read<PaymentSourceController>().selectWalletByRef(walletRef);
|
||||||
|
context.pushNamed(
|
||||||
|
PayoutRoutes.payment,
|
||||||
|
queryParameters: PayoutRoutes.buildQueryParameters(
|
||||||
|
paymentType: PaymentType.wallet,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _sendLedgerPayout(BuildContext context, String ledgerAccountRef) {
|
||||||
|
context.read<PaymentSourceController>().selectLedgerByRef(ledgerAccountRef);
|
||||||
|
context.pushNamed(
|
||||||
|
PayoutRoutes.payment,
|
||||||
|
queryParameters: PayoutRoutes.buildQueryParameters(
|
||||||
|
paymentType: PaymentType.ledger,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class BalanceCopyState {
|
||||||
|
final String label;
|
||||||
|
final String payload;
|
||||||
|
|
||||||
|
const BalanceCopyState({required this.label, required this.payload});
|
||||||
|
|
||||||
|
bool get canCopy => payload.trim().isNotEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
class BalanceSourceCopyController {
|
||||||
|
const BalanceSourceCopyController();
|
||||||
|
|
||||||
|
BalanceCopyState wallet(String? depositAddress) {
|
||||||
|
return BalanceCopyState(
|
||||||
|
label: 'Copy Deposit Address',
|
||||||
|
payload: depositAddress?.trim() ?? '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BalanceCopyState ledger(String? accountCode) {
|
||||||
|
return BalanceCopyState(
|
||||||
|
label: 'Copy Deposit Address',
|
||||||
|
payload: accountCode?.trim() ?? '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> copy(BalanceCopyState state) async {
|
||||||
|
if (!state.canCopy) return false;
|
||||||
|
await Clipboard.setData(ClipboardData(text: state.payload));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/controllers/dashboard/balance/actions_ui.dart';
|
||||||
|
import 'package:pweb/controllers/dashboard/balance/source_actions.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/actions/hover_expandable_action_button.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class BalanceActionsBar extends StatefulWidget {
|
||||||
|
final BalanceActionsState state;
|
||||||
|
|
||||||
|
const BalanceActionsBar({super.key, required this.state});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<BalanceActionsBar> createState() => _BalanceActionsBarState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BalanceActionsBarState extends State<BalanceActionsBar> {
|
||||||
|
static const double _buttonHeight = 34.0;
|
||||||
|
static const double _buttonGap = 6.0;
|
||||||
|
static const double _iconSize = 18.0;
|
||||||
|
static const double _textGap = 8.0;
|
||||||
|
static const double _horizontalPadding = 6.0;
|
||||||
|
|
||||||
|
final BalanceActionsUiController _uiController = BalanceActionsUiController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_uiController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final colorScheme = Theme.of(context).colorScheme;
|
||||||
|
final textStyle = Theme.of(context).textTheme.titleSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: colorScheme.onSecondary,
|
||||||
|
fontSize: 14,
|
||||||
|
);
|
||||||
|
final buttons = <BalanceActionButtonState>[
|
||||||
|
widget.state.topLeading,
|
||||||
|
widget.state.topTrailing,
|
||||||
|
widget.state.bottom,
|
||||||
|
];
|
||||||
|
|
||||||
|
return ListenableBuilder(
|
||||||
|
listenable: _uiController,
|
||||||
|
builder: (context, _) {
|
||||||
|
return Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: OverflowBox(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
minWidth: 0,
|
||||||
|
maxWidth: double.infinity,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
for (var i = 0; i < buttons.length; i++) ...[
|
||||||
|
HoverExpandableActionButton(
|
||||||
|
height: _buttonHeight,
|
||||||
|
icon: buttons[i].icon,
|
||||||
|
label: buttons[i].label,
|
||||||
|
iconSize: _iconSize,
|
||||||
|
textStyle: textStyle,
|
||||||
|
expanded: _uiController.isExpanded(i),
|
||||||
|
textGap: _textGap,
|
||||||
|
horizontalPadding: _horizontalPadding,
|
||||||
|
onHoverChanged: (hovered) =>
|
||||||
|
_uiController.onHoverChanged(i, hovered),
|
||||||
|
onPressed: buttons[i].onPressed,
|
||||||
|
),
|
||||||
|
if (i != buttons.length - 1)
|
||||||
|
const SizedBox(height: _buttonGap),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class HoverExpandableActionButton extends StatelessWidget {
|
||||||
|
final double height;
|
||||||
|
final IconData icon;
|
||||||
|
final String label;
|
||||||
|
final double iconSize;
|
||||||
|
final TextStyle? textStyle;
|
||||||
|
final bool expanded;
|
||||||
|
final double textGap;
|
||||||
|
final double horizontalPadding;
|
||||||
|
final ValueChanged<bool> onHoverChanged;
|
||||||
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
|
const HoverExpandableActionButton({
|
||||||
|
super.key,
|
||||||
|
required this.height,
|
||||||
|
required this.icon,
|
||||||
|
required this.label,
|
||||||
|
required this.iconSize,
|
||||||
|
required this.textStyle,
|
||||||
|
required this.expanded,
|
||||||
|
required this.textGap,
|
||||||
|
required this.horizontalPadding,
|
||||||
|
required this.onHoverChanged,
|
||||||
|
required this.onPressed,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final colorScheme = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
|
return MouseRegion(
|
||||||
|
onEnter: (_) => onHoverChanged(true),
|
||||||
|
onExit: (_) => onHoverChanged(false),
|
||||||
|
child: AnimatedContainer(
|
||||||
|
duration: const Duration(milliseconds: 220),
|
||||||
|
curve: Curves.easeOutCubic,
|
||||||
|
height: height,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: colorScheme.primaryFixed,
|
||||||
|
borderRadius: BorderRadius.circular(999),
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
type: MaterialType.transparency,
|
||||||
|
child: InkWell(
|
||||||
|
borderRadius: BorderRadius.circular(999),
|
||||||
|
onTap: onPressed,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: horizontalPadding),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(icon, size: iconSize, color: colorScheme.onSecondary),
|
||||||
|
AnimatedSize(
|
||||||
|
duration: const Duration(milliseconds: 220),
|
||||||
|
curve: Curves.easeOutCubic,
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: expanded
|
||||||
|
? Padding(
|
||||||
|
padding: EdgeInsets.only(left: textGap),
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.visible,
|
||||||
|
style: textStyle,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,12 +29,17 @@ class BalanceAmount extends StatelessWidget {
|
|||||||
final isMasked = wallets.isBalanceMasked(wallet.id);
|
final isMasked = wallets.isBalanceMasked(wallet.id);
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
isMasked ? '•••• $currencyBalance' : '${amountToString(wallet.balance)} $currencyBalance',
|
isMasked
|
||||||
style: textTheme.headlineSmall?.copyWith(
|
? '•••• $currencyBalance'
|
||||||
|
: '${amountToString(wallet.balance)} $currencyBalance',
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: textTheme.headlineMedium?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: colorScheme.onSurface,
|
color: colorScheme.primary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: _iconSpacing),
|
const SizedBox(width: _iconSpacing),
|
||||||
@@ -43,7 +48,7 @@ class BalanceAmount extends StatelessWidget {
|
|||||||
child: Icon(
|
child: Icon(
|
||||||
isMasked ? Icons.visibility_off : Icons.visibility,
|
isMasked ? Icons.visibility_off : Icons.visibility,
|
||||||
size: _iconSize,
|
size: _iconSize,
|
||||||
color: colorScheme.onSurface,
|
color: colorScheme.primary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,152 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/gestures.dart';
|
|
||||||
|
|
||||||
import 'package:pshared/models/ledger/account.dart';
|
|
||||||
import 'package:pshared/models/payment/wallet.dart';
|
|
||||||
|
|
||||||
import 'package:pweb/models/dashboard/balance_item.dart';
|
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/add/card.dart';
|
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/card.dart';
|
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/config.dart';
|
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/indicator.dart';
|
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/ledger.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class BalanceCarousel extends StatefulWidget {
|
|
||||||
final List<BalanceItem> items;
|
|
||||||
final int currentIndex;
|
|
||||||
final ValueChanged<int> onIndexChanged;
|
|
||||||
final ValueChanged<Wallet> onTopUp;
|
|
||||||
final ValueChanged<LedgerAccount> onLedgerAddFunds;
|
|
||||||
final ValueChanged<Wallet> onWalletTap;
|
|
||||||
final ValueChanged<LedgerAccount> onLedgerTap;
|
|
||||||
|
|
||||||
const BalanceCarousel({
|
|
||||||
super.key,
|
|
||||||
required this.items,
|
|
||||||
required this.currentIndex,
|
|
||||||
required this.onIndexChanged,
|
|
||||||
required this.onTopUp,
|
|
||||||
required this.onLedgerAddFunds,
|
|
||||||
required this.onWalletTap,
|
|
||||||
required this.onLedgerTap,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<BalanceCarousel> createState() => _BalanceCarouselState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _BalanceCarouselState extends State<BalanceCarousel> {
|
|
||||||
late final PageController _controller;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_controller = PageController(
|
|
||||||
initialPage: widget.currentIndex,
|
|
||||||
viewportFraction: WalletCardConfig.viewportFraction,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didUpdateWidget(covariant BalanceCarousel oldWidget) {
|
|
||||||
super.didUpdateWidget(oldWidget);
|
|
||||||
if (!mounted) return;
|
|
||||||
if (_controller.hasClients) {
|
|
||||||
final currentPage = _controller.page?.round();
|
|
||||||
if (currentPage != widget.currentIndex) {
|
|
||||||
_controller.jumpToPage(widget.currentIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _goToPage(int index) {
|
|
||||||
if (!_controller.hasClients) return;
|
|
||||||
_controller.animateToPage(
|
|
||||||
index,
|
|
||||||
duration: const Duration(milliseconds: 220),
|
|
||||||
curve: Curves.easeOut,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (widget.items.isEmpty) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
|
|
||||||
final safeIndex = widget.currentIndex.clamp(0, widget.items.length - 1);
|
|
||||||
final scrollBehavior = ScrollConfiguration.of(context).copyWith(
|
|
||||||
dragDevices: const {
|
|
||||||
PointerDeviceKind.touch,
|
|
||||||
PointerDeviceKind.mouse,
|
|
||||||
PointerDeviceKind.trackpad,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: WalletCardConfig.cardHeight,
|
|
||||||
child: MouseRegion(
|
|
||||||
cursor: SystemMouseCursors.grab,
|
|
||||||
child: ScrollConfiguration(
|
|
||||||
behavior: scrollBehavior,
|
|
||||||
child: PageView.builder(
|
|
||||||
controller: _controller,
|
|
||||||
onPageChanged: widget.onIndexChanged,
|
|
||||||
itemCount: widget.items.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final item = widget.items[index];
|
|
||||||
final Widget card = switch (item) {
|
|
||||||
WalletBalanceItem(:final wallet) => WalletCard(
|
|
||||||
wallet: wallet,
|
|
||||||
onTopUp: () => widget.onTopUp(wallet),
|
|
||||||
onTap: () => widget.onWalletTap(wallet),
|
|
||||||
),
|
|
||||||
LedgerBalanceItem(:final account) => LedgerAccountCard(
|
|
||||||
account: account,
|
|
||||||
onTap: () => widget.onLedgerTap(account),
|
|
||||||
onAddFunds: () => widget.onLedgerAddFunds(account),
|
|
||||||
),
|
|
||||||
AddBalanceActionItem() => const AddBalanceCard(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return Padding(
|
|
||||||
padding: WalletCardConfig.cardPadding,
|
|
||||||
child: card,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
IconButton(
|
|
||||||
onPressed: safeIndex > 0 ? () => _goToPage(safeIndex - 1) : null,
|
|
||||||
icon: const Icon(Icons.arrow_back),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
CarouselIndicator(itemCount: widget.items.length, index: safeIndex),
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
IconButton(
|
|
||||||
onPressed: safeIndex < widget.items.length - 1
|
|
||||||
? () => _goToPage(safeIndex + 1)
|
|
||||||
: null,
|
|
||||||
icon: const Icon(Icons.arrow_forward),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/models/ledger/account.dart';
|
||||||
|
import 'package:pshared/models/payment/wallet.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/models/dashboard/balance_item.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/add/card.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/config.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/source/cards/ledger.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/source/cards/wallet.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class BalanceCarouselCardItem extends StatelessWidget {
|
||||||
|
final BalanceItem item;
|
||||||
|
final ValueChanged<Wallet> onTopUp;
|
||||||
|
final ValueChanged<LedgerAccount> onLedgerAddFunds;
|
||||||
|
final ValueChanged<Wallet> onWalletTap;
|
||||||
|
final ValueChanged<LedgerAccount> onLedgerTap;
|
||||||
|
|
||||||
|
const BalanceCarouselCardItem({
|
||||||
|
super.key,
|
||||||
|
required this.item,
|
||||||
|
required this.onTopUp,
|
||||||
|
required this.onLedgerAddFunds,
|
||||||
|
required this.onWalletTap,
|
||||||
|
required this.onLedgerTap,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final card = switch (item) {
|
||||||
|
WalletBalanceItem(:final wallet) => WalletCard(
|
||||||
|
wallet: wallet,
|
||||||
|
onTopUp: () => onTopUp(wallet),
|
||||||
|
onTap: () => onWalletTap(wallet),
|
||||||
|
),
|
||||||
|
LedgerBalanceItem(:final account) => LedgerAccountCard(
|
||||||
|
account: account,
|
||||||
|
onTap: () => onLedgerTap(account),
|
||||||
|
onAddFunds: () => onLedgerAddFunds(account),
|
||||||
|
),
|
||||||
|
AddBalanceActionItem() => const AddBalanceCard(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Padding(padding: WalletCardConfig.cardPadding, child: card);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import 'package:flutter/gestures.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/models/ledger/account.dart';
|
||||||
|
import 'package:pshared/models/payment/wallet.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/controllers/dashboard/balance/carousel.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/carousel/card_item.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class BalanceCarouselCardsView extends StatelessWidget {
|
||||||
|
final BalanceCarouselController controller;
|
||||||
|
final ValueChanged<Wallet> onTopUp;
|
||||||
|
final ValueChanged<LedgerAccount> onLedgerAddFunds;
|
||||||
|
final ValueChanged<Wallet> onWalletTap;
|
||||||
|
final ValueChanged<LedgerAccount> onLedgerTap;
|
||||||
|
final double height;
|
||||||
|
|
||||||
|
const BalanceCarouselCardsView({
|
||||||
|
super.key,
|
||||||
|
required this.controller,
|
||||||
|
required this.onTopUp,
|
||||||
|
required this.onLedgerAddFunds,
|
||||||
|
required this.onWalletTap,
|
||||||
|
required this.onLedgerTap,
|
||||||
|
required this.height,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final scrollBehavior = ScrollConfiguration.of(context).copyWith(
|
||||||
|
dragDevices: const {
|
||||||
|
PointerDeviceKind.touch,
|
||||||
|
PointerDeviceKind.mouse,
|
||||||
|
PointerDeviceKind.trackpad,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return SizedBox(
|
||||||
|
height: height,
|
||||||
|
child: MouseRegion(
|
||||||
|
cursor: SystemMouseCursors.grab,
|
||||||
|
child: ScrollConfiguration(
|
||||||
|
behavior: scrollBehavior,
|
||||||
|
child: PageView.builder(
|
||||||
|
controller: controller.pageController,
|
||||||
|
onPageChanged: controller.onPageChanged,
|
||||||
|
itemCount: controller.items.length,
|
||||||
|
itemBuilder: (context, index) => BalanceCarouselCardItem(
|
||||||
|
item: controller.items[index],
|
||||||
|
onTopUp: onTopUp,
|
||||||
|
onLedgerAddFunds: onLedgerAddFunds,
|
||||||
|
onWalletTap: onWalletTap,
|
||||||
|
onLedgerTap: onLedgerTap,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/models/ledger/account.dart';
|
||||||
|
import 'package:pshared/models/payment/wallet.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/controllers/dashboard/balance/carousel.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/carousel/cards_view.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/carousel/navigation.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/config.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class BalanceCarousel extends StatelessWidget {
|
||||||
|
final BalanceCarouselController controller;
|
||||||
|
final ValueChanged<Wallet> onTopUp;
|
||||||
|
final ValueChanged<LedgerAccount> onLedgerAddFunds;
|
||||||
|
final ValueChanged<Wallet> onWalletTap;
|
||||||
|
final ValueChanged<LedgerAccount> onLedgerTap;
|
||||||
|
|
||||||
|
const BalanceCarousel({
|
||||||
|
super.key,
|
||||||
|
required this.controller,
|
||||||
|
required this.onTopUp,
|
||||||
|
required this.onLedgerAddFunds,
|
||||||
|
required this.onWalletTap,
|
||||||
|
required this.onLedgerTap,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (controller.items.isEmpty) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
controller.syncPageController();
|
||||||
|
});
|
||||||
|
|
||||||
|
final safeIndex = controller.index.clamp(0, controller.items.length - 1);
|
||||||
|
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
final cardHeight = WalletCardConfig.cardHeightForWidth(
|
||||||
|
constraints.maxWidth,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
BalanceCarouselCardsView(
|
||||||
|
controller: controller,
|
||||||
|
onTopUp: onTopUp,
|
||||||
|
onLedgerAddFunds: onLedgerAddFunds,
|
||||||
|
onWalletTap: onWalletTap,
|
||||||
|
onLedgerTap: onLedgerTap,
|
||||||
|
height: cardHeight,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
BalanceCarouselNavigation(controller: controller, index: safeIndex),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/controllers/dashboard/balance/carousel.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/indicator.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class BalanceCarouselNavigation extends StatelessWidget {
|
||||||
|
final BalanceCarouselController controller;
|
||||||
|
final int index;
|
||||||
|
|
||||||
|
const BalanceCarouselNavigation({
|
||||||
|
super.key,
|
||||||
|
required this.controller,
|
||||||
|
required this.index,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: index > 0 ? controller.goBack : null,
|
||||||
|
icon: const Icon(Icons.arrow_back),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
CarouselIndicator(itemCount: controller.items.length, index: index),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
IconButton(
|
||||||
|
onPressed: index < controller.items.length - 1
|
||||||
|
? controller.goForward
|
||||||
|
: null,
|
||||||
|
icon: const Icon(Icons.arrow_forward),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,14 +2,21 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
|
|
||||||
abstract class WalletCardConfig {
|
abstract class WalletCardConfig {
|
||||||
static const double cardHeight = 145.0;
|
|
||||||
static const double elevation = 4.0;
|
static const double elevation = 4.0;
|
||||||
static const double borderRadius = 16.0;
|
static const double borderRadius = 16.0;
|
||||||
static const double viewportFraction = 0.9;
|
static const double viewportFraction = 0.96;
|
||||||
|
|
||||||
static const EdgeInsets cardPadding = EdgeInsets.symmetric(horizontal: 8);
|
static const EdgeInsets cardPadding = EdgeInsets.symmetric(horizontal: 6);
|
||||||
static const EdgeInsets contentPadding = EdgeInsets.all(16);
|
static const EdgeInsets contentPadding = EdgeInsets.symmetric(
|
||||||
|
horizontal: 28,
|
||||||
|
vertical: 16,
|
||||||
|
);
|
||||||
|
|
||||||
static const double dotSize = 8.0;
|
static const double dotSize = 8.0;
|
||||||
static const EdgeInsets dotMargin = EdgeInsets.symmetric(horizontal: 4);
|
static const EdgeInsets dotMargin = EdgeInsets.symmetric(horizontal: 4);
|
||||||
|
|
||||||
|
static double cardHeightForWidth(double width) {
|
||||||
|
final adaptiveHeight = width * 0.18;
|
||||||
|
return adaptiveHeight.clamp(150.0, 230.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,46 +20,51 @@ class BalanceHeader extends StatelessWidget {
|
|||||||
final subtitleText = subtitle?.trim();
|
final subtitleText = subtitle?.trim();
|
||||||
final badgeText = badge?.trim();
|
final badgeText = badge?.trim();
|
||||||
|
|
||||||
return Row(
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Row(
|
||||||
child: Column(
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
children: [
|
||||||
children: [
|
Flexible(
|
||||||
Text(
|
child: Text(
|
||||||
title,
|
title,
|
||||||
style: textTheme.titleMedium?.copyWith(
|
maxLines: 2,
|
||||||
color: colorScheme.onSurface,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: textTheme.titleLarge?.copyWith(
|
||||||
|
color: colorScheme.primary,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (subtitleText != null && subtitleText.isNotEmpty)
|
),
|
||||||
Text(
|
if (badgeText != null && badgeText.isNotEmpty) ...[
|
||||||
subtitleText,
|
const SizedBox(width: 8),
|
||||||
style: textTheme.bodySmall?.copyWith(
|
Container(
|
||||||
color: colorScheme.onSurfaceVariant,
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||||
fontWeight: FontWeight.w500,
|
decoration: BoxDecoration(
|
||||||
|
color: colorScheme.primaryFixed,
|
||||||
|
borderRadius: BorderRadius.circular(999),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
badgeText,
|
||||||
|
style: textTheme.labelSmall?.copyWith(
|
||||||
|
color: colorScheme.onSecondary,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (badgeText != null && badgeText.isNotEmpty) ...[
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: colorScheme.primaryContainer,
|
|
||||||
borderRadius: BorderRadius.circular(999),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
badgeText,
|
|
||||||
style: textTheme.bodyMedium?.copyWith(
|
|
||||||
color: colorScheme.onPrimaryContainer,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (subtitleText != null && subtitleText.isNotEmpty)
|
||||||
|
Text(
|
||||||
|
subtitleText,
|
||||||
|
style: textTheme.titleSmall?.copyWith(
|
||||||
|
color: colorScheme.primaryFixed,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
|
maxLines: 1,
|
||||||
),
|
),
|
||||||
],
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,14 +26,15 @@ class LedgerBalanceAmount extends StatelessWidget {
|
|||||||
: LedgerBalanceFormatter.format(account);
|
: LedgerBalanceFormatter.format(account);
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Flexible(
|
Text(
|
||||||
child: Text(
|
balance,
|
||||||
balance,
|
maxLines: 1,
|
||||||
style: textTheme.headlineSmall?.copyWith(
|
overflow: TextOverflow.ellipsis,
|
||||||
fontWeight: FontWeight.bold,
|
style: textTheme.headlineSmall?.copyWith(
|
||||||
color: colorScheme.onSurface,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
color: colorScheme.primary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
@@ -44,7 +45,7 @@ class LedgerBalanceAmount extends StatelessWidget {
|
|||||||
child: Icon(
|
child: Icon(
|
||||||
isMasked ? Icons.visibility_off : Icons.visibility,
|
isMasked ? Icons.visibility_off : Icons.visibility,
|
||||||
size: 24,
|
size: 24,
|
||||||
color: colorScheme.onSurface,
|
color: colorScheme.primary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import 'package:provider/provider.dart';
|
|||||||
import 'package:pshared/controllers/balance_mask/wallets.dart';
|
import 'package:pshared/controllers/balance_mask/wallets.dart';
|
||||||
import 'package:pshared/provider/ledger.dart';
|
import 'package:pshared/provider/ledger.dart';
|
||||||
|
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/controller.dart';
|
import 'package:pweb/controllers/dashboard/balance/carousel.dart';
|
||||||
|
|
||||||
|
|
||||||
class BalanceWidgetProviders extends StatelessWidget {
|
class BalanceWidgetProviders extends StatelessWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|||||||
@@ -1,44 +1,31 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:pweb/controllers/dashboard/balance/source_actions.dart';
|
||||||
|
|
||||||
import 'package:pshared/provider/ledger.dart';
|
|
||||||
|
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/actions/bar.dart';
|
import 'package:pweb/pages/dashboard/buttons/balance/actions/bar.dart';
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class LedgerSourceActions extends StatelessWidget {
|
class LedgerSourceActions extends StatelessWidget {
|
||||||
final String ledgerAccountRef;
|
final String ledgerAccountRef;
|
||||||
final VoidCallback onAddFunds;
|
final VoidCallback onAddFunds;
|
||||||
|
final VoidCallback onWalletDetails;
|
||||||
|
|
||||||
const LedgerSourceActions({
|
const LedgerSourceActions({
|
||||||
super.key,
|
super.key,
|
||||||
required this.ledgerAccountRef,
|
required this.ledgerAccountRef,
|
||||||
required this.onAddFunds,
|
required this.onAddFunds,
|
||||||
|
required this.onWalletDetails,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ledgerProvider = context.watch<LedgerAccountsProvider>();
|
const controller = BalanceSourceActionsController();
|
||||||
final loc = AppLocalizations.of(context)!;
|
final state = controller.ledger(
|
||||||
final isBusy =
|
context: context,
|
||||||
ledgerProvider.isWalletRefreshing(ledgerAccountRef) ||
|
ledgerAccountRef: ledgerAccountRef,
|
||||||
ledgerProvider.isLoading;
|
onAddFunds: onAddFunds,
|
||||||
final hasTarget = ledgerProvider.accounts.any(
|
onWalletDetails: onWalletDetails,
|
||||||
(a) => a.ledgerAccountRef == ledgerAccountRef,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return BalanceActionsBar(
|
return BalanceActionsBar(state: state);
|
||||||
isRefreshBusy: isBusy,
|
|
||||||
canRefresh: hasTarget,
|
|
||||||
onRefresh: () {
|
|
||||||
context.read<LedgerAccountsProvider>().refreshBalance(ledgerAccountRef);
|
|
||||||
},
|
|
||||||
onAddFunds: onAddFunds,
|
|
||||||
refreshLabel: loc.refreshBalance,
|
|
||||||
addFundsLabel: loc.addFunds,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:pweb/controllers/dashboard/balance/source_actions.dart';
|
||||||
|
|
||||||
import 'package:pshared/provider/payment/wallets.dart';
|
|
||||||
|
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/actions/bar.dart';
|
import 'package:pweb/pages/dashboard/buttons/balance/actions/bar.dart';
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class WalletSourceActions extends StatelessWidget {
|
class WalletSourceActions extends StatelessWidget {
|
||||||
final String walletRef;
|
final String walletRef;
|
||||||
@@ -21,22 +16,13 @@ class WalletSourceActions extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final walletsProvider = context.watch<WalletsProvider>();
|
const controller = BalanceSourceActionsController();
|
||||||
final loc = AppLocalizations.of(context)!;
|
final state = controller.wallet(
|
||||||
final isBusy =
|
context: context,
|
||||||
walletsProvider.isWalletRefreshing(walletRef) ||
|
walletRef: walletRef,
|
||||||
walletsProvider.isLoading;
|
|
||||||
final hasTarget = walletsProvider.wallets.any((w) => w.id == walletRef);
|
|
||||||
|
|
||||||
return BalanceActionsBar(
|
|
||||||
isRefreshBusy: isBusy,
|
|
||||||
canRefresh: hasTarget,
|
|
||||||
onRefresh: () {
|
|
||||||
context.read<WalletsProvider>().refreshBalance(walletRef);
|
|
||||||
},
|
|
||||||
onAddFunds: onAddFunds,
|
onAddFunds: onAddFunds,
|
||||||
refreshLabel: loc.refreshBalance,
|
|
||||||
addFundsLabel: loc.addFunds,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return BalanceActionsBar(state: state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,15 @@ import 'package:pshared/models/payment/source_type.dart';
|
|||||||
import 'package:pshared/models/payment/wallet.dart';
|
import 'package:pshared/models/payment/wallet.dart';
|
||||||
import 'package:pshared/utils/l10n/chain.dart';
|
import 'package:pshared/utils/l10n/chain.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/controllers/dashboard/balance/source_copy.dart';
|
||||||
|
import 'package:pweb/models/state/visibility.dart';
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/amount.dart';
|
import 'package:pweb/pages/dashboard/buttons/balance/amount.dart';
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/ledger_amount.dart';
|
import 'package:pweb/pages/dashboard/buttons/balance/ledger_amount.dart';
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/source/actions/ledger.dart';
|
import 'package:pweb/pages/dashboard/buttons/balance/source/actions/ledger.dart';
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/source/actions/wallet.dart';
|
import 'package:pweb/pages/dashboard/buttons/balance/source/actions/wallet.dart';
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/source/card_layout.dart';
|
import 'package:pweb/pages/dashboard/buttons/balance/source/card_layout.dart';
|
||||||
|
import 'package:pweb/widgets/refresh_balance/ledger.dart';
|
||||||
|
import 'package:pweb/widgets/refresh_balance/wallet.dart';
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
@@ -24,6 +28,8 @@ class BalanceSourceCard extends StatelessWidget {
|
|||||||
final LedgerAccount? _ledgerAccount;
|
final LedgerAccount? _ledgerAccount;
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
final VoidCallback onAddFunds;
|
final VoidCallback onAddFunds;
|
||||||
|
static const BalanceSourceCopyController _copyController =
|
||||||
|
BalanceSourceCopyController();
|
||||||
|
|
||||||
const BalanceSourceCard.wallet({
|
const BalanceSourceCard.wallet({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -55,12 +61,29 @@ class BalanceSourceCard extends StatelessWidget {
|
|||||||
? null
|
? null
|
||||||
: wallet.network!.localizedName(context);
|
: wallet.network!.localizedName(context);
|
||||||
final symbol = wallet.tokenSymbol?.trim();
|
final symbol = wallet.tokenSymbol?.trim();
|
||||||
|
final copyState = _copyController.wallet(wallet.depositAddress);
|
||||||
|
|
||||||
return BalanceSourceCardLayout(
|
return BalanceSourceCardLayout(
|
||||||
title: wallet.name,
|
title: wallet.name,
|
||||||
subtitle: networkLabel,
|
subtitle: networkLabel,
|
||||||
badge: (symbol == null || symbol.isEmpty) ? null : symbol,
|
badge: (symbol == null || symbol.isEmpty) ? null : symbol,
|
||||||
onTap: onTap,
|
onTap: null,
|
||||||
|
copyLabel: copyState.label,
|
||||||
|
canCopy: copyState.canCopy,
|
||||||
|
onCopy: copyState.canCopy
|
||||||
|
? () async {
|
||||||
|
final copied = await _copyController.copy(copyState);
|
||||||
|
if (!copied || !context.mounted) return;
|
||||||
|
final loc = AppLocalizations.of(context)!;
|
||||||
|
ScaffoldMessenger.of(
|
||||||
|
context,
|
||||||
|
).showSnackBar(SnackBar(content: Text(loc.addressCopied)));
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
refreshButton: WalletBalanceRefreshButton(
|
||||||
|
walletRef: wallet.id,
|
||||||
|
iconOnly: VisibilityState.hidden,
|
||||||
|
),
|
||||||
actions: WalletSourceActions(
|
actions: WalletSourceActions(
|
||||||
walletRef: wallet.id,
|
walletRef: wallet.id,
|
||||||
onAddFunds: onAddFunds,
|
onAddFunds: onAddFunds,
|
||||||
@@ -79,19 +102,35 @@ class BalanceSourceCard extends StatelessWidget {
|
|||||||
final accountName = account.name.trim();
|
final accountName = account.name.trim();
|
||||||
final accountCode = account.accountCode.trim();
|
final accountCode = account.accountCode.trim();
|
||||||
final title = accountName.isNotEmpty ? accountName : loc.paymentTypeLedger;
|
final title = accountName.isNotEmpty ? accountName : loc.paymentTypeLedger;
|
||||||
final subtitle = accountCode.isNotEmpty ? accountCode : null;
|
|
||||||
final badge = account.currency.trim().isEmpty
|
final badge = account.currency.trim().isEmpty
|
||||||
? null
|
? null
|
||||||
: account.currency.toUpperCase();
|
: account.currency.toUpperCase();
|
||||||
|
final copyState = _copyController.ledger(accountCode);
|
||||||
|
|
||||||
return BalanceSourceCardLayout(
|
return BalanceSourceCardLayout(
|
||||||
title: title,
|
title: title,
|
||||||
subtitle: subtitle,
|
subtitle: null,
|
||||||
badge: badge,
|
badge: badge,
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
|
copyLabel: copyState.label,
|
||||||
|
canCopy: copyState.canCopy,
|
||||||
|
onCopy: copyState.canCopy
|
||||||
|
? () async {
|
||||||
|
final copied = await _copyController.copy(copyState);
|
||||||
|
if (!copied || !context.mounted) return;
|
||||||
|
ScaffoldMessenger.of(
|
||||||
|
context,
|
||||||
|
).showSnackBar(SnackBar(content: Text(loc.addressCopied)));
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
refreshButton: LedgerBalanceRefreshButton(
|
||||||
|
ledgerAccountRef: account.ledgerAccountRef,
|
||||||
|
iconOnly: VisibilityState.hidden,
|
||||||
|
),
|
||||||
actions: LedgerSourceActions(
|
actions: LedgerSourceActions(
|
||||||
ledgerAccountRef: account.ledgerAccountRef,
|
ledgerAccountRef: account.ledgerAccountRef,
|
||||||
onAddFunds: onAddFunds,
|
onAddFunds: onAddFunds,
|
||||||
|
onWalletDetails: onTap,
|
||||||
),
|
),
|
||||||
amount: LedgerBalanceAmount(account: account),
|
amount: LedgerBalanceAmount(account: account),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/config.dart';
|
import 'package:pweb/pages/dashboard/buttons/balance/config.dart';
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/header.dart';
|
import 'package:pweb/pages/dashboard/buttons/balance/source/layout/wide_body.dart';
|
||||||
|
|
||||||
|
|
||||||
class BalanceSourceCardLayout extends StatelessWidget {
|
class BalanceSourceCardLayout extends StatelessWidget {
|
||||||
@@ -9,8 +9,12 @@ class BalanceSourceCardLayout extends StatelessWidget {
|
|||||||
final String? subtitle;
|
final String? subtitle;
|
||||||
final String? badge;
|
final String? badge;
|
||||||
final Widget amount;
|
final Widget amount;
|
||||||
|
final Widget refreshButton;
|
||||||
final Widget actions;
|
final Widget actions;
|
||||||
final VoidCallback onTap;
|
final VoidCallback? onTap;
|
||||||
|
final String copyLabel;
|
||||||
|
final bool canCopy;
|
||||||
|
final VoidCallback? onCopy;
|
||||||
|
|
||||||
const BalanceSourceCardLayout({
|
const BalanceSourceCardLayout({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -18,40 +22,39 @@ class BalanceSourceCardLayout extends StatelessWidget {
|
|||||||
required this.subtitle,
|
required this.subtitle,
|
||||||
required this.badge,
|
required this.badge,
|
||||||
required this.amount,
|
required this.amount,
|
||||||
|
required this.refreshButton,
|
||||||
required this.actions,
|
required this.actions,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
|
required this.copyLabel,
|
||||||
|
required this.canCopy,
|
||||||
|
required this.onCopy,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final colorScheme = Theme.of(context).colorScheme;
|
final colorScheme = Theme.of(context).colorScheme;
|
||||||
|
final borderRadius = BorderRadius.circular(WalletCardConfig.borderRadius);
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
color: colorScheme.onSecondary,
|
color: colorScheme.onSecondary,
|
||||||
elevation: WalletCardConfig.elevation,
|
elevation: WalletCardConfig.elevation,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(borderRadius: borderRadius),
|
||||||
borderRadius: BorderRadius.circular(WalletCardConfig.borderRadius),
|
|
||||||
),
|
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius: BorderRadius.circular(WalletCardConfig.borderRadius),
|
borderRadius: borderRadius,
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: SizedBox.expand(
|
child: SizedBox.expand(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: WalletCardConfig.contentPadding,
|
padding: WalletCardConfig.contentPadding,
|
||||||
child: Column(
|
child: BalanceSourceBody(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
title: title,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
subtitle: subtitle,
|
||||||
children: [
|
badge: badge,
|
||||||
BalanceHeader(title: title, subtitle: subtitle, badge: badge),
|
amount: amount,
|
||||||
Row(
|
refreshButton: refreshButton,
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
actions: actions,
|
||||||
children: [
|
copyLabel: copyLabel,
|
||||||
Expanded(child: amount),
|
canCopy: canCopy,
|
||||||
const SizedBox(width: 12),
|
onCopy: onCopy,
|
||||||
actions,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class BalanceAmountWithRefresh extends StatelessWidget {
|
||||||
|
final Widget amount;
|
||||||
|
final Widget refreshButton;
|
||||||
|
|
||||||
|
const BalanceAmountWithRefresh({
|
||||||
|
super.key,
|
||||||
|
required this.amount,
|
||||||
|
required this.refreshButton,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final colorScheme = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
IconButtonTheme(
|
||||||
|
data: IconButtonThemeData(
|
||||||
|
style: IconButton.styleFrom(
|
||||||
|
minimumSize: const Size(30, 30),
|
||||||
|
maximumSize: const Size(40, 40),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
foregroundColor: colorScheme.primary,
|
||||||
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: refreshButton,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
amount,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class BalanceCopyableField extends StatelessWidget {
|
||||||
|
final String label;
|
||||||
|
final bool canCopy;
|
||||||
|
final VoidCallback? onCopy;
|
||||||
|
|
||||||
|
const BalanceCopyableField({
|
||||||
|
super.key,
|
||||||
|
required this.label,
|
||||||
|
required this.canCopy,
|
||||||
|
required this.onCopy,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final colorScheme = theme.colorScheme;
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: colorScheme.onSecondary,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(color: colorScheme.primaryFixed, width: 0.6),
|
||||||
|
),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: canCopy ? onCopy : null,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.copy_rounded,
|
||||||
|
size: 16,
|
||||||
|
color: canCopy
|
||||||
|
? colorScheme.primaryFixed
|
||||||
|
: colorScheme.primary.withValues(alpha: 0.35),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: theme.textTheme.labelMedium?.copyWith(
|
||||||
|
color: canCopy
|
||||||
|
? colorScheme.primaryFixed
|
||||||
|
: colorScheme.primary.withValues(alpha: 0.45),
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/header.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/source/layout/amount_with_refresh.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/source/layout/copyable_field.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class BalanceSourceBody extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final String? subtitle;
|
||||||
|
final String? badge;
|
||||||
|
final Widget amount;
|
||||||
|
final Widget refreshButton;
|
||||||
|
final Widget actions;
|
||||||
|
final String copyLabel;
|
||||||
|
final bool canCopy;
|
||||||
|
final VoidCallback? onCopy;
|
||||||
|
|
||||||
|
const BalanceSourceBody({
|
||||||
|
super.key,
|
||||||
|
required this.title,
|
||||||
|
required this.subtitle,
|
||||||
|
required this.badge,
|
||||||
|
required this.amount,
|
||||||
|
required this.refreshButton,
|
||||||
|
required this.actions,
|
||||||
|
required this.copyLabel,
|
||||||
|
required this.canCopy,
|
||||||
|
required this.onCopy,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
final sideMaxWidth = constraints.maxWidth * 0.30;
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
fit: FlexFit.loose,
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(maxWidth: sideMaxWidth),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
BalanceHeader(
|
||||||
|
title: title,
|
||||||
|
subtitle: subtitle,
|
||||||
|
badge: badge,
|
||||||
|
),
|
||||||
|
SizedBox(height: constraints.maxHeight * 0.06),
|
||||||
|
BalanceCopyableField(
|
||||||
|
label: copyLabel,
|
||||||
|
canCopy: canCopy,
|
||||||
|
onCopy: onCopy,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: FittedBox(
|
||||||
|
fit: BoxFit.scaleDown,
|
||||||
|
child: BalanceAmountWithRefresh(
|
||||||
|
amount: amount,
|
||||||
|
refreshButton: refreshButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
fit: FlexFit.loose,
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(maxWidth: sideMaxWidth),
|
||||||
|
child: SizedBox(height: constraints.maxHeight, child: actions),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,11 +7,12 @@ import 'package:pshared/models/ledger/account.dart';
|
|||||||
import 'package:pshared/provider/ledger.dart';
|
import 'package:pshared/provider/ledger.dart';
|
||||||
import 'package:pshared/models/payment/wallet.dart';
|
import 'package:pshared/models/payment/wallet.dart';
|
||||||
|
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/carousel.dart';
|
import 'package:pweb/pages/dashboard/buttons/balance/carousel/carousel.dart';
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/controller.dart';
|
import 'package:pweb/controllers/dashboard/balance/carousel.dart';
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
|
|
||||||
class BalanceWidget extends StatelessWidget {
|
class BalanceWidget extends StatelessWidget {
|
||||||
final ValueChanged<Wallet> onTopUp;
|
final ValueChanged<Wallet> onTopUp;
|
||||||
final ValueChanged<LedgerAccount> onLedgerAddFunds;
|
final ValueChanged<LedgerAccount> onLedgerAddFunds;
|
||||||
@@ -46,9 +47,7 @@ class BalanceWidget extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final carouselWidget = BalanceCarousel(
|
final carouselWidget = BalanceCarousel(
|
||||||
items: carousel.items,
|
controller: carousel,
|
||||||
currentIndex: carousel.index,
|
|
||||||
onIndexChanged: carousel.onPageChanged,
|
|
||||||
onTopUp: onTopUp,
|
onTopUp: onTopUp,
|
||||||
onLedgerAddFunds: onLedgerAddFunds,
|
onLedgerAddFunds: onLedgerAddFunds,
|
||||||
onWalletTap: onWalletTap,
|
onWalletTap: onWalletTap,
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import 'package:pshared/controllers/payment/source.dart';
|
|||||||
import 'package:pshared/provider/payment/amount.dart';
|
import 'package:pshared/provider/payment/amount.dart';
|
||||||
|
|
||||||
import 'package:pweb/controllers/payments/amount_field.dart';
|
import 'package:pweb/controllers/payments/amount_field.dart';
|
||||||
import 'package:pweb/pages/dashboard/payouts/amount/feild.dart';
|
import 'package:pweb/pages/dashboard/payouts/amount/field.dart';
|
||||||
|
|
||||||
|
|
||||||
class PaymentAmountWidget extends StatelessWidget {
|
class PaymentAmountWidget extends StatelessWidget {
|
||||||
const PaymentAmountWidget({super.key});
|
const PaymentAmountWidget({super.key});
|
||||||
|
|||||||
Reference in New Issue
Block a user