mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
ui: add copy button
This commit is contained in:
@@ -4,6 +4,7 @@ import 'package:cake_wallet/utils/image_utill.dart';
|
||||
import 'package:cake_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({
|
||||
@@ -39,18 +40,36 @@ class CakePayTransactionSentBottomSheet extends StatelessWidget {
|
||||
final String paymentId;
|
||||
final String paymentIdValue;
|
||||
|
||||
TextStyle _titleStyle(BuildContext ctx) => Theme.of(ctx).textTheme.bodyLarge!;
|
||||
TextStyle _titleStyle(BuildContext ctx) =>
|
||||
Theme
|
||||
.of(ctx)
|
||||
.textTheme
|
||||
.bodyLarge!;
|
||||
|
||||
TextStyle _valueStyle(BuildContext ctx) => Theme.of(ctx).textTheme.titleMedium!.copyWith(
|
||||
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,
|
||||
TextStyle _subStyle(BuildContext ctx) =>
|
||||
Theme
|
||||
.of(ctx)
|
||||
.textTheme
|
||||
.labelSmall!
|
||||
.copyWith(
|
||||
color: Theme
|
||||
.of(ctx)
|
||||
.colorScheme
|
||||
.onSurfaceVariant,
|
||||
);
|
||||
|
||||
Widget _buildHeader(BuildContext ctx) => Column(
|
||||
Widget _buildHeader(BuildContext ctx) =>
|
||||
Column(
|
||||
children: [
|
||||
const SizedBox(height: 12),
|
||||
Container(
|
||||
@@ -58,7 +77,10 @@ class CakePayTransactionSentBottomSheet extends StatelessWidget {
|
||||
height: 5,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
color: Theme.of(ctx).colorScheme.onSurface,
|
||||
color: Theme
|
||||
.of(ctx)
|
||||
.colorScheme
|
||||
.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
@@ -69,11 +91,15 @@ class CakePayTransactionSentBottomSheet extends StatelessWidget {
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
titleText,
|
||||
style: Theme.of(ctx).textTheme.titleLarge!.copyWith(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
style: Theme
|
||||
.of(ctx)
|
||||
.textTheme
|
||||
.titleLarge!
|
||||
.copyWith(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -81,7 +107,8 @@ class CakePayTransactionSentBottomSheet extends StatelessWidget {
|
||||
],
|
||||
);
|
||||
|
||||
Widget _buildBody(BuildContext context) => Padding(
|
||||
Widget _buildBody(BuildContext context) =>
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -112,25 +139,49 @@ class CakePayTransactionSentBottomSheet extends StatelessWidget {
|
||||
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: [
|
||||
Text(paymentId + ': ' + paymentIdValue,
|
||||
style: Theme.of(context).textTheme.bodyLarge, textAlign: TextAlign.center),
|
||||
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,
|
||||
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,
|
||||
text: S
|
||||
.of(context)
|
||||
.close,
|
||||
color: Theme
|
||||
.of(context)
|
||||
.colorScheme
|
||||
.primary,
|
||||
textColor: Theme
|
||||
.of(context)
|
||||
.colorScheme
|
||||
.onPrimaryContainer,
|
||||
onPressed: onClose,
|
||||
),
|
||||
],
|
||||
@@ -142,12 +193,18 @@ class CakePayTransactionSentBottomSheet extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final maxHeight = MediaQuery.of(context).size.height * 0.9;
|
||||
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,
|
||||
color: Theme
|
||||
.of(context)
|
||||
.colorScheme
|
||||
.surface,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: maxHeight),
|
||||
child: SingleChildScrollView(
|
||||
@@ -174,6 +231,8 @@ class _StandardTile extends StatelessWidget {
|
||||
this.itemSubTitle,
|
||||
this.itemSubTitleStyle,
|
||||
this.imagePath,
|
||||
this.copyButton = false,
|
||||
this.copyButtonOnPressed,
|
||||
});
|
||||
|
||||
final String itemTitle;
|
||||
@@ -183,6 +242,8 @@ class _StandardTile extends StatelessWidget {
|
||||
final String? itemSubTitle;
|
||||
final TextStyle? itemSubTitleStyle;
|
||||
final String? imagePath;
|
||||
final bool copyButton;
|
||||
final VoidCallback? copyButtonOnPressed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -193,12 +254,17 @@ class _StandardTile extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: Theme.of(context).colorScheme.surfaceContainerLowest.withAlpha(80)),
|
||||
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(
|
||||
@@ -216,10 +282,19 @@ class _StandardTile extends StatelessWidget {
|
||||
itemTitle,
|
||||
style: titleStyle,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
maxLines: 2,
|
||||
softWrap: true,
|
||||
)),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
if (copyButton)
|
||||
RoundedIconButton(
|
||||
icon: Icons.copy_all_outlined,
|
||||
onPressed: copyButtonOnPressed ?? () {},
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -237,3 +312,41 @@ class _StandardTile extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RoundedIconButton extends StatelessWidget {
|
||||
const RoundedIconButton({this.icon,
|
||||
this.iconWidget,
|
||||
required this.onPressed,
|
||||
this.shape,
|
||||
this.width,
|
||||
this.height,
|
||||
this.iconSize,
|
||||
this.fillColor});
|
||||
|
||||
final IconData? icon;
|
||||
final Widget? iconWidget;
|
||||
final VoidCallback onPressed;
|
||||
final ShapeBorder? shape;
|
||||
final double? width;
|
||||
final double? height;
|
||||
final double? iconSize;
|
||||
final Color? fillColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme
|
||||
.of(context)
|
||||
.colorScheme;
|
||||
return RawMaterialButton(
|
||||
onPressed: onPressed,
|
||||
fillColor: fillColor ?? colorScheme.surfaceContainerHighest,
|
||||
elevation: 0,
|
||||
constraints: BoxConstraints.tightFor(width: width ?? 30, height: height ?? 30),
|
||||
padding: EdgeInsets.zero,
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
shape: shape ?? const CircleBorder(),
|
||||
child: icon != null
|
||||
? Icon(icon, size: iconSize ?? 14, color: colorScheme.onSurface)
|
||||
: iconWidget);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ 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';
|
||||
@@ -45,7 +46,7 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
|
||||
_currentTheme = currentTheme,
|
||||
super(
|
||||
titleText: titleText,
|
||||
maxHeight: 900,
|
||||
maxHeight: 900,
|
||||
titleIconPath: titleIconPath,
|
||||
currentTheme: currentTheme,
|
||||
footerType: footerType,
|
||||
@@ -115,6 +116,7 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet {
|
||||
itemSubTitleTextStyle: itemSubTitleTextStyle,
|
||||
tileBackgroundColor: tileBackgroundColor,
|
||||
applyAddressFormatting: false,
|
||||
copyButton: true,
|
||||
)),
|
||||
),
|
||||
if (explanation != null)
|
||||
@@ -307,20 +309,20 @@ class StandardInfoTile extends StatelessWidget {
|
||||
}
|
||||
|
||||
class AddressTile extends StatelessWidget {
|
||||
const AddressTile({
|
||||
super.key,
|
||||
required this.itemTitle,
|
||||
required this.itemTitleTextStyle,
|
||||
required this.address,
|
||||
required this.itemSubTitleTextStyle,
|
||||
required this.tileBackgroundColor,
|
||||
required this.walletType,
|
||||
this.amountTextStyle,
|
||||
this.applyAddressFormatting = true,
|
||||
this.imagePath,
|
||||
this.amount,
|
||||
this.itemSubTitle,
|
||||
});
|
||||
const AddressTile(
|
||||
{super.key,
|
||||
required this.itemTitle,
|
||||
required this.itemTitleTextStyle,
|
||||
required this.address,
|
||||
required this.itemSubTitleTextStyle,
|
||||
required this.tileBackgroundColor,
|
||||
required this.walletType,
|
||||
this.amountTextStyle,
|
||||
this.applyAddressFormatting = true,
|
||||
this.imagePath,
|
||||
this.amount,
|
||||
this.itemSubTitle,
|
||||
this.copyButton = false});
|
||||
|
||||
final String itemTitle;
|
||||
final TextStyle itemTitleTextStyle;
|
||||
@@ -333,6 +335,7 @@ class AddressTile extends StatelessWidget {
|
||||
final bool applyAddressFormatting;
|
||||
final String? imagePath;
|
||||
final String? itemSubTitle;
|
||||
final bool copyButton;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -387,9 +390,24 @@ class AddressTile extends StatelessWidget {
|
||||
fontWeight: FontWeight.w600,
|
||||
decoration: TextDecoration.none,
|
||||
))
|
||||
: Text(
|
||||
address,
|
||||
style: itemTitleTextStyle,
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(address,
|
||||
style: copyButton
|
||||
? itemTitleTextStyle.copyWith(fontSize: 12)
|
||||
: itemTitleTextStyle),
|
||||
SizedBox(width: 8),
|
||||
if (copyButton)
|
||||
RoundedIconButton(
|
||||
icon: Icons.copy_all_outlined,
|
||||
onPressed: () async =>
|
||||
await Clipboard.setData(ClipboardData(text: address)),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
itemSubTitle == null
|
||||
? Container()
|
||||
@@ -490,3 +508,40 @@ class ExpansionAddressTile extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RoundedIconButton extends StatelessWidget {
|
||||
const RoundedIconButton(
|
||||
{this.icon,
|
||||
this.iconWidget,
|
||||
required this.onPressed,
|
||||
this.shape,
|
||||
this.width,
|
||||
this.height,
|
||||
this.iconSize,
|
||||
this.fillColor});
|
||||
|
||||
final IconData? icon;
|
||||
final Widget? iconWidget;
|
||||
final VoidCallback onPressed;
|
||||
final ShapeBorder? shape;
|
||||
final double? width;
|
||||
final double? height;
|
||||
final double? iconSize;
|
||||
final Color? fillColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return RawMaterialButton(
|
||||
onPressed: onPressed,
|
||||
fillColor: fillColor ?? colorScheme.surfaceContainerHighest,
|
||||
elevation: 0,
|
||||
constraints: BoxConstraints.tightFor(width: width ?? 30, height: height ?? 30),
|
||||
padding: EdgeInsets.zero,
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
shape: shape ?? const CircleBorder(),
|
||||
child: icon != null
|
||||
? Icon(icon, size: iconSize ?? 14, color: colorScheme.onSurface)
|
||||
: iconWidget);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user