transaction note provider

This commit is contained in:
julian 2023-11-09 11:39:12 -06:00
parent 335c2b9993
commit 758c3def5f
15 changed files with 243 additions and 338 deletions

View file

@ -33,4 +33,14 @@ class TransactionNote {
late String txid;
late String value;
TransactionNote copyWith({
String? value,
}) {
return TransactionNote(
walletId: walletId,
txid: txid,
value: value ?? this.value,
);
}
}

View file

@ -13,11 +13,13 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/models/trade_wallet_lookup.dart';
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
import 'package:stackwallet/pages/send_view/sub_widgets/sending_transaction_dialog.dart';
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart';
import 'package:stackwallet/providers/db/main_db_provider.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/themes/stack_colors.dart';
@ -129,9 +131,13 @@ class _ConfirmChangeNowSendViewState
txid = (results.first as TxData).txid!;
// save note
await ref
.read(notesServiceChangeNotifierProvider(walletId))
.editOrAddNote(txid: txid, note: note);
await ref.read(mainDBProvider).putTransactionNote(
TransactionNote(
walletId: walletId,
txid: txid,
value: note,
),
);
await ref.read(tradeSentFromStackLookupProvider).save(
tradeWalletLookup: TradeWalletLookup(

View file

@ -84,8 +84,6 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
late final Transaction? transactionIfSentFromStack;
late final String? walletId;
String _note = "";
bool isStackCoin(String ticker) {
try {
coinFromTickerCaseInsensitive(ticker);
@ -950,7 +948,9 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
maxHeight: 360,
child: EditTradeNoteView(
tradeId: tradeId,
note: _note,
note: ref
.read(tradeNoteServiceProvider)
.getNote(tradeId: tradeId),
),
);
},
@ -1036,7 +1036,6 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
txid:
transactionIfSentFromStack!.txid,
walletId: walletId!,
note: _note,
),
);
},
@ -1047,10 +1046,9 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
onTap: () {
Navigator.of(context).pushNamed(
EditNoteView.routeName,
arguments: Tuple3(
arguments: Tuple2(
transactionIfSentFromStack!.txid,
walletId!,
_note,
walletId,
),
);
},
@ -1079,22 +1077,19 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
const SizedBox(
height: 4,
),
FutureBuilder(
future: ref.watch(
notesServiceChangeNotifierProvider(walletId!).select(
(value) => value.getNoteFor(
txid: transactionIfSentFromStack!.txid))),
builder:
(builderContext, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
_note = snapshot.data ?? "";
}
return SelectableText(
_note,
style: STextStyles.itemSubtitle12(context),
);
},
SelectableText(
ref
.watch(
pTransactionNote(
(
txid: transactionIfSentFromStack!.txid,
walletId: walletId!,
),
),
)
?.value ??
"",
style: STextStyles.itemSubtitle12(context),
),
],
),

View file

@ -16,6 +16,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_libepiccash/lib.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/isar/models/transaction_note.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
import 'package:stackwallet/pages/send_view/sub_widgets/sending_transaction_dialog.dart';
@ -23,6 +24,7 @@ import 'package:stackwallet/pages/token_view/token_view.dart';
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
import 'package:stackwallet/pages_desktop_specific/coin_control/desktop_coin_control_use_dialog.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart';
import 'package:stackwallet/providers/db/main_db_provider.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
import 'package:stackwallet/route_generator.dart';
@ -169,9 +171,13 @@ class _ConfirmTransactionViewState
ref.refresh(desktopUseUTXOs);
// save note
await ref
.read(notesServiceChangeNotifierProvider(walletId))
.editOrAddNote(txid: txid, note: note);
await ref.read(mainDBProvider).putTransactionNote(
TransactionNote(
walletId: walletId,
txid: txid,
value: note,
),
);
if (widget.isTokenTx) {
unawaited(ref.read(tokenServiceProvider)!.refresh());

View file

@ -16,6 +16,7 @@ import 'package:flutter_svg/svg.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/models/isar/models/transaction_note.dart';
import 'package:stackwallet/models/transaction_filter.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/token_view/token_view.dart';
@ -105,8 +106,13 @@ class _TransactionDetailsViewState extends ConsumerState<AllTransactionsView> {
// debugPrint("FILTER: $filter");
final contacts = ref.read(addressBookServiceProvider).contacts;
final notes =
ref.read(notesServiceChangeNotifierProvider(walletId)).notesSync;
final notes = ref
.read(mainDBProvider)
.isar
.transactionNotes
.where()
.walletIdEqualTo(walletId)
.findAllSync();
return transactions.where((tx) {
if (!filter.sent && !filter.received) {
@ -144,7 +150,7 @@ class _TransactionDetailsViewState extends ConsumerState<AllTransactionsView> {
}
bool _isKeywordMatch(Transaction tx, String keyword,
List<ContactEntry> contacts, Map<String, String> notes) {
List<ContactEntry> contacts, List<TransactionNote> notes) {
if (keyword.isEmpty) {
return true;
}
@ -164,9 +170,15 @@ class _TransactionDetailsViewState extends ConsumerState<AllTransactionsView> {
contains |=
tx.address.value?.value.toLowerCase().contains(keyword) ?? false;
TransactionNote? note;
final matchingNotes = notes.where((e) => e.txid == tx.txid);
if (matchingNotes.isNotEmpty) {
note = matchingNotes.first;
}
// check if note contains
contains |= notes[tx.txid] != null &&
notes[tx.txid]!.toLowerCase().contains(keyword);
contains |= note != null &&
note.value.toLowerCase().contains(keyword);
// check if txid contains
contains |= tx.txid.toLowerCase().contains(keyword);
@ -193,8 +205,13 @@ class _TransactionDetailsViewState extends ConsumerState<AllTransactionsView> {
}
text = text.toLowerCase();
final contacts = ref.read(addressBookServiceProvider).contacts;
final notes =
ref.read(notesServiceChangeNotifierProvider(walletId)).notesSync;
final notes = ref
.read(mainDBProvider)
.isar
.transactionNotes
.where()
.walletIdEqualTo(walletId)
.findAllSync();
return transactions
.where((tx) => _isKeywordMatch(tx, text, contacts, notes))

View file

@ -10,6 +10,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/models/isar/models/transaction_note.dart';
import 'package:stackwallet/providers/db/main_db_provider.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/constants.dart';
@ -29,14 +31,12 @@ class EditNoteView extends ConsumerStatefulWidget {
Key? key,
required this.txid,
required this.walletId,
required this.note,
}) : super(key: key);
static const String routeName = "/editNote";
final String txid;
final String walletId;
final String note;
@override
ConsumerState<EditNoteView> createState() => _EditNoteViewState();
@ -48,11 +48,19 @@ class _EditNoteViewState extends ConsumerState<EditNoteView> {
late final bool isDesktop;
TransactionNote? _note;
@override
void initState() {
isDesktop = Util.isDesktop;
_noteController = TextEditingController();
_noteController.text = widget.note;
_note = ref.read(
pTransactionNote(
(txid: widget.txid, walletId: widget.walletId),
),
);
_noteController.text = _note?.value ?? "";
super.initState();
}
@ -185,13 +193,15 @@ class _EditNoteViewState extends ConsumerState<EditNoteView> {
child: PrimaryButton(
label: "Save",
onPressed: () async {
await ref
.read(notesServiceChangeNotifierProvider(
widget.walletId))
.editOrAddNote(
txid: widget.txid,
note: _noteController.text,
await ref.read(mainDBProvider).putTransactionNote(
_note?.copyWith(value: _noteController.text) ??
TransactionNote(
walletId: widget.walletId,
txid: widget.walletId,
value: _noteController.text,
),
);
if (mounted) {
Navigator.of(context).pop();
}
@ -201,12 +211,13 @@ class _EditNoteViewState extends ConsumerState<EditNoteView> {
if (!isDesktop)
TextButton(
onPressed: () async {
await ref
.read(
notesServiceChangeNotifierProvider(widget.walletId))
.editOrAddNote(
txid: widget.txid,
note: _noteController.text,
await ref.read(mainDBProvider).putTransactionNote(
_note?.copyWith(value: _noteController.text) ??
TransactionNote(
walletId: widget.walletId,
txid: widget.walletId,
value: _noteController.text,
),
);
if (mounted) {
Navigator.of(context).pop();

View file

@ -216,8 +216,6 @@ class _TransactionDetailsViewState
}
}
String _note = "";
Future<bool> showExplorerWarning(String explorer) async {
final bool? shouldContinue = await showDialog<bool>(
context: context,
@ -879,7 +877,6 @@ class _TransactionDetailsViewState
child: EditNoteView(
txid: _transaction.txid,
walletId: walletId,
note: _note,
),
);
},
@ -890,10 +887,9 @@ class _TransactionDetailsViewState
onTap: () {
Navigator.of(context).pushNamed(
EditNoteView.routeName,
arguments: Tuple3(
arguments: Tuple2(
_transaction.txid,
walletId,
_note,
),
);
},
@ -924,36 +920,28 @@ class _TransactionDetailsViewState
const SizedBox(
height: 8,
),
FutureBuilder(
future: ref.watch(
notesServiceChangeNotifierProvider(
walletId)
.select((value) => value.getNoteFor(
txid: (coin == Coin.epicCash)
? _transaction.slateId!
: _transaction.txid))),
builder: (builderContext,
AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState ==
ConnectionState.done &&
snapshot.hasData) {
_note = snapshot.data ?? "";
}
return SelectableText(
_note,
style: isDesktop
? STextStyles
.desktopTextExtraExtraSmall(
context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
)
: STextStyles.itemSubtitle12(
context),
);
},
SelectableText(
ref
.watch(
pTransactionNote(
(
txid: _transaction.txid,
walletId: walletId
),
),
)
?.value ??
"",
style: isDesktop
? STextStyles
.desktopTextExtraExtraSmall(
context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
)
: STextStyles.itemSubtitle12(context),
),
],
),

View file

@ -17,6 +17,7 @@ import 'package:isar/isar.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/v2/transaction_v2.dart';
import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/models/transaction_filter.dart';
import 'package:stackwallet/pages/wallet_view/sub_widgets/tx_icon.dart';
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_search_filter_view.dart';
@ -101,8 +102,13 @@ class _AllTransactionsV2ViewState extends ConsumerState<AllTransactionsV2View> {
// debugPrint("FILTER: $filter");
final contacts = ref.read(addressBookServiceProvider).contacts;
final notes =
ref.read(notesServiceChangeNotifierProvider(walletId)).notesSync;
final notes = ref
.read(mainDBProvider)
.isar
.transactionNotes
.where()
.walletIdEqualTo(walletId)
.findAllSync();
return transactions.where((tx) {
if (!filter.sent && !filter.received) {
@ -139,7 +145,7 @@ class _AllTransactionsV2ViewState extends ConsumerState<AllTransactionsV2View> {
TransactionV2 tx,
String keyword,
List<ContactEntry> contacts,
Map<String, String> notes,
List<TransactionNote> notes,
) {
if (keyword.isEmpty) {
return true;
@ -164,9 +170,15 @@ class _AllTransactionsV2ViewState extends ConsumerState<AllTransactionsV2View> {
.where((e) => e.toLowerCase().contains(keyword))
.isNotEmpty;
TransactionNote? note;
final matchingNotes = notes.where((e) => e.txid == tx.txid);
if (matchingNotes.isNotEmpty) {
note = matchingNotes.first;
}
// check if note contains
contains |= notes[tx.txid] != null &&
notes[tx.txid]!.toLowerCase().contains(keyword);
contains |= note != null &&
note.value.toLowerCase().contains(keyword);
// check if txid contains
contains |= tx.txid.toLowerCase().contains(keyword);
@ -193,8 +205,13 @@ class _AllTransactionsV2ViewState extends ConsumerState<AllTransactionsV2View> {
}
text = text.toLowerCase();
final contacts = ref.read(addressBookServiceProvider).contacts;
final notes =
ref.read(notesServiceChangeNotifierProvider(walletId)).notesSync;
final notes = ref
.read(mainDBProvider)
.isar
.transactionNotes
.where()
.walletIdEqualTo(walletId)
.findAllSync();
return transactions
.where((tx) => _isKeywordMatch(tx, text, contacts, notes))

View file

@ -256,8 +256,6 @@ class _TransactionV2DetailsViewState
}
}
String _note = "";
Future<bool> showExplorerWarning(String explorer) async {
final bool? shouldContinue = await showDialog<bool>(
context: context,
@ -927,7 +925,6 @@ class _TransactionV2DetailsViewState
child: EditNoteView(
txid: _transaction.txid,
walletId: walletId,
note: _note,
),
);
},
@ -938,10 +935,9 @@ class _TransactionV2DetailsViewState
onTap: () {
Navigator.of(context).pushNamed(
EditNoteView.routeName,
arguments: Tuple3(
arguments: Tuple2(
_transaction.txid,
walletId,
_note,
),
);
},
@ -972,34 +968,28 @@ class _TransactionV2DetailsViewState
const SizedBox(
height: 8,
),
FutureBuilder(
future: ref.watch(
notesServiceChangeNotifierProvider(
walletId)
.select((value) => value.getNoteFor(
txid: _transaction.txid))),
builder: (builderContext,
AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState ==
ConnectionState.done &&
snapshot.hasData) {
_note = snapshot.data ?? "";
}
return SelectableText(
_note,
style: isDesktop
? STextStyles
.desktopTextExtraExtraSmall(
context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
)
: STextStyles.itemSubtitle12(
context),
);
},
SelectableText(
ref
.watch(
pTransactionNote(
(
txid: _transaction.txid,
walletId: walletId
),
),
)
?.value ??
"",
style: isDesktop
? STextStyles
.desktopTextExtraExtraSmall(
context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
)
: STextStyles.itemSubtitle12(context),
),
],
),

View file

@ -31,4 +31,4 @@ export './ui/home_view_index_provider.dart';
export './ui/verify_recovery_phrase/correct_word_provider.dart';
export './ui/verify_recovery_phrase/random_index_provider.dart';
export './ui/verify_recovery_phrase/selected_word_provider.dart';
export './wallet/notes_service_provider.dart';
export './wallet/transaction_note_provider.dart';

View file

@ -1,24 +0,0 @@
/*
* This file is part of Stack Wallet.
*
* Copyright (c) 2023 Cypher Stack
* All Rights Reserved.
* The code is distributed under GPLv3 license, see LICENSE file for details.
* Generated by Cypher Stack on 2023-05-26
*
*/
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/services/notes_service.dart';
int _count = 0;
final notesServiceChangeNotifierProvider =
ChangeNotifierProvider.family<NotesService, String>((_, walletId) {
if (kDebugMode) {
_count++;
}
return NotesService(walletId: walletId);
});

View file

@ -0,0 +1,75 @@
/*
* This file is part of Stack Wallet.
*
* Copyright (c) 2023 Cypher Stack
* All Rights Reserved.
* The code is distributed under GPLv3 license, see LICENSE file for details.
* Generated by Cypher Stack on 2023-05-26
*
*/
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/models/isar/models/transaction_note.dart';
import 'package:stackwallet/providers/db/main_db_provider.dart';
class _TransactionNoteWatcher extends ChangeNotifier {
final ({String walletId, String txid}) key;
late final StreamSubscription<List<TransactionNote>> _streamSubscription;
TransactionNote? _value;
TransactionNote? get value => _value;
_TransactionNoteWatcher(this._value, this.key, Isar isar) {
_streamSubscription = isar.transactionNotes
.where()
.txidWalletIdEqualTo(key.txid, key.walletId)
.watch(fireImmediately: true)
.listen((event) {
print("AAAAAA $event");
if (event.isEmpty) {
_value = null;
} else {
_value = event.first;
}
notifyListeners();
});
}
@override
void dispose() {
_streamSubscription.cancel();
super.dispose();
}
}
final _wiProvider = ChangeNotifierProvider.family<_TransactionNoteWatcher,
({String walletId, String txid})>(
(ref, key) {
final isar = ref.watch(mainDBProvider).isar;
final watcher = _TransactionNoteWatcher(
isar.transactionNotes
.where()
.txidWalletIdEqualTo(key.txid, key.walletId)
.findFirstSync(),
key,
isar,
);
ref.onDispose(() => watcher.dispose());
return watcher;
},
);
final pTransactionNote =
Provider.family<TransactionNote?, ({String walletId, String txid})>(
(ref, key) {
return ref.watch(_wiProvider(key)).value;
},
);

View file

@ -906,13 +906,12 @@ class RouteGenerator {
return _routeError("${settings.name} invalid args: ${args.toString()}");
case EditNoteView.routeName:
if (args is Tuple3<String, String, String>) {
if (args is Tuple2<String, String>) {
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => EditNoteView(
txid: args.item1,
walletId: args.item2,
note: args.item3,
),
settings: RouteSettings(
name: settings.name,

View file

@ -1,85 +0,0 @@
/*
* This file is part of Stack Wallet.
*
* Copyright (c) 2023 Cypher Stack
* All Rights Reserved.
* The code is distributed under GPLv3 license, see LICENSE file for details.
* Generated by Cypher Stack on 2023-05-26
*
*/
import 'package:flutter/material.dart';
import 'package:stackwallet/db/hive/db.dart';
import 'package:stackwallet/utilities/logger.dart';
class NotesService extends ChangeNotifier {
final String walletId;
NotesService({required this.walletId});
Map<String, String> get notesSync {
final notes =
DB.instance.get<dynamic>(boxName: walletId, key: 'notes') as Map?;
return notes == null ? <String, String>{} : Map<String, String>.from(notes);
}
/// Holds transaction notes
/// map of contact <txid, note>
/// txid is used as key due to uniqueness
Future<Map<String, String>>? _notes;
Future<Map<String, String>> get notes => _notes ??= _fetchNotes();
// fetch notes map
Future<Map<String, String>> _fetchNotes() async {
final notes =
DB.instance.get<dynamic>(boxName: walletId, key: 'notes') as Map?;
return notes == null ? <String, String>{} : Map<String, String>.from(notes);
}
/// search notes
//TODO optimize notes search?
Future<Map<String, String>> search(String text) async {
if (text.isEmpty) return notes;
var results = Map<String, String>.from(await notes);
results.removeWhere(
(key, value) => (!key.contains(text) && !value.contains(text)));
return results;
}
/// fetch note given a transaction ID
Future<String> getNoteFor({required String txid}) async {
final note = (await notes)[txid];
return note ?? "";
}
/// edit or add new note for the given [txid]
Future<void> editOrAddNote(
{required String txid, required String note}) async {
final _notes = await notes;
_notes[txid] = note;
await DB.instance
.put<dynamic>(boxName: walletId, key: 'notes', value: _notes);
//todo: check if this is needed
Logging.instance.log("editOrAddNote: tx note saved", level: LogLevel.Info);
await _refreshNotes();
}
/// Remove note from db
Future<void> deleteNote({required String txid}) async {
final entries =
DB.instance.get<dynamic>(boxName: walletId, key: 'notes') as Map;
entries.remove(txid);
await DB.instance
.put<dynamic>(boxName: walletId, key: 'notes', value: entries);
Logging.instance.log("tx note removed", level: LogLevel.Info);
await _refreshNotes();
}
Future<void> _refreshNotes() async {
final newNotes = await _fetchNotes();
_notes = Future(() => newNotes);
notifyListeners();
}
}

View file

@ -1,100 +0,0 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:hive/hive.dart';
import 'package:hive_test/hive_test.dart';
import 'package:stackwallet/services/notes_service.dart';
void main() {
setUp(() async {
await setUpTestHive();
final wallets = await Hive.openBox<dynamic>('wallets');
await wallets.put('names', {"My Firo Wallet": "wallet_id"});
await wallets.put('currentWalletName', "My Firo Wallet");
final wallet = await Hive.openBox<dynamic>("wallet_id");
await wallet.put("notes", {"txid1": "note1", "txid2": "note2"});
});
test("get null notes", () async {
final service = NotesService(walletId: 'wallet_id');
final wallet = await Hive.openBox<dynamic>("wallet_id");
await wallet.put("notes", null);
expect(await service.notes, <String, String>{});
});
test("get empty notes", () async {
final service = NotesService(walletId: 'wallet_id');
final wallet = await Hive.openBox<dynamic>("wallet_id");
await wallet.put("notes", <String, String>{});
expect(await service.notes, <String, String>{});
});
test("get some notes", () async {
final service = NotesService(walletId: 'wallet_id');
expect(await service.notes, {"txid1": "note1", "txid2": "note2"});
});
test("search finds none", () async {
final service = NotesService(walletId: 'wallet_id');
expect(await service.search("some"), <String, String>{});
});
test("empty search", () async {
final service = NotesService(walletId: 'wallet_id');
expect(await service.search(""), {"txid1": "note1", "txid2": "note2"});
});
test("search finds some", () async {
final service = NotesService(walletId: 'wallet_id');
expect(await service.search("note"), {"txid1": "note1", "txid2": "note2"});
});
test("search finds one", () async {
final service = NotesService(walletId: 'wallet_id');
expect(await service.search("2"), {"txid2": "note2"});
});
test("get note for existing txid", () async {
final service = NotesService(walletId: 'wallet_id');
expect(await service.getNoteFor(txid: "txid1"), "note1");
});
test("get note for non existing txid", () async {
final service = NotesService(walletId: 'wallet_id');
expect(await service.getNoteFor(txid: "txid"), "");
});
test("add new note", () async {
final service = NotesService(walletId: 'wallet_id');
await service.editOrAddNote(txid: "txid3", note: "note3");
expect(await service.notes,
{"txid1": "note1", "txid2": "note2", "txid3": "note3"});
});
test("add or overwrite note for new txid", () async {
final service = NotesService(walletId: 'wallet_id');
await service.editOrAddNote(txid: "txid3", note: "note3");
expect(await service.notes,
{"txid1": "note1", "txid2": "note2", "txid3": "note3"});
});
test("add or overwrite note for existing txid", () async {
final service = NotesService(walletId: 'wallet_id');
await service.editOrAddNote(txid: "txid2", note: "note3");
expect(await service.notes, {"txid1": "note1", "txid2": "note3"});
});
test("delete existing note", () async {
final service = NotesService(walletId: 'wallet_id');
await service.deleteNote(txid: "txid2");
expect(await service.notes, {"txid1": "note1"});
});
test("delete non existing note", () async {
final service = NotesService(walletId: 'wallet_id');
await service.deleteNote(txid: "txid5");
expect(await service.notes, {"txid1": "note1", "txid2": "note2"});
});
tearDown(() async {
await tearDownTestHive();
});
}