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, cryptonote,
mimbleWimble, mimbleWimble,
unknown, 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 // do not modify
@ -133,7 +152,26 @@ enum AddressSubType {
paynymSend, paynymSend,
paynymReceive, paynymReceive,
unknown, 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) @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 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stackwallet/db/main_db.dart'; import 'package:stackwallet/db/main_db.dart';
import 'package:stackwallet/models/isar/models/isar_models.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_tag.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/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.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'; import 'package:stackwallet/widgets/rounded_white_container.dart';
class AddressCard extends StatefulWidget { class AddressCard extends StatefulWidget {
@ -24,6 +16,7 @@ class AddressCard extends StatefulWidget {
required this.addressId, required this.addressId,
required this.walletId, required this.walletId,
required this.coin, required this.coin,
this.onPressed,
this.clipboard = const ClipboardWrapper(), this.clipboard = const ClipboardWrapper(),
}) : super(key: key); }) : super(key: key);
@ -31,6 +24,7 @@ class AddressCard extends StatefulWidget {
final String walletId; final String walletId;
final Coin coin; final Coin coin;
final ClipboardInterface clipboard; final ClipboardInterface clipboard;
final VoidCallback? onPressed;
@override @override
State<AddressCard> createState() => _AddressCardState(); State<AddressCard> createState() => _AddressCardState();
@ -72,106 +66,126 @@ class _AddressCardState extends State<AddressCard> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return RoundedWhiteContainer( return RoundedWhiteContainer(
onPressed: widget.onPressed,
child: StreamBuilder<AddressLabel?>( child: StreamBuilder<AddressLabel?>(
stream: stream, stream: stream,
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData) { if (snapshot.hasData) {
label = snapshot.data!; label = snapshot.data!;
} }
return Column( return Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
Row( children: [
mainAxisAlignment: MainAxisAlignment.spaceBetween, if (label!.value.isNotEmpty)
children: [ Text(
Text( label!.value,
label!.value, style: STextStyles.itemSubtitle(context),
style: STextStyles.itemSubtitle(context), textAlign: TextAlign.left,
),
CustomTextButton(
text: "Edit label",
textSize: 14,
onTap: () {
Navigator.of(context).pushNamed(
EditAddressLabelView.routeName,
arguments: label!.id,
);
},
),
],
), ),
// 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( const SizedBox(
height: 8, height: 8,
), ),
Row( Row(
children: [ children: [
Expanded( Expanded(
child: SelectableText( child: SelectableText(
address.value, address.value,
style: STextStyles.itemSubtitle12(context), style: STextStyles.itemSubtitle12(context),
), ),
) )
], ],
), ),
const SizedBox( const SizedBox(
height: 10, height: 10,
), ),
Row(
children: [ if (label!.tags != null && label!.tags!.isNotEmpty)
Expanded( Wrap(
child: SecondaryButton( spacing: 10,
label: "Copy address", runSpacing: 10,
icon: CopyIcon( children: label!.tags!
color: Theme.of(context) .map(
.extension<StackColors>()! (e) => AddressTag(
.buttonTextSecondary, tag: e,
), ),
onPressed: () async { )
await widget.clipboard.setData( .toList(),
ClipboardData( ),
text: address.value, // Row(
), // children: [
); // Expanded(
if (mounted) { // child: SecondaryButton(
unawaited( // label: "Copy address",
showFloatingFlushBar( // icon: CopyIcon(
type: FlushBarType.info, // color: Theme.of(context)
message: "Copied to clipboard", // .extension<StackColors>()!
context: context, // .buttonTextSecondary,
), // ),
); // onPressed: () async {
} // await widget.clipboard.setData(
}, // ClipboardData(
), // text: address.value,
), // ),
const SizedBox( // );
width: 12, // if (mounted) {
), // unawaited(
Expanded( // showFloatingFlushBar(
child: SecondaryButton( // type: FlushBarType.info,
label: "Show QR Code", // message: "Copied to clipboard",
icon: QrCodeIcon( // context: context,
color: Theme.of(context) // ),
.extension<StackColors>()! // );
.buttonTextSecondary, // }
), // },
onPressed: () { // ),
showDialog<void>( // ),
context: context, // const SizedBox(
builder: (context) => AddressQrPopup( // width: 12,
addressString: address.value, // ),
coin: widget.coin, // Expanded(
clipboard: widget.clipboard, // 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/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stackwallet/db/main_db.dart'; import 'package:stackwallet/db/main_db.dart';
import 'package:stackwallet/models/isar/models/isar_models.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_card.dart';
import 'package:stackwallet/pages/receive_view/addresses/address_details_view.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.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/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/loading_indicator.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 { class WalletAddressesView extends ConsumerStatefulWidget {
const WalletAddressesView({ const WalletAddressesView({
@ -33,7 +40,88 @@ class WalletAddressesView extends ConsumerStatefulWidget {
class _WalletAddressesViewState extends ConsumerState<WalletAddressesView> { class _WalletAddressesViewState extends ConsumerState<WalletAddressesView> {
final bool isDesktop = Util.isDesktop; 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -68,26 +156,66 @@ class _WalletAddressesViewState extends ConsumerState<WalletAddressesView> {
child: Column( child: Column(
children: [ children: [
SizedBox( SizedBox(
height: isDesktop ? 56 : 48,
width: isDesktop ? 490 : null, width: isDesktop ? 490 : null,
child: Toggle( child: ClipRRect(
key: UniqueKey(), borderRadius: BorderRadius.circular(
onColor: Theme.of(context).extension<StackColors>()!.popupBG, Constants.size.circularBorderRadius,
onText: "Receiving", ),
offColor: Theme.of(context) child: TextField(
.extension<StackColors>()! autocorrect: !isDesktop,
.textFieldDefaultBG, enableSuggestions: !isDesktop,
offText: "Change", controller: _searchController,
isOn: _showChange, focusNode: searchFieldFocusNode,
onValueChanged: (value) { onChanged: (value) {
setState(() { setState(() {
_showChange = value; _searchString = value;
}); });
}, },
decoration: BoxDecoration( style: isDesktop
color: Colors.transparent, ? STextStyles.desktopTextExtraSmall(context).copyWith(
borderRadius: BorderRadius.circular( color: Theme.of(context)
Constants.size.circularBorderRadius, .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( Expanded(
child: FutureBuilder( child: FutureBuilder(
future: MainDB.instance future: _search(_searchString),
.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(),
builder: (context, AsyncSnapshot<List<int>> snapshot) { builder: (context, AsyncSnapshot<List<int>> snapshot) {
if (snapshot.connectionState == ConnectionState.done && if (snapshot.connectionState == ConnectionState.done &&
snapshot.data != null) { snapshot.data != null) {
@ -127,6 +239,15 @@ class _WalletAddressesViewState extends ConsumerState<WalletAddressesView> {
walletId: widget.walletId, walletId: widget.walletId,
addressId: snapshot.data![index], addressId: snapshot.data![index],
coin: coin, coin: coin,
onPressed: () {
Navigator.of(context).pushNamed(
AddressDetailsView.routeName,
arguments: Tuple2(
snapshot.data![index],
widget.walletId,
),
);
},
), ),
); );
} else { } 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_claim_view.dart';
import 'package:stackwallet/pages/paynym/paynym_home_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/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/edit_address_label_view.dart';
import 'package:stackwallet/pages/receive_view/addresses/wallet_addresses_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'; 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()}"); 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: case SendView.routeName:
if (args is Tuple2<String, Coin>) { if (args is Tuple2<String, Coin>) {
return getRoute( return getRoute(

View file

@ -221,11 +221,27 @@ class DbVersionMigrator with WalletDB {
final List<isar_models.AddressLabel> labels = []; final List<isar_models.AddressLabel> labels = [];
for (final address in addresses) { for (final address in addresses) {
final tags = address.subType == AddressSubType.receiving List<String>? tags;
? ["receiving"] switch (address.subType) {
: address.subType == AddressSubType.change case AddressSubType.receiving:
? ["change"] tags = ["receiving"];
: null; 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 // update/create label if tags is not empty
if (tags != null) { if (tags != null) {

View file

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

View file

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