refactor: delete dead Cake Pay/buy/exchange code; split di setup()

- Cake Pay: 36 files (~5.3k LOC) plus DI registrations, routes, and UI
  branches (feature was hard-disabled and unreachable)
- unreachable buy providers: robinhood, dfx, onramper, meld, kryptonim
  (~1.7k LOC); MoonPay untouched
- exchange providers that only existed as commented-out wiring:
  changenow, sideshift, chainflip, exolix, swaptrade, letsexchange,
  stealthex, xoswap, swapsxyz, thorchain, simpleswap (~5.2k LOC);
  Trocador untouched; ExchangeProviderDescription values and Hive
  adapters kept so stored trades and orders still deserialize
- di.dart setup() split from one 1,452-line function into 10 sequential
  chunk functions; registration execution order verified identical
  before and after (251 register calls)
This commit is contained in:
jwinterm
2026-08-15 16:29:03 -04:00
parent 71706314fb
commit adece963c3
75 changed files with 74 additions and 13200 deletions
@@ -14,7 +14,6 @@ import 'package:hash_wallet/src/widgets/vulnerable_seeds_popup.dart';
import 'package:hash_wallet/utils/device_info.dart';
import 'package:hash_wallet/utils/feature_flag.dart';
import 'package:hash_wallet/utils/version_comparator.dart';
import 'package:hash_wallet/view_model/dashboard/cake_features_view_model.dart';
import 'package:hash_wallet/generated/i18n.dart';
import 'package:hash_wallet/routes.dart';
import 'package:hash_wallet/src/screens/yat_emoji_id.dart';
@@ -327,7 +326,6 @@ class _DashboardPageView extends BasePage {
label: S.of(context).apps,
child: CakeFeaturesPage(
dashboardViewModel: dashboardViewModel,
cakeFeaturesViewModel: getIt.get<CakeFeaturesViewModel>(),
),
),
);
@@ -1,9 +1,7 @@
import 'package:hash_wallet/di.dart';
import 'package:hash_wallet/entities/main_actions.dart';
import 'package:hash_wallet/src/screens/dashboard/desktop_widgets/desktop_action_button.dart';
import 'package:hash_wallet/src/screens/dashboard/pages/cake_features_page.dart';
import 'package:hash_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:hash_wallet/view_model/dashboard/cake_features_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -75,7 +73,6 @@ class DesktopDashboardActions extends StatelessWidget {
Expanded(
child: CakeFeaturesPage(
dashboardViewModel: dashboardViewModel,
cakeFeaturesViewModel: getIt.get<CakeFeaturesViewModel>(),
),
),
],
@@ -7,10 +7,8 @@ import 'package:hash_wallet/src/screens/dashboard/widgets/info_card.dart';
import 'package:hash_wallet/src/widgets/alert_with_one_action.dart';
import 'package:hash_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:hash_wallet/src/widgets/dashboard_card_widget.dart';
import 'package:hash_wallet/src/widgets/introducing_card.dart';
import 'package:hash_wallet/src/widgets/standard_switch.dart';
import 'package:hash_wallet/themes/core/theme_extension.dart';
import 'package:hash_wallet/utils/feature_flag.dart';
import 'package:hash_wallet/utils/show_pop_up.dart';
import 'package:hash_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cw_core/wallet_info.dart';
@@ -139,18 +137,6 @@ class CryptoBalanceWidget extends StatelessWidget {
),
],
)),
Observer(
builder: (_) {
if (dashboardViewModel.balanceViewModel.isShowCard && FeatureFlag.isCakePayEnabled) {
return IntroducingCard(
title: S.of(context).introducing_cake_pay,
subTitle: S.of(context).cake_pay_learn_more,
borderColor: Theme.of(context).colorScheme.outline,
closeCard: dashboardViewModel.balanceViewModel.disableIntroCakePayCard);
}
return Container();
},
),
Observer(builder: (_) {
if (!dashboardViewModel.showRepWarning) {
return const SizedBox();
@@ -1,24 +1,17 @@
import 'dart:io';
import 'package:hash_wallet/generated/i18n.dart';
import 'package:hash_wallet/new-ui/widgets/apps_widget.dart';
import 'package:hash_wallet/routes.dart';
import 'package:hash_wallet/src/widgets/hash_image_widget.dart';
import 'package:hash_wallet/src/widgets/dashboard_card_widget.dart';
import 'package:hash_wallet/utils/feature_flag.dart';
import 'package:hash_wallet/view_model/dashboard/cake_features_view_model.dart';
import 'package:hash_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:hash_wallet/src/widgets/gradient_background.dart';
class CakeFeaturesPage extends StatelessWidget {
CakeFeaturesPage({required this.dashboardViewModel, required this.cakeFeaturesViewModel});
CakeFeaturesPage({required this.dashboardViewModel});
final DashboardViewModel dashboardViewModel;
final CakeFeaturesViewModel cakeFeaturesViewModel;
@override
Widget build(BuildContext context) {
@@ -102,23 +95,4 @@ class CakeFeaturesPage extends StatelessWidget {
);
}
void _onCakePayTap(BuildContext context) {
if (Platform.isMacOS) {
_launchUrl("buy.cakepay.com");
} else {
_navigatorToGiftCardsPage(context);
}
}
void _launchUrl(String url) {
try {
launchUrl(Uri.https(url), mode: LaunchMode.externalApplication);
} catch (e) {
printV(e);
}
}
void _navigatorToGiftCardsPage(BuildContext context) {
Navigator.pushNamed(context, Routes.cakePayCardsPage);
}
}
+1 -10
View File
@@ -1,6 +1,4 @@
import 'package:hash_wallet/exchange/exchange_provider_description.dart';
import 'package:hash_wallet/exchange/provider/chainflip_exchange_provider.dart';
import 'package:hash_wallet/exchange/provider/thorchain_exchange.provider.dart';
import 'package:hash_wallet/core/auth_service.dart';
import 'package:hash_wallet/di.dart';
import 'package:hash_wallet/src/screens/exchange/widgets/desktop_exchange_cards_section.dart';
@@ -542,14 +540,7 @@ class ExchangePage extends BasePage {
if (depositAmountController.text != exchangeViewModel.depositAmount &&
depositAmountController.text != S.of(context).all) {
exchangeViewModel.isSendAllEnabled = false;
final isThorChain = exchangeViewModel.selectedProviders
.any((provider) => provider is ThorChainExchangeProvider);
final isChainflip = exchangeViewModel.selectedProviders
.any((provider) => provider is ChainflipExchangeProvider);
_depositAmountDebounce = isThorChain || isChainflip
? Debounce(Duration(milliseconds: 1000))
: Debounce(Duration(milliseconds: 500));
_depositAmountDebounce = Debounce(Duration(milliseconds: 500));
_depositAmountDebounce.run(() {
exchangeViewModel.calculateBestRate();
@@ -1,27 +0,0 @@
import 'package:hash_wallet/cake_pay/src/models/cake_pay_order.dart';
import 'package:hash_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:flutter/material.dart';
class CakePayDetailsListCardItem extends StandartListItem {
CakePayDetailsListCardItem({
required String title,
required String value,
required this.id,
required this.createdAt,
this.price,
this.quantity,
required this.from,
required this.to,
required this.onTap,
required this.cards,
}) : super(title: title, value: value);
final String id;
final String createdAt;
final String? price;
final String? quantity;
final String from;
final String to;
final void Function(BuildContext) onTap;
final List<OrderCard> cards;
}
@@ -1,6 +1,4 @@
import 'package:hash_wallet/src/screens/order_details/cake_pay_detail_list_card_item.dart';
import 'package:hash_wallet/src/screens/trade_details/trade_details_status_item.dart';
import 'package:hash_wallet/src/widgets/cake_pay_order_list_card.dart';
import 'package:hash_wallet/src/widgets/standard_list.dart';
import 'package:hash_wallet/src/widgets/standard_list_status_row.dart';
import 'package:hash_wallet/themes/core/material_base_theme.dart';
@@ -64,21 +62,6 @@ class OrderDetailsPageBodyState extends State<OrderDetailsPageBody> {
return StandardListStatusRow(title: item.title, value: item.value);
}
if (item is CakePayDetailsListCardItem) {
final cardImagePath = (item.cards.isNotEmpty) ? item.cards.first.cardImagePath : null;
return CakePayOrderListCard(
id: item.id,
create: item.createdAt,
price: item.price,
quantity: item.quantity,
pair: '${item.from} → ${item.to}',
currentTheme: widget.currentTheme.type,
onTap: item.onTap,
backgroundImage: cardImagePath,
);
}
if (item is TrackTradeListItem) {
return GestureDetector(
onTap: item.onTap,
@@ -1,338 +0,0 @@
import 'package:hash_wallet/cake_pay/src/widgets/cake_pay_alert_modal.dart';
import 'package:hash_wallet/cake_pay/src/widgets/flip_card_widget.dart';
import 'package:hash_wallet/cake_pay/src/widgets/link_extractor.dart';
import 'package:hash_wallet/generated/i18n.dart';
import 'package:hash_wallet/utils/image_utill.dart';
import 'package:hash_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'base_bottom_sheet_widget.dart';
class CakePayCardInfoBottomSheet extends BaseBottomSheet {
CakePayCardInfoBottomSheet({
required String titleText,
required FooterType footerType,
String? titleIconPath,
String? singleActionButtonText,
VoidCallback? onSingleActionButtonPressed,
Key? singleActionButtonKey,
String? doubleActionLeftButtonText,
String? doubleActionRightButtonText,
VoidCallback? onLeftActionButtonPressed,
VoidCallback? onRightActionButtonPressed,
Key? rightActionButtonKey,
Key? leftActionButtonKey,
required this.onUpdateBalancePressed,
required this.isReloadable,
required this.balance,
this.contentImage,
this.howToUse,
this.applyBoxShadow = false,
Key? key,
}) : super(
titleText: titleText,
maxHeight: 900,
titleIconPath: titleIconPath,
footerType: footerType,
singleActionButtonText: singleActionButtonText,
onSingleActionButtonPressed: onSingleActionButtonPressed,
singleActionButtonKey: singleActionButtonKey,
doubleActionLeftButtonText: doubleActionLeftButtonText,
doubleActionRightButtonText: doubleActionRightButtonText,
onLeftActionButtonPressed: onLeftActionButtonPressed,
onRightActionButtonPressed: onRightActionButtonPressed,
leftActionButtonKey: leftActionButtonKey,
rightActionButtonKey: rightActionButtonKey,
key: key);
final VoidCallback onUpdateBalancePressed;
final String? contentImage;
final String? howToUse;
final bool isReloadable;
final String balance;
final bool applyBoxShadow;
final _cardKey = GlobalKey<FlipCardState>();
@override
Widget contentWidget(BuildContext context) {
final itemTitleTextStyle = Theme.of(context).textTheme.bodyMedium!.copyWith(
fontSize: 16,
fontWeight: FontWeight.w500,
decoration: TextDecoration.none,
);
final itemSubTitleTextStyle = Theme.of(context).textTheme.bodySmall!.copyWith(
fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.onSurfaceVariant,
decoration: TextDecoration.none,
);
final tileBackgroundColor = Theme.of(context).colorScheme.surfaceContainer;
return Column(
mainAxisSize: MainAxisSize.min,
children: [
if (contentImage != null)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Stack(
children: [
Padding(
padding: const EdgeInsets.only(top: 0, left: 16, right: 16, bottom: 16),
child: AspectRatio(
aspectRatio: 1.6,
child: FlipCard(
key: _cardKey,
flipOnTouch: true,
front: _buildCardImage(context, contentImage!, applyBoxShadow),
back: _buildBarcodeSide(context,
cardNumber: '6006491979836784204', pin: '4782'),
),
),
),
Positioned(
bottom: 0,
right: 0,
child: GestureDetector(
onTap: () => _cardKey.currentState?.toggleCard(),
child: Container(
height: 43,
width: 43,
decoration: BoxDecoration(
border: Border.all(color: Colors.white, width: 1),
color: Colors.white.withAlpha(75),
shape: BoxShape.circle,
),
child: Transform.scale(
scale: .8,
child: const ImageIcon(
AssetImage('assets/images/transfer.png'),
color: Colors.white,
),
)),
),
),
],
),
),
Container(),
Text(
'Tap card to show details',
style: itemTitleTextStyle.copyWith(fontSize: 12, fontWeight: FontWeight.w700),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Column(
children: [
const SizedBox(height: 34),
CakePayInfoTile(
isReloadable: isReloadable,
itemValue: balance,
itemTitleTextStyle: itemTitleTextStyle,
itemSubTitleTextStyle: itemSubTitleTextStyle,
tileBackgroundColor: tileBackgroundColor),
const SizedBox(height: 8),
_HowToUseTile(howToUse: howToUse ?? '', tileBackgroundColor: tileBackgroundColor),
const SizedBox(height: 40),
],
),
),
],
);
}
}
class _HowToUseTile extends StatelessWidget {
const _HowToUseTile({required this.howToUse, required this.tileBackgroundColor});
final String howToUse;
final Color tileBackgroundColor;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () => _showHowToUseCard(context: context, howToUse: howToUse),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
decoration:
BoxDecoration(borderRadius: BorderRadius.circular(10), color: tileBackgroundColor),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(S.of(context).how_to_use_card, style: Theme.of(context).textTheme.bodyLarge),
Icon(
Icons.chevron_right_rounded,
color: Theme.of(context).textTheme.titleLarge!.color!,
),
],
)),
);
}
}
class CakePayInfoTile extends StatelessWidget {
const CakePayInfoTile({
super.key,
required this.isReloadable,
required this.itemValue,
required this.itemTitleTextStyle,
this.itemSubTitle,
required this.itemSubTitleTextStyle,
required this.tileBackgroundColor,
});
final bool isReloadable;
final String itemValue;
final TextStyle itemTitleTextStyle;
final String? itemSubTitle;
final TextStyle itemSubTitleTextStyle;
final Color tileBackgroundColor;
@override
Widget build(BuildContext context) {
return Semantics(
container: true,
label: isReloadable ? 'Balance' : 'Total Value',
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
decoration:
BoxDecoration(borderRadius: BorderRadius.circular(10), color: tileBackgroundColor),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(isReloadable ? 'Balance' : 'Total Value', style: itemTitleTextStyle),
Text(itemValue,
style: itemTitleTextStyle.copyWith(fontSize: 18, fontWeight: FontWeight.w600)),
],
),
const SizedBox(height: 14),
Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
child: Text(isReloadable ? 'Top Up Balance' : 'Manually update Balance',
style: itemTitleTextStyle.copyWith(fontSize: 12, fontWeight: FontWeight.w600)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(18),
color: Theme.of(context).dialogBackgroundColor)),
const SizedBox(height: 4),
],
),
),
);
}
}
void _showHowToUseCard({required BuildContext context, String? howToUse}) {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return CakePayAlertModal(
title: S.of(context).how_to_use_card,
content: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
ClickableLinksText(
text: howToUse ?? '',
textStyle: Theme.of(context).textTheme.bodyMedium!,
linkStyle: TextStyle(
color: Theme.of(context).textTheme.titleLarge!.color!,
fontSize: 18,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w400,
),
),
]),
actionTitle: S.current.got_it,
);
});
}
Widget _buildCardImage(BuildContext ctx, String path, bool addShadow) {
final border = BorderRadius.circular(10);
return Container(
decoration: addShadow
? BoxDecoration(
borderRadius: border,
boxShadow: [BoxShadow(color: Colors.black.withAlpha(150), blurRadius: 5)],
)
: null,
child: ClipRRect(
borderRadius: border,
child: Stack(
fit: StackFit.expand,
children: [
Container(color: Theme.of(ctx).cardColor.withAlpha(200)),
ImageUtil.getImageFromPath(
imagePath: path,
fit: BoxFit.cover,
),
],
),
),
);
}
Widget _buildBarcodeSide(BuildContext context, {required String cardNumber, required String pin}) =>
SizedBox.expand(
child: Container(
padding: const EdgeInsets.only(top: 16, left: 24, right: 24, bottom: 34),
decoration: BoxDecoration(
color: Theme.of(context).cardColor.withAlpha(200),
borderRadius: BorderRadius.circular(10),
boxShadow: [BoxShadow(color: Colors.black.withAlpha(150), blurRadius: 5)],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Container(
color: Theme.of(context).textTheme.titleLarge!.color!.withOpacity(.1),
),
),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Gift Card Number',
style: TextStyle(
fontFamily: 'Lato',
fontSize: 10,
fontWeight: FontWeight.w500,
color: Color.fromRGBO(207, 207, 207, 1))),
const SizedBox(height: 4),
Text(cardNumber,
style: TextStyle(
fontFamily: 'Lato',
fontSize: 12,
fontWeight: FontWeight.w900,
color: Color.fromRGBO(146, 146, 146, 1))),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('PIN Number',
style: TextStyle(
fontFamily: 'Lato',
fontSize: 10,
fontWeight: FontWeight.w500,
color: Color.fromRGBO(207, 207, 207, 1))),
const SizedBox(height: 4),
Text(pin,
style: TextStyle(
fontFamily: 'Lato',
fontSize: 12,
fontWeight: FontWeight.w900,
color: Color.fromRGBO(146, 146, 146, 1))),
],
),
],
),
],
),
),
);
@@ -1,315 +0,0 @@
import 'package:hash_wallet/generated/i18n.dart';
import 'package:hash_wallet/src/widgets/primary_button.dart';
import 'package:hash_wallet/src/widgets/rounded_icon_button.dart';
import 'package:hash_wallet/utils/image_utill.dart';
import 'package:hash_wallet/view_model/send/output.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class CakePayTransactionSentBottomSheet extends StatelessWidget {
const CakePayTransactionSentBottomSheet({
super.key,
required this.titleText,
required this.currency,
required this.amount,
required this.amountValue,
required this.fiatAmountValue,
required this.output,
required this.fee,
required this.feeValue,
required this.feeFiatAmount,
this.titleIconWidget,
required this.quantity,
required this.onClose,
required this.paymentId,
required this.paymentIdValue,
});
final String titleText;
final Widget? titleIconWidget;
final CryptoCurrency currency;
final String amount;
final String amountValue;
final String fiatAmountValue;
final Output output;
final String fee;
final String feeValue;
final String feeFiatAmount;
final String quantity;
final VoidCallback onClose;
final String paymentId;
final String paymentIdValue;
TextStyle _titleStyle(BuildContext ctx) =>
Theme
.of(ctx)
.textTheme
.bodyLarge!;
TextStyle _valueStyle(BuildContext ctx) =>
Theme
.of(ctx)
.textTheme
.titleMedium!
.copyWith(
fontSize: 18,
fontWeight: FontWeight.w600,
);
TextStyle _subStyle(BuildContext ctx) =>
Theme
.of(ctx)
.textTheme
.labelSmall!
.copyWith(
color: Theme
.of(ctx)
.colorScheme
.onSurfaceVariant,
);
Widget _buildHeader(BuildContext ctx) =>
Column(
children: [
const SizedBox(height: 12),
Container(
width: 64,
height: 5,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: Theme
.of(ctx)
.colorScheme
.onSurface,
),
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (titleIconWidget != null) titleIconWidget!,
const SizedBox(width: 6),
Text(
titleText,
style: Theme
.of(ctx)
.textTheme
.titleLarge!
.copyWith(
fontSize: 20,
fontWeight: FontWeight.w600,
decoration: TextDecoration.none,
),
),
],
),
const SizedBox(height: 12),
],
);
Widget _buildBody(BuildContext context) =>
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Column(
children: [
_StandardTile(
itemTitle: amount,
titleStyle: _titleStyle(context),
itemValue: '$amountValue ${currency.title}',
itemValueStyle: _valueStyle(context),
itemSubTitle: fiatAmountValue,
itemSubTitleStyle: _subStyle(context),
),
const SizedBox(height: 8),
_StandardTile(
itemTitle: fee,
titleStyle: _titleStyle(context),
itemValue: feeValue,
itemValueStyle: _valueStyle(context),
itemSubTitle: feeFiatAmount,
itemSubTitleStyle: _subStyle(context),
),
const SizedBox(height: 8),
_StandardTile(
itemTitle: output.parsedAddress.profileName,
titleStyle: _titleStyle(context),
itemValue: output.fiatAmount,
itemValueStyle: _valueStyle(context),
itemSubTitle: quantity,
itemSubTitleStyle: _subStyle(context),
imagePath: output.parsedAddress.profileImageUrl,
),
const SizedBox(height: 8),
_StandardTile(
itemTitle: paymentId + ': \n' + paymentIdValue,
titleStyle: _titleStyle(context).copyWith(
fontSize: 14
),
itemValue: '',
itemValueStyle: _valueStyle(context),
copyButton: true,
copyButtonOnPressed: () async =>
await Clipboard.setData(ClipboardData(text: paymentIdValue)),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Column(
children: [
const SizedBox(height: 18),
Image.asset('assets/images/envelope.png'),
const SizedBox(height: 18),
Text(
S
.of(context)
.cake_pay_card_email_delivered_message,
style: Theme
.of(context)
.textTheme
.bodyLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
PrimaryButton(
text: S
.of(context)
.close,
color: Theme
.of(context)
.colorScheme
.primary,
textColor: Theme
.of(context)
.colorScheme
.onPrimaryContainer,
onPressed: onClose,
),
],
),
),
],
),
);
@override
Widget build(BuildContext context) {
final maxHeight = MediaQuery
.of(context)
.size
.height * 0.9;
return ClipRRect(
borderRadius: const BorderRadius.vertical(top: Radius.circular(30)),
child: Material(
color: Theme
.of(context)
.colorScheme
.surface,
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: maxHeight),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_buildHeader(context),
_buildBody(context),
],
),
),
),
),
);
}
}
class _StandardTile extends StatelessWidget {
const _StandardTile({
required this.itemTitle,
required this.titleStyle,
required this.itemValue,
required this.itemValueStyle,
this.itemSubTitle,
this.itemSubTitleStyle,
this.imagePath,
this.copyButton = false,
this.copyButtonOnPressed,
});
final String itemTitle;
final TextStyle titleStyle;
final String itemValue;
final TextStyle itemValueStyle;
final String? itemSubTitle;
final TextStyle? itemSubTitleStyle;
final String? imagePath;
final bool copyButton;
final VoidCallback? copyButtonOnPressed;
@override
Widget build(BuildContext context) {
return Semantics(
container: true,
label: itemTitle,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Theme
.of(context)
.colorScheme
.surfaceContainerLowest
.withAlpha(80)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
mainAxisAlignment: copyButton ? MainAxisAlignment.spaceBetween : MainAxisAlignment.start,
children: [
if (imagePath != null)
Padding(
padding: const EdgeInsets.only(right: 8),
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: ImageUtil.getImageFromPath(
imagePath: imagePath!, height: 40, width: 40),
),
),
Flexible(
child: Padding(
padding: const EdgeInsets.only(right: 8),
child: Text(
itemTitle,
style: titleStyle,
overflow: TextOverflow.ellipsis,
maxLines: 2,
softWrap: true,
)),
),
SizedBox(width: 8),
if (copyButton)
RoundedIconButton(
icon: Icons.copy_all_outlined,
onPressed: copyButtonOnPressed ?? () {},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
Text(itemValue, style: itemValueStyle.copyWith(height: 1.0)),
if (itemSubTitle != null) Text(itemSubTitle!, style: itemSubTitleStyle),
],
),
],
),
),
);
}
}
@@ -5,14 +5,12 @@ import 'package:hash_wallet/src/widgets/rounded_icon_button.dart';
import 'package:hash_wallet/themes/core/theme_extension.dart';
import 'package:hash_wallet/utils/address_formatter.dart';
import 'package:hash_wallet/utils/image_utill.dart';
import 'package:hash_wallet/view_model/cake_pay/cake_pay_buy_card_view_model.dart';
import 'package:hash_wallet/view_model/send/output.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'base_bottom_sheet_widget.dart';
@@ -26,9 +24,6 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
bool isSlideActionEnabled = true,
String? accessibleNavigationModeSlideActionButtonText,
required this.currency,
this.paymentId,
this.paymentIdValue,
this.expirationTime,
required this.amount,
required this.amountValue,
required this.fiatAmountValue,
@@ -41,8 +36,6 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
this.change,
this.explanation,
this.isOpenCryptoPay = false,
this.cakePayBuyCardViewModel,
this.quantity,
Key? key,
}) : showScrollbar = outputs.length > 3,
super(
@@ -58,9 +51,6 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
key: key);
final CryptoCurrency currency;
final String? paymentId;
final String? paymentIdValue;
final String? expirationTime;
final String amount;
final String amountValue;
final String fiatAmountValue;
@@ -71,8 +61,6 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
final WalletType walletType;
final PendingChange? change;
final bool isOpenCryptoPay;
final CakePayBuyCardViewModel? cakePayBuyCardViewModel;
final String? quantity;
final String? explanation;
final AmountParsingProxy? amountParsingProxy;
@@ -103,26 +91,6 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
padding: EdgeInsets.fromLTRB(8, 0, showScrollbar ? 16 : 8, 8),
child: Column(
children: [
if (paymentId != null && paymentIdValue != null && cakePayBuyCardViewModel != null)
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Observer(
builder: (_) => AddressTile(
itemTitle: paymentId!,
itemTitleTextStyle: itemTitleTextStyle,
amountTextStyle: itemSubTitleTextStyle,
walletType: walletType,
amount: expirationTime != null
? S.current.offer_expires_in +
' ${cakePayBuyCardViewModel!.formattedRemainingTime}'
: null,
address: paymentIdValue!,
itemSubTitleTextStyle: itemSubTitleTextStyle,
tileBackgroundColor: tileBackgroundColor,
applyAddressFormatting: false,
copyButton: true,
)),
),
if (explanation != null)
Padding(
padding: const EdgeInsets.only(bottom: 8),
@@ -163,12 +131,11 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
final isBatchSending = outputs.length > 1;
final item = outputs[index];
final contactName = item.parsedAddress.name;
final isCakePayName = contactName == 'Cake Pay';
final batchContactTitle =
'${index + 1}/${outputs.length} - ${contactName.isEmpty ? 'Address' : contactName}';
final _address = item.isParsedAddress ? item.extractedAddress : item.address;
final _amount = '${item.cryptoAmount.replaceAll(',', '.')} ${amountParsingProxy?.getCryptoSymbol(currency) ?? currency.title}';
return isBatchSending || (contactName.isNotEmpty && !isCakePayName)
return isBatchSending || contactName.isNotEmpty
? ExpansionAddressTile(
contactType: isOpenCryptoPay ? 'Open CryptoPay' : S.of(context).contact,
name: isBatchSending ? batchContactTitle : contactName,
@@ -181,15 +148,11 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
tileBackgroundColor: tileBackgroundColor,
)
: AddressTile(
itemTitle: isCakePayName
? item.parsedAddress.profileName
: S.of(context).address,
imagePath: isCakePayName ? item.parsedAddress.profileImageUrl : null,
itemTitle: S.of(context).address,
itemTitleTextStyle: itemTitleTextStyle,
walletType: walletType,
amount: isCakePayName ? item.fiatAmount : _amount,
amount: _amount,
address: _address,
itemSubTitle: isCakePayName ? quantity : null,
itemSubTitleTextStyle: itemSubTitleTextStyle,
tileBackgroundColor: tileBackgroundColor,
);
@@ -1,188 +0,0 @@
import 'package:flutter/material.dart';
import 'package:hash_wallet/themes/core/material_base_theme.dart';
class CakePayOrderListCard extends StatelessWidget {
const CakePayOrderListCard({
Key? key,
required this.id,
required this.create,
this.quantity,
this.price,
required this.pair,
required this.onTap,
required this.currentTheme,
this.backgroundImage,
this.aspectRatio = 16 / 9,
}) : super(key: key);
final String id;
final String create;
final String? quantity;
final String? price;
final String pair;
final ThemeType currentTheme;
final void Function(BuildContext) onTap;
final String? backgroundImage;
final double aspectRatio;
ImageProvider? _imageProviderFor(String? path) {
if (path == null || path.isEmpty) return null;
if (path.startsWith('http://') || path.startsWith('https://')) return NetworkImage(path);
return AssetImage(path);
}
Color _labelBackground(BuildContext context) {
final surface = Theme.of(context).colorScheme.surface;
return surface.withOpacity(0.75);
}
Color _titleLabelBackground(BuildContext context) {
final surface = Theme.of(context).colorScheme.surface;
return surface.withOpacity(0.85);
}
Widget _labelBox(
BuildContext context, {
required String text,
EdgeInsets padding = const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
double radius = 10,
Color? background,
TextStyle? style,
}) {
return Container(
padding: padding,
decoration: BoxDecoration(
color: background ?? _labelBackground(context),
borderRadius: BorderRadius.circular(radius),
),
child: Text(
text,
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: style ??
Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.onSurface,
),
),
);
}
@override
Widget build(BuildContext context) {
final image = _imageProviderFor(backgroundImage);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),
child: InkWell(
borderRadius: BorderRadius.circular(16),
onTap: () => onTap(context),
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: AspectRatio(
aspectRatio: aspectRatio,
child: Stack(
fit: StackFit.expand,
children: [
if (image != null)
Image(image: image, fit: BoxFit.cover)
else
Container(color: Theme.of(context).colorScheme.surfaceContainerHighest),
if (image != null)
Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: [0.0, 0.6, 1.0],
colors: [Colors.transparent, Colors.black26, Colors.black54],
),
),
),
Padding(
padding: const EdgeInsets.all(14.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_labelBox(
context,
text: 'Create • $create',
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
radius: 8,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.w700,
fontSize: 10,
color: Theme.of(context).colorScheme.onSurface,
),
),
const SizedBox(height: 4),
_labelBox(
context,
text: 'Qty • $quantity Total • $price',
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
radius: 8,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.w700,
fontSize: 10,
color: Theme.of(context).colorScheme.onSurface,
),
),
],
),
_labelBox(
context,
text: pair,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
radius: 12,
background: _titleLabelBackground(context),
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w800,
fontSize: 16,
color: Theme.of(context).colorScheme.onSurface,
),
),
],
),
const Spacer(),
_labelBox(
context,
text: 'Order • $id',
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
radius: 10,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w800,
fontSize: 12,
color: Theme.of(context).colorScheme.onSurface,
),
),
],
),
),
IgnorePointer(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(currentTheme == ThemeType.dark ? 0.08 : 0.12),
width: 1,
),
),
),
),
],
),
),
),
),
);
}
}