WIP address details

This commit is contained in:
julian 2023-03-21 17:18:07 -06:00
parent 172429f94a
commit c35eaf0b0f
10 changed files with 778 additions and 183 deletions

View file

@ -122,7 +122,26 @@ enum AddressType {
cryptonote,
mimbleWimble,
unknown,
nonWallet,
nonWallet;
String get readableName {
switch (this) {
case AddressType.p2pkh:
return "Legacy";
case AddressType.p2sh:
return "Wrapped segwit";
case AddressType.p2wpkh:
return "Segwit";
case AddressType.cryptonote:
return "Cryptonote";
case AddressType.mimbleWimble:
return "Mimble Wimble";
case AddressType.unknown:
return "Unknown";
case AddressType.nonWallet:
return "Non wallet/unknown";
}
}
}
// do not modify
@ -133,7 +152,26 @@ enum AddressSubType {
paynymSend,
paynymReceive,
unknown,
nonWallet,
nonWallet;
String get prettyName {
switch (this) {
case AddressSubType.receiving:
return "Receiving";
case AddressSubType.change:
return "Change";
case AddressSubType.paynymNotification:
return "PayNym Notification";
case AddressSubType.paynymSend:
return "PayNym Send";
case AddressSubType.paynymReceive:
return "PayNym Receiving";
case AddressSubType.unknown:
return "Unknown";
case AddressSubType.nonWallet:
return "Non wallet/unknown";
}
}
}
@Embedded(inheritance: false)

View file

@ -196,7 +196,11 @@ class _SingleFieldEditViewState extends State<SingleFieldEditView> {
}
},
),
)
),
if (!isDesktop)
const SizedBox(
height: 16,
),
],
),
);

View file

@ -1,21 +1,13 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/db/main_db.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/receive_view/addresses/address_qr_popup.dart';
import 'package:stackwallet/pages/receive_view/addresses/edit_address_label_view.dart';
import 'package:stackwallet/pages/receive_view/addresses/address_tag.dart';
import 'package:stackwallet/utilities/clipboard_interface.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/icon_widgets/copy_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
class AddressCard extends StatefulWidget {
@ -24,6 +16,7 @@ class AddressCard extends StatefulWidget {
required this.addressId,
required this.walletId,
required this.coin,
this.onPressed,
this.clipboard = const ClipboardWrapper(),
}) : super(key: key);
@ -31,6 +24,7 @@ class AddressCard extends StatefulWidget {
final String walletId;
final Coin coin;
final ClipboardInterface clipboard;
final VoidCallback? onPressed;
@override
State<AddressCard> createState() => _AddressCardState();
@ -72,106 +66,126 @@ class _AddressCardState extends State<AddressCard> {
@override
Widget build(BuildContext context) {
return RoundedWhiteContainer(
onPressed: widget.onPressed,
child: StreamBuilder<AddressLabel?>(
stream: stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
label = snapshot.data!;
}
stream: stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
label = snapshot.data!;
}
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
label!.value,
style: STextStyles.itemSubtitle(context),
),
CustomTextButton(
text: "Edit label",
textSize: 14,
onTap: () {
Navigator.of(context).pushNamed(
EditAddressLabelView.routeName,
arguments: label!.id,
);
},
),
],
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (label!.value.isNotEmpty)
Text(
label!.value,
style: STextStyles.itemSubtitle(context),
textAlign: TextAlign.left,
),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
//
// CustomTextButton(
// text: "Edit label",
// textSize: 14,
// onTap: () {
// Navigator.of(context).pushNamed(
// EditAddressLabelView.routeName,
// arguments: label!.id,
// );
// },
// ),
// ],
// ),
if (label!.value.isNotEmpty)
const SizedBox(
height: 8,
),
Row(
children: [
Expanded(
child: SelectableText(
address.value,
style: STextStyles.itemSubtitle12(context),
),
)
],
),
const SizedBox(
height: 10,
),
Row(
children: [
Expanded(
child: SecondaryButton(
label: "Copy address",
icon: CopyIcon(
color: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondary,
Row(
children: [
Expanded(
child: SelectableText(
address.value,
style: STextStyles.itemSubtitle12(context),
),
)
],
),
const SizedBox(
height: 10,
),
if (label!.tags != null && label!.tags!.isNotEmpty)
Wrap(
spacing: 10,
runSpacing: 10,
children: label!.tags!
.map(
(e) => AddressTag(
tag: e,
),
onPressed: () async {
await widget.clipboard.setData(
ClipboardData(
text: address.value,
),
);
if (mounted) {
unawaited(
showFloatingFlushBar(
type: FlushBarType.info,
message: "Copied to clipboard",
context: context,
),
);
}
},
),
),
const SizedBox(
width: 12,
),
Expanded(
child: SecondaryButton(
label: "Show QR Code",
icon: QrCodeIcon(
color: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondary,
),
onPressed: () {
showDialog<void>(
context: context,
builder: (context) => AddressQrPopup(
addressString: address.value,
coin: widget.coin,
clipboard: widget.clipboard,
),
);
},
),
),
],
)
],
);
}),
)
.toList(),
),
// Row(
// children: [
// Expanded(
// child: SecondaryButton(
// label: "Copy address",
// icon: CopyIcon(
// color: Theme.of(context)
// .extension<StackColors>()!
// .buttonTextSecondary,
// ),
// onPressed: () async {
// await widget.clipboard.setData(
// ClipboardData(
// text: address.value,
// ),
// );
// if (mounted) {
// unawaited(
// showFloatingFlushBar(
// type: FlushBarType.info,
// message: "Copied to clipboard",
// context: context,
// ),
// );
// }
// },
// ),
// ),
// const SizedBox(
// width: 12,
// ),
// Expanded(
// child: SecondaryButton(
// label: "Show QR Code",
// icon: QrCodeIcon(
// color: Theme.of(context)
// .extension<StackColors>()!
// .buttonTextSecondary,
// ),
// onPressed: () {
// showDialog<void>(
// context: context,
// builder: (context) => AddressQrPopup(
// addressString: address.value,
// coin: widget.coin,
// clipboard: widget.clipboard,
// ),
// );
// },
// ),
// ),
// ],
// )
],
);
},
),
);
}
}

View file

@ -0,0 +1,346 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:isar/isar.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:stackwallet/db/main_db.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/pages/receive_view/addresses/address_tag.dart';
import 'package:stackwallet/pages/wallet_view/sub_widgets/transactions_list.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/utilities/address_utils.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/background.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
import 'package:stackwallet/widgets/custom_buttons/simple_edit_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
class AddressDetailsView extends ConsumerStatefulWidget {
const AddressDetailsView({
Key? key,
required this.addressId,
required this.walletId,
}) : super(key: key);
static const String routeName = "/addressDetailsView";
final Id addressId;
final String walletId;
@override
ConsumerState<AddressDetailsView> createState() => _AddressDetailsViewState();
}
class _AddressDetailsViewState extends ConsumerState<AddressDetailsView> {
final _qrKey = GlobalKey();
final isDesktop = Util.isDesktop;
late Stream<AddressLabel?> stream;
late final Address address;
AddressLabel? label;
@override
void initState() {
address = MainDB.instance.isar.addresses
.where()
.idEqualTo(widget.addressId)
.findFirstSync()!;
label = MainDB.instance.getAddressLabelSync(widget.walletId, address.value);
Id? id = label?.id;
if (id == null) {
label = AddressLabel(
walletId: widget.walletId,
addressString: address.value,
value: "",
tags: address.subType == AddressSubType.receiving
? ["receiving"]
: address.subType == AddressSubType.change
? ["change"]
: null,
);
id = MainDB.instance.putAddressLabelSync(label!);
}
stream = MainDB.instance.watchAddressLabel(id: id);
super.initState();
}
@override
Widget build(BuildContext context) {
final coin = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManager(widget.walletId).coin));
return ConditionalParent(
condition: !isDesktop,
builder: (child) => Background(
child: Scaffold(
backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
backgroundColor:
Theme.of(context).extension<StackColors>()!.backgroundAppBar,
leading: AppBarBackButton(
onPressed: () {
Navigator.of(context).pop();
},
),
titleSpacing: 0,
title: Text(
"Wallet addresses",
style: STextStyles.navBarTitle(context),
),
),
body: SafeArea(
child: NestedScrollView(
floatHeaderSlivers: true,
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
context),
sliver: SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.only(
left: 16,
right: 16,
top: 16,
),
child: child,
),
),
)
];
},
body: TransactionsList(
walletId: widget.walletId,
managerProvider: ref.watch(
walletsChangeNotifierProvider.select((value) =>
value.getManagerProvider(widget.walletId)))),
),
),
),
),
child: StreamBuilder<AddressLabel?>(
stream: stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
label = snapshot.data!;
}
return Column(
children: [
Center(
child: RepaintBoundary(
key: _qrKey,
child: QrImage(
data: AddressUtils.buildUriString(
coin,
address.value,
{},
),
size: 220,
backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
foregroundColor: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
),
),
),
const SizedBox(
height: 16,
),
_Item(
title: "Address",
data: address.value,
button: SimpleCopyButton(
data: address.value,
),
),
const SizedBox(
height: 12,
),
_Item(
title: "Label",
data: label!.value,
button: SimpleEditButton(
editValue: label!.value,
editLabel: 'label',
onValueChanged: (value) {
MainDB.instance.putAddressLabel(
label!.copyWith(
label: value,
),
);
},
),
),
const SizedBox(
height: 12,
),
_Tags(
tags: label!.tags,
),
if (address.derivationPath != null)
const SizedBox(
height: 12,
),
if (address.derivationPath != null)
_Item(
title: "Derivation path",
data: address.derivationPath!.value,
button: SimpleEditButton(
editValue: label!.value,
editLabel: 'label',
onValueChanged: (value) {
MainDB.instance.putAddressLabel(
label!.copyWith(
label: value,
),
);
},
),
),
const SizedBox(
height: 12,
),
_Item(
title: "Type",
data: address.type.readableName,
button: Container(),
),
const SizedBox(
height: 12,
),
_Item(
title: "Sub type",
data: address.subType.prettyName,
button: Container(),
),
const SizedBox(
height: 20,
),
Text(
"Transactions",
style: STextStyles.itemSubtitle(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textDark3,
),
),
],
);
},
),
);
}
}
class _Tags extends StatelessWidget {
const _Tags({
Key? key,
required this.tags,
}) : super(key: key);
final List<String>? tags;
@override
Widget build(BuildContext context) {
return RoundedWhiteContainer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Tags",
style: STextStyles.itemSubtitle(context),
),
SimpleEditButton(
onPressedOverride: () {
// TODO edit tags
},
),
],
),
const SizedBox(
height: 8,
),
tags != null && tags!.isNotEmpty
? Wrap(
spacing: 10,
runSpacing: 10,
children: tags!
.map(
(e) => AddressTag(
tag: e,
),
)
.toList(),
)
: Text(
"Tags will appear here",
style: STextStyles.w500_14(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle3,
),
),
],
),
);
}
}
class _Item extends StatelessWidget {
const _Item({
Key? key,
required this.title,
required this.data,
required this.button,
}) : super(key: key);
final String title;
final String data;
final Widget button;
@override
Widget build(BuildContext context) {
return RoundedWhiteContainer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: STextStyles.itemSubtitle(context),
),
button,
],
),
const SizedBox(
height: 5,
),
data.isNotEmpty
? SelectableText(
data,
style: STextStyles.w500_14(context),
)
: Text(
"$title will appear here",
style: STextStyles.w500_14(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle3,
),
),
],
),
);
}
}

View file

@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
import 'package:flutter_native_splash/cli_commands.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/rounded_container.dart';
class AddressTag extends StatelessWidget {
const AddressTag({Key? key, required this.tag}) : super(key: key);
final String tag;
@override
Widget build(BuildContext context) {
return RoundedContainer(
radiusMultiplier: 0.5,
padding: const EdgeInsets.symmetric(
vertical: 5,
horizontal: 7,
),
color: Colors.black,
child: Text(
tag.capitalize(),
style: STextStyles.w500_14(context),
),
);
}
}

View file

@ -1,9 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/db/main_db.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/pages/receive_view/addresses/address_card.dart';
import 'package:stackwallet/pages/receive_view/addresses/address_details_view.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart';
@ -13,7 +15,12 @@ import 'package:stackwallet/widgets/background.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/loading_indicator.dart';
import 'package:stackwallet/widgets/toggle.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:tuple/tuple.dart';
import '../../../utilities/assets.dart';
import '../../../widgets/icon_widgets/x_icon.dart';
import '../../../widgets/textfield_icon_button.dart';
class WalletAddressesView extends ConsumerStatefulWidget {
const WalletAddressesView({
@ -33,7 +40,88 @@ class WalletAddressesView extends ConsumerStatefulWidget {
class _WalletAddressesViewState extends ConsumerState<WalletAddressesView> {
final bool isDesktop = Util.isDesktop;
bool _showChange = false;
String _searchString = "";
late final TextEditingController _searchController;
final searchFieldFocusNode = FocusNode();
Future<List<int>> _search(String term) async {
if (term.isEmpty) {
return MainDB.instance
.getAddresses(widget.walletId)
.filter()
.group((q) => q
.subTypeEqualTo(AddressSubType.change)
.or()
.subTypeEqualTo(AddressSubType.receiving)
.or()
.subTypeEqualTo(AddressSubType.paynymReceive)
.or()
.subTypeEqualTo(AddressSubType.paynymNotification))
.and()
.not()
.typeEqualTo(AddressType.nonWallet)
.sortByDerivationIndex()
.idProperty()
.findAll();
}
final labels = await MainDB.instance
.getAddressLabels(widget.walletId)
.filter()
.group(
(q) => q
.valueContains(term, caseSensitive: false)
.or()
.addressStringContains(term, caseSensitive: false)
.or()
.group(
(q) => q
.tagsIsNotNull()
.and()
.tagsElementContains(term, caseSensitive: false),
),
)
.findAll();
if (labels.isEmpty) {
return [];
}
return MainDB.instance
.getAddresses(widget.walletId)
.filter()
.anyOf<AddressLabel, Address>(
labels, (q, e) => q.valueEqualTo(e.addressString))
.group((q) => q
.subTypeEqualTo(AddressSubType.change)
.or()
.subTypeEqualTo(AddressSubType.receiving)
.or()
.subTypeEqualTo(AddressSubType.paynymReceive)
.or()
.subTypeEqualTo(AddressSubType.paynymNotification))
.and()
.not()
.typeEqualTo(AddressType.nonWallet)
.sortByDerivationIndex()
.idProperty()
.findAll();
}
@override
void initState() {
_searchController = TextEditingController();
super.initState();
}
@override
void dispose() {
_searchController.dispose();
searchFieldFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
@ -68,26 +156,66 @@ class _WalletAddressesViewState extends ConsumerState<WalletAddressesView> {
child: Column(
children: [
SizedBox(
height: isDesktop ? 56 : 48,
width: isDesktop ? 490 : null,
child: Toggle(
key: UniqueKey(),
onColor: Theme.of(context).extension<StackColors>()!.popupBG,
onText: "Receiving",
offColor: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
offText: "Change",
isOn: _showChange,
onValueChanged: (value) {
setState(() {
_showChange = value;
});
},
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autocorrect: !isDesktop,
enableSuggestions: !isDesktop,
controller: _searchController,
focusNode: searchFieldFocusNode,
onChanged: (value) {
setState(() {
_searchString = value;
});
},
style: isDesktop
? STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
height: 1.8,
)
: STextStyles.field(context),
decoration: standardInputDecoration(
"Search...",
searchFieldFocusNode,
context,
desktopMed: isDesktop,
).copyWith(
prefixIcon: Padding(
padding: EdgeInsets.symmetric(
horizontal: isDesktop ? 12 : 10,
vertical: isDesktop ? 18 : 16,
),
child: SvgPicture.asset(
Assets.svg.search,
width: isDesktop ? 20 : 16,
height: isDesktop ? 20 : 16,
),
),
suffixIcon: _searchController.text.isNotEmpty
? Padding(
padding: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(),
onTap: () async {
setState(() {
_searchController.text = "";
_searchString = "";
});
},
),
],
),
),
)
: null,
),
),
),
@ -97,23 +225,7 @@ class _WalletAddressesViewState extends ConsumerState<WalletAddressesView> {
),
Expanded(
child: FutureBuilder(
future: MainDB.instance
.getAddresses(widget.walletId)
.filter()
.group(
(q) => _showChange
? q.subTypeEqualTo(AddressSubType.change)
: q
.subTypeEqualTo(AddressSubType.receiving)
.or()
.subTypeEqualTo(AddressSubType.paynymReceive),
)
.and()
.not()
.typeEqualTo(AddressType.nonWallet)
.sortByDerivationIndex()
.idProperty()
.findAll(),
future: _search(_searchString),
builder: (context, AsyncSnapshot<List<int>> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.data != null) {
@ -127,6 +239,15 @@ class _WalletAddressesViewState extends ConsumerState<WalletAddressesView> {
walletId: widget.walletId,
addressId: snapshot.data![index],
coin: coin,
onPressed: () {
Navigator.of(context).pushNamed(
AddressDetailsView.routeName,
arguments: Tuple2(
snapshot.data![index],
widget.walletId,
),
);
},
),
);
} else {

View file

@ -48,6 +48,7 @@ import 'package:stackwallet/pages/paynym/add_new_paynym_follow_view.dart';
import 'package:stackwallet/pages/paynym/paynym_claim_view.dart';
import 'package:stackwallet/pages/paynym/paynym_home_view.dart';
import 'package:stackwallet/pages/pinpad_views/create_pin_view.dart';
import 'package:stackwallet/pages/receive_view/addresses/address_details_view.dart';
import 'package:stackwallet/pages/receive_view/addresses/edit_address_label_view.dart';
import 'package:stackwallet/pages/receive_view/addresses/wallet_addresses_view.dart';
import 'package:stackwallet/pages/receive_view/generate_receiving_uri_qr_code_view.dart';
@ -928,6 +929,21 @@ class RouteGenerator {
}
return _routeError("${settings.name} invalid args: ${args.toString()}");
case AddressDetailsView.routeName:
if (args is Tuple2<Id, String>) {
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => AddressDetailsView(
walletId: args.item2,
addressId: args.item1,
),
settings: RouteSettings(
name: settings.name,
),
);
}
return _routeError("${settings.name} invalid args: ${args.toString()}");
case SendView.routeName:
if (args is Tuple2<String, Coin>) {
return getRoute(

View file

@ -221,11 +221,27 @@ class DbVersionMigrator with WalletDB {
final List<isar_models.AddressLabel> labels = [];
for (final address in addresses) {
final tags = address.subType == AddressSubType.receiving
? ["receiving"]
: address.subType == AddressSubType.change
? ["change"]
: null;
List<String>? tags;
switch (address.subType) {
case AddressSubType.receiving:
tags = ["receiving"];
break;
case AddressSubType.change:
tags = ["change"];
break;
case AddressSubType.paynymNotification:
tags = ["paynym notification"];
break;
case AddressSubType.paynymSend:
break;
case AddressSubType.paynymReceive:
tags = ["paynym receiving"];
break;
case AddressSubType.unknown:
break;
case AddressSubType.nonWallet:
break;
}
// update/create label if tags is not empty
if (tags != null) {

View file

@ -13,14 +13,23 @@ import '../icon_widgets/pencil_icon.dart';
class SimpleEditButton extends StatelessWidget {
const SimpleEditButton({
Key? key,
required this.editValue,
required this.editLabel,
required this.onValueChanged,
}) : super(key: key);
this.editValue,
this.editLabel,
this.onValueChanged,
this.onPressedOverride,
}) : assert(
(editLabel != null && editValue != null && onValueChanged != null) ||
(editLabel == null &&
editValue == null &&
onValueChanged == null &&
onPressedOverride != null),
),
super(key: key);
final String editValue;
final String editLabel;
final void Function(String) onValueChanged;
final String? editValue;
final String? editLabel;
final void Function(String)? onValueChanged;
final VoidCallback? onPressedOverride;
@override
Widget build(BuildContext context) {
@ -36,24 +45,25 @@ class SimpleEditButton extends StatelessWidget {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
onPressed: () async {
final result = await showDialog<String?>(
context: context,
builder: (context) {
return DesktopDialog(
maxWidth: 580,
maxHeight: 360,
child: SingleFieldEditView(
initialValue: editValue,
label: editLabel,
),
onPressed: onPressedOverride ??
() async {
final result = await showDialog<String?>(
context: context,
builder: (context) {
return DesktopDialog(
maxWidth: 580,
maxHeight: 360,
child: SingleFieldEditView(
initialValue: editValue!,
label: editLabel!,
),
);
},
);
if (result is String && result != editValue!) {
onValueChanged?.call(result);
}
},
);
if (result is String && result != editValue) {
onValueChanged(result);
}
},
child: Padding(
padding: const EdgeInsets.all(5),
child: PencilIcon(
@ -66,18 +76,19 @@ class SimpleEditButton extends StatelessWidget {
);
} else {
return GestureDetector(
onTap: () async {
final result = await Navigator.of(context).pushNamed(
SingleFieldEditView.routeName,
arguments: Tuple2(
editValue,
editLabel,
),
);
if (result is String && result != editValue) {
onValueChanged(result);
}
},
onTap: onPressedOverride ??
() async {
final result = await Navigator.of(context).pushNamed(
SingleFieldEditView.routeName,
arguments: Tuple2(
editValue!,
editLabel!,
),
);
if (result is String && result != editValue!) {
onValueChanged?.call(result);
}
},
child: Row(
children: [
SvgPicture.asset(

View file

@ -12,6 +12,7 @@ class RoundedWhiteContainer extends StatelessWidget {
this.height,
this.borderColor,
this.boxShadow,
this.onPressed,
}) : super(key: key);
final Widget? child;
@ -21,6 +22,7 @@ class RoundedWhiteContainer extends StatelessWidget {
final double? height;
final Color? borderColor;
final List<BoxShadow>? boxShadow;
final VoidCallback? onPressed;
@override
Widget build(BuildContext context) {
@ -32,6 +34,7 @@ class RoundedWhiteContainer extends StatelessWidget {
height: height,
borderColor: borderColor,
boxShadow: boxShadow,
onPressed: onPressed,
child: child,
);
}