Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions lib/pages/receive_view/receive_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import '../../wallets/wallet/wallet_mixin_interfaces/multi_address_interface.dar
import '../../wallets/wallet/wallet_mixin_interfaces/mweb_interface.dart';
import '../../wallets/wallet/wallet_mixin_interfaces/spark_interface.dart';
import '../../wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
import '../../widgets/address_label_editor.dart';
import '../../widgets/background.dart';
import '../../widgets/conditional_parent.dart';
import '../../widgets/custom_buttons/app_bar_icon_button.dart';
Expand Down Expand Up @@ -161,8 +162,7 @@ class _ReceiveViewState extends ConsumerState<ReceiveView> {

if (slatepackString == null) return;
if (mounted) {
final wallet =
ref.read(pWallets).getWallet(walletId) as EpiccashWallet;
final wallet = ref.read(pWallets).getWallet(walletId) as EpiccashWallet;

Exception? ex;
final result = await showLoading(
Expand Down Expand Up @@ -792,6 +792,14 @@ class _ReceiveViewState extends ConsumerState<ReceiveView> {
),
),
const SizedBox(height: 12),
RoundedWhiteContainer(
child: AddressLabelEditor(
walletId: walletId,
address: address,
isDesktop: false,
),
),
const SizedBox(height: 12),
PrimaryButton(
label: "Copy address",
onPressed: () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import '../../../../wallets/wallet/wallet_mixin_interfaces/multi_address_interfa
import '../../../../wallets/wallet/wallet_mixin_interfaces/mweb_interface.dart';
import '../../../../wallets/wallet/wallet_mixin_interfaces/spark_interface.dart';
import '../../../../wallets/wallet/wallet_mixin_interfaces/view_only_option_interface.dart';
import '../../../../widgets/address_label_editor.dart';
import '../../../../widgets/conditional_parent.dart';
import '../../../../widgets/custom_buttons/app_bar_icon_button.dart';
import '../../../../widgets/custom_loading_overlay.dart';
Expand Down Expand Up @@ -174,8 +175,7 @@ class _DesktopReceiveState extends ConsumerState<DesktopReceive> {
}

Future<void> _onEpicReceiveSlatePressed() async {
final wallet =
ref.read(pWallets).getWallet(walletId) as EpiccashWallet;
final wallet = ref.read(pWallets).getWallet(walletId) as EpiccashWallet;

Exception? ex;
final result = await showLoading(
Expand Down Expand Up @@ -605,9 +605,11 @@ class _DesktopReceiveState extends ConsumerState<DesktopReceive> {
),
),
),
if (!((isMimblewimblecoin || isEpiccash) && ref.watch(pIsSlatepack(widget.walletId))))
if (!((isMimblewimblecoin || isEpiccash) &&
ref.watch(pIsSlatepack(widget.walletId))))
const SizedBox(height: 20),
if (!((isMimblewimblecoin || isEpiccash) && ref.watch(pIsSlatepack(widget.walletId))))
if (!((isMimblewimblecoin || isEpiccash) &&
ref.watch(pIsSlatepack(widget.walletId))))
ConditionalParent(
condition: showMultiType,
builder: (child) => Column(
Expand Down Expand Up @@ -762,6 +764,28 @@ class _DesktopReceiveState extends ConsumerState<DesktopReceive> {
),
),

const SizedBox(height: 12),
Container(
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(
context,
).extension<StackColors>()!.backgroundAppBar,
width: 1,
),
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
child: RoundedWhiteContainer(
child: AddressLabelEditor(
walletId: walletId,
address: address,
isDesktop: true,
),
),
),

if (canGen) const SizedBox(height: 20),

if (canGen)
Expand All @@ -778,7 +802,8 @@ class _DesktopReceiveState extends ConsumerState<DesktopReceive> {
label: "Generate new address",
),
const SizedBox(height: 20),
if ((isMimblewimblecoin || isEpiccash) && ref.watch(pIsSlatepack(widget.walletId)))
if ((isMimblewimblecoin || isEpiccash) &&
ref.watch(pIsSlatepack(widget.walletId)))
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expand Down Expand Up @@ -909,15 +934,18 @@ class _DesktopReceiveState extends ConsumerState<DesktopReceive> {

// TODO: create transparent button class to account for hover
// Conditional logic for 'Submit' button or QR code
if ((isMimblewimblecoin || isEpiccash) && ref.watch(pIsSlatepack(widget.walletId)))
if ((isMimblewimblecoin || isEpiccash) &&
ref.watch(pIsSlatepack(widget.walletId)))
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: PrimaryButton(
buttonHeight: ButtonHeight.l,
label: "Receive Slatepack",
enabled: _slateToggleFlag,
onPressed: _slateToggleFlag
? (isEpiccash ? _onEpicReceiveSlatePressed : _onReceiveSlatePressed)
? (isEpiccash
? _onEpicReceiveSlatePressed
: _onReceiveSlatePressed)
: null,
),
)
Expand Down
71 changes: 71 additions & 0 deletions lib/providers/wallet/address_label_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:isar_community/isar.dart';

import '../../models/isar/models/address_label.dart';
import '../db/main_db_provider.dart';

typedef AddressLabelKey = ({String walletId, String address});

abstract interface class AddressLabelStore {
AddressLabel? find(AddressLabelKey key);

Stream<List<AddressLabel>> watch(AddressLabelKey key);
}

class _MainDBAddressLabelStore implements AddressLabelStore {
const _MainDBAddressLabelStore(this.isar);

final Isar isar;

QueryBuilder<AddressLabel, AddressLabel, QAfterWhereClause> _query(
AddressLabelKey key,
) => isar.addressLabels.where().addressStringWalletIdEqualTo(
key.address,
key.walletId,
);

@override
AddressLabel? find(AddressLabelKey key) => _query(key).findFirstSync();

@override
Stream<List<AddressLabel>> watch(AddressLabelKey key) =>
_query(key).watch(fireImmediately: true);
}

final addressLabelStoreProvider = Provider<AddressLabelStore>((ref) {
return _MainDBAddressLabelStore(ref.watch(mainDBProvider).isar);
});

class _AddressLabelWatcher extends ChangeNotifier {
_AddressLabelWatcher(AddressLabelStore store, AddressLabelKey key)
: _value = store.find(key) {
_subscription = store.watch(key).listen((labels) {
_value = labels.firstOrNull;
notifyListeners();
});
}

late final StreamSubscription<List<AddressLabel>> _subscription;
AddressLabel? _value;

AddressLabel? get value => _value;

@override
void dispose() {
_subscription.cancel();
super.dispose();
}
}

final _addressLabelWatcherProvider = ChangeNotifierProvider.autoDispose
.family<_AddressLabelWatcher, AddressLabelKey>((ref, key) {
return _AddressLabelWatcher(ref.watch(addressLabelStoreProvider), key);
});

final pAddressLabel = Provider.autoDispose
.family<AddressLabel?, AddressLabelKey>(
(ref, key) => ref.watch(_addressLabelWatcherProvider(key)).value,
);
111 changes: 111 additions & 0 deletions lib/widgets/address_label_editor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../db/isar/main_db.dart';
import '../models/isar/models/address_label.dart';
import '../notifications/show_flush_bar.dart';
import '../providers/db/main_db_provider.dart';
import '../providers/wallet/address_label_provider.dart';
import '../themes/stack_colors.dart';
import '../utilities/logger.dart';
import '../utilities/text_styles.dart';
import 'custom_buttons/simple_edit_button.dart';

abstract interface class AddressLabelWriter {
Future<void> write(AddressLabelKey key, String value);
}

class _MainDBAddressLabelWriter implements AddressLabelWriter {
const _MainDBAddressLabelWriter(this.db);

final MainDB db;

@override
Future<void> write(AddressLabelKey key, String value) async {
final existing = db.getAddressLabelSync(key.walletId, key.address);
await db.putAddressLabel(
existing?.copyWith(label: value) ??
AddressLabel(
walletId: key.walletId,
addressString: key.address,
value: value,
tags: null,
),
);
}
}

final addressLabelWriterProvider = Provider<AddressLabelWriter>((ref) {
return _MainDBAddressLabelWriter(ref.watch(mainDBProvider));
});

class AddressLabelEditor extends ConsumerStatefulWidget {
const AddressLabelEditor({
super.key,
required this.walletId,
required this.address,
required this.isDesktop,
});

final String walletId;
final String address;
final bool isDesktop;

@override
ConsumerState<AddressLabelEditor> createState() => _AddressLabelEditorState();
}

class _AddressLabelEditorState extends ConsumerState<AddressLabelEditor> {
Future<void> _pendingWrite = Future.value();

void _queueWrite(String value) {
final key = (walletId: widget.walletId, address: widget.address);
final writer = ref.read(addressLabelWriterProvider);
_pendingWrite = _pendingWrite.then((_) async {
try {
await writer.write(key, value);
} catch (error, stackTrace) {
Logging.instance.w(
'Failed to update address label',
error: error,
stackTrace: stackTrace,
);
if (mounted) {
unawaited(
showFloatingFlushBar(
type: FlushBarType.warning,
message: 'Failed to update address label',
context: context,
),
);
}
}
});
}

@override
Widget build(BuildContext context) {
final key = (walletId: widget.walletId, address: widget.address);
final value = ref.watch(pAddressLabel(key))?.value ?? '';
final style = widget.isDesktop
? STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textDark,
)
: STextStyles.itemSubtitle(context);

return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text(value.isEmpty ? 'No label' : value, style: style)),
SimpleEditButton(
editValue: value,
editLabel: 'label',
overrideTitle: 'Edit label',
onValueChanged: _queueWrite,
),
],
);
}
}
Loading
Loading