Merge remote-tracking branch 'origin/staging' into tor

This commit is contained in:
Josh Babb 2023-05-17 15:28:59 -05:00
commit 174e9b29a6
80 changed files with 3675 additions and 1217 deletions

Binary file not shown.

Binary file not shown.

View file

@ -41,7 +41,6 @@ class DB {
String boxNameUsedSerialsCache({required Coin coin}) => String boxNameUsedSerialsCache({required Coin coin}) =>
"${coin.name}_usedSerialsCache"; "${coin.name}_usedSerialsCache";
Box<dynamic>? _boxAddressBook;
Box<String>? _boxDebugInfo; Box<String>? _boxDebugInfo;
Box<NodeModel>? _boxNodeModels; Box<NodeModel>? _boxNodeModels;
Box<NodeModel>? _boxPrimaryNodes; Box<NodeModel>? _boxPrimaryNodes;
@ -100,7 +99,6 @@ class DB {
_boxPrefs = await Hive.openBox<dynamic>(boxNamePrefs); _boxPrefs = await Hive.openBox<dynamic>(boxNamePrefs);
} }
_boxAddressBook = await Hive.openBox<dynamic>(boxNameAddressBook);
_boxDebugInfo = await Hive.openBox<String>(boxNameDebugInfo); _boxDebugInfo = await Hive.openBox<String>(boxNameDebugInfo);
if (Hive.isBoxOpen(boxNameNodeModels)) { if (Hive.isBoxOpen(boxNameNodeModels)) {

View file

@ -3,6 +3,7 @@ import 'package:flutter_native_splash/cli_commands.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stackwallet/exceptions/main_db/main_db_exception.dart'; import 'package:stackwallet/exceptions/main_db/main_db_exception.dart';
import 'package:stackwallet/models/isar/models/block_explorer.dart'; import 'package:stackwallet/models/isar/models/block_explorer.dart';
import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/models/isar/stack_theme.dart'; import 'package:stackwallet/models/isar/stack_theme.dart';
import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount.dart';
@ -37,6 +38,7 @@ class MainDB {
EthContractSchema, EthContractSchema,
TransactionBlockExplorerSchema, TransactionBlockExplorerSchema,
StackThemeSchema, StackThemeSchema,
ContactEntrySchema,
], ],
directory: (await StackFileSystem.applicationIsarDirectory()).path, directory: (await StackFileSystem.applicationIsarDirectory()).path,
// inspector: kDebugMode, // inspector: kDebugMode,
@ -47,6 +49,45 @@ class MainDB {
return true; return true;
} }
// contact entries
List<ContactEntry> getContactEntries(){
return isar.contactEntrys.where().findAllSync();
}
Future<bool> deleteContactEntry({required String id}) {
try {
return isar.writeTxn(() async {
await isar.contactEntrys.deleteByCustomId(id);
return true;
});
} catch (e) {
throw MainDBException("failed deleteContactEntry: $id", e);
}
}
Future<bool> isContactEntryExists({required String id}) async {
return isar.contactEntrys
.where()
.customIdEqualTo(id)
.count()
.then((value) => value > 0);
}
ContactEntry? getContactEntry({required String id}) {
return isar.contactEntrys.where().customIdEqualTo(id).findFirstSync();
}
Future<bool> putContactEntry({required ContactEntry contactEntry}) async {
try {
return await isar.writeTxn(() async {
await isar.contactEntrys.put(contactEntry);
return true;
});
} catch (e) {
throw MainDBException("failed putContactEntry: $contactEntry", e);
}
}
// tx block explorers // tx block explorers
TransactionBlockExplorer? getTransactionBlockExplorer({required Coin coin}) { TransactionBlockExplorer? getTransactionBlockExplorer({required Coin coin}) {
return isar.transactionBlockExplorers return isar.transactionBlockExplorers

View file

@ -162,7 +162,7 @@ void main() async {
int dbVersion = DB.instance.get<dynamic>( int dbVersion = DB.instance.get<dynamic>(
boxName: DB.boxNameDBInfo, key: "hive_data_version") as int? ?? boxName: DB.boxNameDBInfo, key: "hive_data_version") as int? ??
0; 0;
if (dbVersion < Constants.currentHiveDbVersion) { if (dbVersion < Constants.currentDataVersion) {
try { try {
await DbVersionMigrator().migrate( await DbVersionMigrator().migrate(
dbVersion, dbVersion,
@ -178,9 +178,6 @@ void main() async {
} }
} }
//Add Themes directory - TODO
// await StackFileSystem.applicationThemesDirectory();
monero.onStartup(); monero.onStartup();
wownero.onStartup(); wownero.onStartup();

View file

@ -3,6 +3,7 @@ import 'dart:convert';
import 'package:stackwallet/models/contact_address_entry.dart'; import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
@Deprecated("Use lib/models/isar/models/contact_entry.dart instead")
class Contact { class Contact {
final String? emojiChar; final String? emojiChar;
final String name; final String name;

View file

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@Deprecated("Use lib/models/isar/models/contact_entry.dart instead")
class ContactAddressEntry { class ContactAddressEntry {
final Coin coin; final Coin coin;
final String address; final String address;

View file

@ -1,5 +1,5 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:stackwallet/models/contact_address_entry.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/address_utils.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -57,7 +57,7 @@ class AddressEntryData extends ChangeNotifier {
} }
bool get isValidAddress { bool get isValidAddress {
if ( coin == null) { if (coin == null) {
return true; return true;
} }
if (_address == null) { if (_address == null) {
@ -67,8 +67,11 @@ class AddressEntryData extends ChangeNotifier {
} }
ContactAddressEntry buildAddressEntry() { ContactAddressEntry buildAddressEntry() {
return ContactAddressEntry( return ContactAddressEntry()
coin: coin!, address: address!, label: addressLabel!); ..coinName = coin!.name
..address = address!
..other = null
..label = addressLabel!;
} }
@override @override

View file

@ -0,0 +1,108 @@
import 'package:isar/isar.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
part 'contact_entry.g.dart';
@collection
class ContactEntry {
ContactEntry({
this.emojiChar,
required this.name,
required this.addresses,
required this.isFavorite,
required this.customId,
});
Id id = Isar.autoIncrement;
late final String? emojiChar;
late final String name;
late final List<ContactAddressEntry> addresses;
late final bool isFavorite;
@Index(unique: true, replace: true)
late final String customId;
ContactEntry copyWith({
bool shouldCopyEmojiWithNull = false,
String? emojiChar,
String? name,
List<ContactAddressEntry>? addresses,
bool? isFavorite,
}) {
List<ContactAddressEntry> _addresses = [];
if (addresses == null) {
for (var e in this.addresses) {
_addresses.add(e.copyWith());
}
} else {
for (var e in addresses) {
_addresses.add(e.copyWith());
}
}
String? newEmoji;
if (shouldCopyEmojiWithNull) {
newEmoji = emojiChar;
} else {
newEmoji = emojiChar ?? this.emojiChar;
}
return ContactEntry(
emojiChar: newEmoji,
name: name ?? this.name,
addresses: _addresses,
isFavorite: isFavorite ?? this.isFavorite,
customId: customId,
);
}
Map<String, dynamic> toMap() {
return {
"emoji": emojiChar,
"name": name,
"addresses": addresses.map((e) => e.toMap()).toList(),
"id": customId,
"isFavorite": isFavorite,
};
}
}
@embedded
class ContactAddressEntry {
late final String coinName;
late final String address;
late final String label;
late final String? other;
@ignore
Coin get coin => Coin.values.byName(coinName);
ContactAddressEntry();
ContactAddressEntry copyWith({
Coin? coin,
String? address,
String? label,
String? other,
}) {
return ContactAddressEntry()
..coinName = coin?.name ?? coinName
..address = address ?? this.address
..label = label ?? this.label
..other = other ?? this.other;
}
Map<String, String> toMap() {
return {
"label": label,
"address": address,
"coin": coin.name,
"other": other ?? "",
};
}
@override
String toString() {
return "AddressBookEntry: ${toMap()}";
}
}

File diff suppressed because it is too large Load diff

View file

@ -794,6 +794,15 @@ class StackTheme {
Color? _bottomNavIconIcon; Color? _bottomNavIconIcon;
final int bottomNavIconIconInt; final int bottomNavIconIconInt;
// ==== bottomNavIconIcon highlighted =====================================================
@ignore
Color get bottomNavIconIconHighlighted =>
_bottomNavIconIconHighlighted ??= Color(bottomNavIconIconHighlightedInt);
@ignore
Color? _bottomNavIconIconHighlighted;
final int bottomNavIconIconHighlightedInt;
// ==== topNavIconPrimary ===================================================== // ==== topNavIconPrimary =====================================================
@ignore @ignore
@ -1556,6 +1565,7 @@ class StackTheme {
required this.snackBarTextInfoInt, required this.snackBarTextInfoInt,
required this.bottomNavIconBackInt, required this.bottomNavIconBackInt,
required this.bottomNavIconIconInt, required this.bottomNavIconIconInt,
required this.bottomNavIconIconHighlightedInt,
required this.topNavIconPrimaryInt, required this.topNavIconPrimaryInt,
required this.topNavIconGreenInt, required this.topNavIconGreenInt,
required this.topNavIconYellowInt, required this.topNavIconYellowInt,
@ -1795,6 +1805,8 @@ class StackTheme {
parseColor(json["colors"]["bottom_nav_icon_back"] as String), parseColor(json["colors"]["bottom_nav_icon_back"] as String),
bottomNavIconIconInt: bottomNavIconIconInt:
parseColor(json["colors"]["bottom_nav_icon_icon"] as String), parseColor(json["colors"]["bottom_nav_icon_icon"] as String),
bottomNavIconIconHighlightedInt: parseColor(
json["colors"]["bottom_nav_icon_icon_highlighted"] as String),
topNavIconPrimaryInt: topNavIconPrimaryInt:
parseColor(json["colors"]["top_nav_icon_primary"] as String), parseColor(json["colors"]["top_nav_icon_primary"] as String),
topNavIconGreenInt: topNavIconGreenInt:

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,14 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/isar/stack_theme.dart';
import 'package:stackwallet/models/notification_model.dart'; import 'package:stackwallet/models/notification_model.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/theme_providers.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
@ -9,7 +16,7 @@ import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
class NotificationCard extends StatelessWidget { class NotificationCard extends ConsumerWidget {
const NotificationCard({ const NotificationCard({
Key? key, Key? key,
required this.notification, required this.notification,
@ -25,8 +32,17 @@ class NotificationCard extends StatelessWidget {
static const double mobileIconSize = 24; static const double mobileIconSize = 24;
static const double desktopIconSize = 30; static const double desktopIconSize = 30;
String coinIconPath(ThemeAssets assets, WidgetRef ref) {
try {
final coin = coinFromPrettyName(notification.coinName);
return ref.read(coinIconProvider(coin));
} catch (_) {
return notification.iconAssetName;
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context, WidgetRef ref) {
final isDesktop = Util.isDesktop; final isDesktop = Util.isDesktop;
return Stack( return Stack(
@ -41,8 +57,14 @@ class NotificationCard extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
notification.changeNowId == null notification.changeNowId == null
? SvgPicture.asset( ? SvgPicture.file(
notification.iconAssetName, File(
coinIconPath(
ref.watch(
themeProvider.select((value) => value.assets),
),
ref),
),
width: isDesktop ? desktopIconSize : mobileIconSize, width: isDesktop ? desktopIconSize : mobileIconSize,
height: isDesktop ? desktopIconSize : mobileIconSize, height: isDesktop ? desktopIconSize : mobileIconSize,
) )
@ -53,8 +75,14 @@ class NotificationCard extends StatelessWidget {
color: Colors.transparent, color: Colors.transparent,
borderRadius: BorderRadius.circular(24), borderRadius: BorderRadius.circular(24),
), ),
child: SvgPicture.asset( child: SvgPicture.file(
notification.iconAssetName, File(
coinIconPath(
ref.watch(
themeProvider.select((value) => value.assets),
),
ref),
),
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.accentColorDark, .accentColorDark,

View file

@ -1,8 +1,7 @@
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:flutter_svg/svg.dart';
import 'package:stackwallet/models/contact.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/pages/address_book_views/subviews/add_address_book_entry_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/add_address_book_entry_view.dart';
import 'package:stackwallet/pages/address_book_views/subviews/address_book_filter_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/address_book_filter_view.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart';
@ -73,19 +72,18 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
final managers = ref.read(walletsChangeNotifierProvider).managers; final managers = ref.read(walletsChangeNotifierProvider).managers;
for (final manager in managers) { for (final manager in managers) {
addresses.add( addresses.add(
ContactAddressEntry( ContactAddressEntry()
coin: manager.coin, ..coinName = manager.coin.name
address: await manager.currentReceivingAddress, ..address = await manager.currentReceivingAddress
label: "Current Receiving", ..label = "Current Receiving"
other: manager.walletName, ..other = manager.walletName,
),
); );
} }
final self = Contact( final self = ContactEntry(
name: "My Stack", name: "My Stack",
addresses: addresses, addresses: addresses,
isFavorite: true, isFavorite: true,
id: "default", customId: "default",
); );
await ref.read(addressBookServiceProvider).editContact(self); await ref.read(addressBookServiceProvider).editContact(self);
}); });
@ -306,8 +304,8 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
.where((element) => element.isFavorite) .where((element) => element.isFavorite)
.map( .map(
(e) => AddressBookCard( (e) => AddressBookCard(
key: Key("favContactCard_${e.id}_key"), key: Key("favContactCard_${e.customId}_key"),
contactId: e.id, contactId: e.customId,
), ),
), ),
], ],
@ -352,8 +350,9 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
.matches(widget.filterTerm ?? _searchTerm, e)) .matches(widget.filterTerm ?? _searchTerm, e))
.map( .map(
(e) => AddressBookCard( (e) => AddressBookCard(
key: Key("desktopContactCard_${e.id}_key"), key:
contactId: e.id, Key("desktopContactCard_${e.customId}_key"),
contactId: e.customId,
), ),
), ),
], ],

View file

@ -2,8 +2,7 @@ import 'package:emojis/emoji.dart';
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/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/models/contact.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/pages/address_book_views/subviews/new_contact_address_entry_form.dart'; import 'package:stackwallet/pages/address_book_views/subviews/new_contact_address_entry_form.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart';
import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart';
@ -28,6 +27,7 @@ import 'package:stackwallet/widgets/emoji_select_sheet.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:uuid/uuid.dart';
class AddAddressBookEntryView extends ConsumerStatefulWidget { class AddAddressBookEntryView extends ConsumerStatefulWidget {
const AddAddressBookEntryView({ const AddAddressBookEntryView({
@ -688,11 +688,12 @@ class _AddAddressBookEntryViewState
forms[i].id)) forms[i].id))
.buildAddressEntry()); .buildAddressEntry());
} }
Contact contact = Contact( ContactEntry contact = ContactEntry(
emojiChar: _selectedEmoji?.char, emojiChar: _selectedEmoji?.char,
name: nameController.text, name: nameController.text,
addresses: entries, addresses: entries,
isFavorite: _isFavorite, isFavorite: _isFavorite,
customId: const Uuid().v1(),
); );
if (await ref if (await ref

View file

@ -1,8 +1,7 @@
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:flutter_svg/svg.dart';
import 'package:stackwallet/models/contact.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/pages/address_book_views/subviews/new_contact_address_entry_form.dart'; import 'package:stackwallet/pages/address_book_views/subviews/new_contact_address_entry_form.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart';
import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart';
@ -208,7 +207,7 @@ class _AddNewContactAddressViewState
.read(addressEntryDataProvider(0)) .read(addressEntryDataProvider(0))
.buildAddressEntry()); .buildAddressEntry());
Contact editedContact = ContactEntry editedContact =
contact.copyWith(addresses: entries); contact.copyWith(addresses: entries);
if (await ref if (await ref

View file

@ -1,9 +1,11 @@
import 'dart:io';
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:flutter_svg/svg.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_image_provider.dart'; import 'package:stackwallet/themes/coin_image_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.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';
@ -87,8 +89,10 @@ class CoinSelectSheet extends StatelessWidget {
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
child: Row( child: Row(
children: [ children: [
SvgPicture.asset( SvgPicture.file(
ref.watch(coinImageProvider(coin)), File(
ref.watch(coinImageProvider(coin)),
),
height: 20, height: 20,
width: 20, width: 20,
), ),

View file

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
@ -13,8 +15,8 @@ import 'package:stackwallet/providers/global/address_book_service_provider.dart'
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart';
import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.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';
@ -197,7 +199,7 @@ class _ContactDetailsViewState extends ConsumerState<ContactDetailsView> {
onPressed: () { onPressed: () {
ref ref
.read(addressBookServiceProvider) .read(addressBookServiceProvider)
.removeContact(_contact.id); .removeContact(_contact.customId);
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.of(context).pop(); Navigator.of(context).pop();
showFloatingFlushBar( showFloatingFlushBar(
@ -334,8 +336,10 @@ class _ContactDetailsViewState extends ConsumerState<ContactDetailsView> {
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
child: Row( child: Row(
children: [ children: [
SvgPicture.asset( SvgPicture.file(
ref.watch(coinIconProvider(e.coin)), File(
ref.watch(coinIconProvider(e.coin)),
),
height: 24, height: 24,
), ),
const SizedBox( const SizedBox(

View file

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
@ -9,8 +11,8 @@ import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.
import 'package:stackwallet/pages/send_view/send_view.dart'; import 'package:stackwallet/pages/send_view/send_view.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/themes/theme_providers.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart';
@ -110,11 +112,13 @@ class ContactPopUp extends ConsumerWidget {
), ),
child: contact.id == "default" child: contact.id == "default"
? Center( ? Center(
child: SvgPicture.asset( child: SvgPicture.file(
ref.watch( File(
themeProvider.select( ref.watch(
(value) => themeProvider.select(
value.assets.stackIcon, (value) => value
.assets.stackIcon,
),
), ),
), ),
width: 20, width: 20,
@ -211,9 +215,11 @@ class ContactPopUp extends ConsumerWidget {
const SizedBox( const SizedBox(
height: 2, height: 2,
), ),
SvgPicture.asset( SvgPicture.file(
ref.watch( File(
coinIconProvider(e.coin), ref.watch(
coinIconProvider(e.coin),
),
), ),
height: 24, height: 24,
), ),

View file

@ -1,8 +1,7 @@
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:flutter_svg/svg.dart';
import 'package:stackwallet/models/contact.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/pages/address_book_views/subviews/new_contact_address_entry_form.dart'; import 'package:stackwallet/pages/address_book_views/subviews/new_contact_address_entry_form.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart';
import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart';
@ -49,7 +48,7 @@ class _EditContactAddressViewState
late final BarcodeScannerInterface barcodeScanner; late final BarcodeScannerInterface barcodeScanner;
late final ClipboardInterface clipboard; late final ClipboardInterface clipboard;
Future<void> save(Contact contact) async { Future<void> save(ContactEntry contact) async {
if (FocusScope.of(context).hasFocus) { if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
await Future<void>.delayed( await Future<void>.delayed(
@ -73,7 +72,7 @@ class _EditContactAddressViewState
entries.insert(index, editedEntry); entries.insert(index, editedEntry);
Contact editedContact = contact.copyWith(addresses: entries); ContactEntry editedContact = contact.copyWith(addresses: entries);
if (await ref.read(addressBookServiceProvider).editContact(editedContact)) { if (await ref.read(addressBookServiceProvider).editContact(editedContact)) {
if (mounted) { if (mounted) {
@ -226,7 +225,8 @@ class _EditContactAddressViewState
); );
_addresses.remove(entry); _addresses.remove(entry);
Contact editedContact = contact.copyWith(addresses: _addresses); ContactEntry editedContact =
contact.copyWith(addresses: _addresses);
if (await ref if (await ref
.read(addressBookServiceProvider) .read(addressBookServiceProvider)
.editContact(editedContact)) { .editContact(editedContact)) {

View file

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -7,8 +9,8 @@ import 'package:stackwallet/pages/address_book_views/subviews/coin_select_sheet.
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
// import 'package:stackwallet/providers/global/should_show_lockscreen_on_resume_state_provider.dart'; // import 'package:stackwallet/providers/global/should_show_lockscreen_on_resume_state_provider.dart';
import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/address_utils.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart';
@ -141,8 +143,10 @@ class _NewContactAddressEntryFormState
padding: const EdgeInsets.symmetric(vertical: 4), padding: const EdgeInsets.symmetric(vertical: 4),
child: Row( child: Row(
children: [ children: [
SvgPicture.asset( SvgPicture.file(
ref.watch(coinIconProvider(coin)), File(
ref.watch(coinIconProvider(coin)),
),
height: 24, height: 24,
width: 24, width: 24,
), ),
@ -211,15 +215,17 @@ class _NewContactAddressEntryFormState
) )
: Row( : Row(
children: [ children: [
SvgPicture.asset( SvgPicture.file(
ref.watch( File(
coinIconProvider( ref.watch(
ref.watch( coinIconProvider(
addressEntryDataProvider(widget.id) ref.watch(
.select( addressEntryDataProvider(widget.id)
(value) => value.coin, .select(
), (value) => value.coin,
)!, ),
)!,
),
), ),
), ),
height: 20, height: 20,

View file

@ -144,7 +144,7 @@ class _ReceiveViewState extends ConsumerState<ReceiveView> {
aspectRatio: 1, aspectRatio: 1,
child: AppBarIconButton( child: AppBarIconButton(
semanticsLabel: semanticsLabel:
"Address List Pop-up Button. Opens A Pop-up For Adress List Button.", "Address List Pop-up Button. Opens A Pop-up For Address List Button.",
key: const Key("walletNetworkSettingsAddNewNodeViewButton"), key: const Key("walletNetworkSettingsAddNewNodeViewButton"),
size: 36, size: 36,
shadows: const [], shadows: const [],

View file

@ -35,6 +35,12 @@ class _ManageExplorerViewState extends ConsumerState<ManageExplorerView> {
.replaceAll("%5BTXID%5D", "[TXID]")); .replaceAll("%5BTXID%5D", "[TXID]"));
} }
@override
void dispose() {
textEditingController.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Background( return Background(
@ -93,13 +99,19 @@ class _ManageExplorerViewState extends ConsumerState<ManageExplorerView> {
style: Theme.of(context) style: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.getPrimaryEnabledButtonStyle(context), .getPrimaryEnabledButtonStyle(context),
onPressed: () { onPressed: () async {
textEditingController.text = textEditingController.text =
textEditingController.text.trim(); textEditingController.text.trim();
setBlockExplorerForCoin( await setBlockExplorerForCoin(
coin: widget.coin, coin: widget.coin,
url: Uri.parse(textEditingController.text)) url: Uri.parse(
.then((value) => Navigator.of(context).pop()); textEditingController.text,
),
);
if (mounted) {
Navigator.of(context).pop();
}
}, },
child: Text( child: Text(
"Save", "Save",

View file

@ -191,7 +191,8 @@ class GlobalSettingsView extends StatelessWidget {
title: "Appearance", title: "Appearance",
onPressed: () { onPressed: () {
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
AppearanceSettingsView.routeName); AppearanceSettingsView.routeName,
);
}, },
), ),
if (Platform.isIOS) if (Platform.isIOS)

View file

@ -5,10 +5,9 @@ import 'dart:typed_data';
import 'package:stack_wallet_backup/stack_wallet_backup.dart'; import 'package:stack_wallet_backup/stack_wallet_backup.dart';
import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/db/hive/db.dart';
import 'package:stackwallet/models/contact.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'; import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart'; import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/models/node_model.dart';
import 'package:stackwallet/models/stack_restoring_ui_state.dart'; import 'package:stackwallet/models/stack_restoring_ui_state.dart';
import 'package:stackwallet/models/trade_wallet_lookup.dart'; import 'package:stackwallet/models/trade_wallet_lookup.dart';
@ -266,7 +265,7 @@ abstract class SWB {
); );
AddressBookService addressBookService = AddressBookService(); AddressBookService addressBookService = AddressBookService();
var addresses = await addressBookService.addressBookEntries; var addresses = addressBookService.contacts;
backupJson['addressBookEntries'] = backupJson['addressBookEntries'] =
addresses.map((e) => e.toMap()).toList(); addresses.map((e) => e.toMap()).toList();
@ -799,7 +798,7 @@ abstract class SWB {
// contacts // contacts
final addressBookService = AddressBookService(); final addressBookService = AddressBookService();
final allContactIds = addressBookService.contacts.map((e) => e.id); final allContactIds = addressBookService.contacts.map((e) => e.customId);
if (addressBookEntries == null) { if (addressBookEntries == null) {
// if no contacts were present before attempted restore then delete any that // if no contacts were present before attempted restore then delete any that
@ -823,21 +822,20 @@ abstract class SWB {
List<ContactAddressEntry> addresses = []; List<ContactAddressEntry> addresses = [];
for (var address in (contact['addresses'] as List<dynamic>)) { for (var address in (contact['addresses'] as List<dynamic>)) {
addresses.add( addresses.add(
ContactAddressEntry( ContactAddressEntry()
coin: Coin.values ..coinName = address['coin'] as String
.firstWhere((element) => element.name == address['coin']), ..address = address['address'] as String
address: address['address'] as String, ..label = address['label'] as String
label: address['label'] as String, ..other = address['other'] as String?,
),
); );
} }
await addressBookService.editContact( await addressBookService.editContact(
Contact( ContactEntry(
emojiChar: contact['emoji'] as String?, emojiChar: contact['emoji'] as String?,
name: contact['name'] as String, name: contact['name'] as String,
addresses: addresses, addresses: addresses,
isFavorite: contact['isFavorite'] as bool, isFavorite: contact['isFavorite'] as bool,
id: contact['id'] as String, customId: contact['id'] as String,
), ),
); );
} else { } else {
@ -1026,21 +1024,20 @@ abstract class SWB {
List<ContactAddressEntry> addresses = []; List<ContactAddressEntry> addresses = [];
for (var address in (contact['addresses'] as List<dynamic>)) { for (var address in (contact['addresses'] as List<dynamic>)) {
addresses.add( addresses.add(
ContactAddressEntry( ContactAddressEntry()
coin: Coin.values ..coinName = address['coin'] as String
.firstWhere((element) => element.name == address['coin']), ..address = address['address'] as String
address: address['address'] as String, ..label = address['label'] as String
label: address['label'] as String, ..other = address['other'] as String?,
),
); );
} }
await addressBookService.addContact( await addressBookService.addContact(
Contact( ContactEntry(
emojiChar: contact['emoji'] as String?, emojiChar: contact['emoji'] as String?,
name: contact['name'] as String, name: contact['name'] as String,
addresses: addresses, addresses: addresses,
isFavorite: contact['isFavorite'] as bool, isFavorite: contact['isFavorite'] as bool,
id: contact['id'] as String, customId: contact['id'] as String,
), ),
); );
} }

View file

@ -1,3 +1,5 @@
import 'dart:io';
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:flutter_svg/svg.dart';
@ -6,8 +8,8 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/stack_back
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_item_card.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_item_card.dart';
import 'package:stackwallet/providers/stack_restore/stack_restoring_ui_state_provider.dart'; import 'package:stackwallet/providers/stack_restore/stack_restoring_ui_state_provider.dart';
import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/stack_restoring_status.dart'; import 'package:stackwallet/utilities/enums/stack_restoring_status.dart';
@ -81,8 +83,10 @@ class _RestoringWalletCardState extends ConsumerState<RestoringWalletCard> {
.extension<StackColors>()! .extension<StackColors>()!
.colorForCoin(coin), .colorForCoin(coin),
child: Center( child: Center(
child: SvgPicture.asset( child: SvgPicture.file(
ref.watch(coinIconProvider(coin)), File(
ref.watch(coinIconProvider(coin)),
),
height: 20, height: 20,
width: 20, width: 20,
), ),
@ -222,9 +226,11 @@ class _RestoringWalletCardState extends ConsumerState<RestoringWalletCard> {
.extension<StackColors>()! .extension<StackColors>()!
.colorForCoin(coin), .colorForCoin(coin),
child: Center( child: Center(
child: SvgPicture.asset( child: SvgPicture.file(
ref.watch( File(
coinIconProvider(coin), ref.watch(
coinIconProvider(coin),
),
), ),
height: 20, height: 20,
width: 20, width: 20,

View file

@ -1,10 +1,12 @@
import 'dart:io';
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/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/startup_preferences/startup_wallet_selection_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/startup_preferences/startup_wallet_selection_view.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.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';
import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/background.dart';
@ -236,22 +238,24 @@ class _StartupPreferencesViewState
.only(top: 12), .only(top: 12),
child: Row( child: Row(
children: [ children: [
SvgPicture.asset( SvgPicture.file(
ref.watch( File(
coinIconProvider( ref.watch(
ref coinIconProvider(
.watch( ref
walletsChangeNotifierProvider .watch(
.select( walletsChangeNotifierProvider
(value) => .select(
value.getManager( (value) =>
ref.watch( value.getManager(
prefsChangeNotifierProvider.select((value) => value.startupWalletId!), ref.watch(
prefsChangeNotifierProvider.select((value) => value.startupWalletId!),
),
), ),
), ),
), )
) .coin,
.coin, ),
), ),
), ),
), ),

View file

@ -1,9 +1,11 @@
import 'dart:io';
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:flutter_svg/svg.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.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';
import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/background.dart';
@ -102,9 +104,11 @@ class _StartupWalletSelectionViewState
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
child: SvgPicture.asset( child: SvgPicture.file(
ref.watch( File(
coinIconProvider(manager.coin), ref.watch(
coinIconProvider(manager.coin),
),
), ),
width: 20, width: 20,
height: 20, height: 20,

View file

@ -1,9 +1,11 @@
import 'dart:io';
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:flutter_svg/svg.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/sync_type_enum.dart'; import 'package:stackwallet/utilities/enums/sync_type_enum.dart';
@ -116,9 +118,11 @@ class WalletSyncingOptionsView extends ConsumerWidget {
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
child: SvgPicture.asset( child: SvgPicture.file(
ref.watch( File(
coinIconProvider(manager.coin), ref.watch(
coinIconProvider(manager.coin),
),
), ),
width: 20, width: 20,
height: 20, height: 20,

View file

@ -8,7 +8,6 @@ import 'package:qr_flutter/qr_flutter.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/services/mixins/xpubable.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart';
@ -177,7 +176,7 @@ class _XPubViewState extends ConsumerState<XPubView> {
child: child, child: child,
), ),
child: FutureBuilder( child: FutureBuilder(
future: (manager.wallet as XPubAble).xpub, future: manager.xpub,
builder: (context, AsyncSnapshot<String> snapshot) { builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.done && if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) { snapshot.hasData) {

View file

@ -33,7 +33,7 @@ import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
/// [eventBus] should only be set during testing /// [eventBus] should only be set during testing
class WalletSettingsView extends StatefulWidget { class WalletSettingsView extends ConsumerStatefulWidget {
const WalletSettingsView({ const WalletSettingsView({
Key? key, Key? key,
required this.walletId, required this.walletId,
@ -52,10 +52,10 @@ class WalletSettingsView extends StatefulWidget {
final EventBus? eventBus; final EventBus? eventBus;
@override @override
State<WalletSettingsView> createState() => _WalletSettingsViewState(); ConsumerState<WalletSettingsView> createState() => _WalletSettingsViewState();
} }
class _WalletSettingsViewState extends State<WalletSettingsView> { class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
late final String walletId; late final String walletId;
late final Coin coin; late final Coin coin;
late String xpub; late String xpub;
@ -74,7 +74,7 @@ class _WalletSettingsViewState extends State<WalletSettingsView> {
walletId = widget.walletId; walletId = widget.walletId;
coin = widget.coin; coin = widget.coin;
xPubEnabled = xPubEnabled =
coin != Coin.monero && coin != Coin.wownero && coin != Coin.epicCash; ref.read(walletsChangeNotifierProvider).getManager(walletId).hasXPub;
xpub = ""; xpub = "";
_currentSyncStatus = widget.initialSyncStatus; _currentSyncStatus = widget.initialSyncStatus;

View file

@ -308,14 +308,23 @@ class TokenOptionsButton extends StatelessWidget {
child: child, child: child,
), ),
), ),
child: SvgPicture.file( child: iconAssetPathSVG.startsWith("assets/")
File(iconAssetPathSVG), ? SvgPicture.asset(
color: Theme.of(context) iconAssetPathSVG,
.extension<StackColors>()! color: Theme.of(context)
.tokenSummaryIcon, .extension<StackColors>()!
width: iconSize, .tokenSummaryIcon,
height: iconSize, width: iconSize,
), height: iconSize,
)
: SvgPicture.file(
File(iconAssetPathSVG),
color: Theme.of(context)
.extension<StackColors>()!
.tokenSummaryIcon,
width: iconSize,
height: iconSize,
),
), ),
), ),
), ),

View file

@ -23,19 +23,6 @@ class TxIcon extends ConsumerWidget {
static const Size size = Size(32, 32); static const Size size = Size(32, 32);
// String _getBundleAssetName(
// bool isCancelled, bool isReceived, bool isPending, BuildContext context) {
// if (!isReceived && transaction.subType == TransactionSubType.mint) {
// if (isCancelled) {
// return Assets.svg.anonymizeFailed;
// }
// if (isPending) {
// return Assets.svg.anonymizePending;
// }
// return Assets.svg.anonymize;
// }
// }
String _getAssetName( String _getAssetName(
bool isCancelled, bool isReceived, bool isPending, ThemeAssets assets) { bool isCancelled, bool isReceived, bool isPending, ThemeAssets assets) {
if (!isReceived && transaction.subType == TransactionSubType.mint) { if (!isReceived && transaction.subType == TransactionSubType.mint) {

View file

@ -3,8 +3,8 @@ import 'dart:async';
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:flutter_svg/svg.dart';
import 'package:stackwallet/models/contact.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/models/transaction_filter.dart'; import 'package:stackwallet/models/transaction_filter.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/wallet_view/sub_widgets/tx_icon.dart'; import 'package:stackwallet/pages/wallet_view/sub_widgets/tx_icon.dart';
@ -120,8 +120,8 @@ class _TransactionDetailsViewState extends ConsumerState<AllTransactionsView> {
}).toList(); }).toList();
} }
bool _isKeywordMatch(Transaction tx, String keyword, List<Contact> contacts, bool _isKeywordMatch(Transaction tx, String keyword,
Map<String, String> notes) { List<ContactEntry> contacts, Map<String, String> notes) {
if (keyword.isEmpty) { if (keyword.isEmpty) {
return true; return true;
} }

View file

@ -1,8 +1,7 @@
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:flutter_svg/svg.dart';
import 'package:stackwallet/models/contact.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/pages/address_book_views/subviews/add_address_book_entry_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/add_address_book_entry_view.dart';
import 'package:stackwallet/pages/address_book_views/subviews/address_book_filter_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/address_book_filter_view.dart';
import 'package:stackwallet/pages_desktop_specific/address_book_view/subwidgets/desktop_address_book_scaffold.dart'; import 'package:stackwallet/pages_desktop_specific/address_book_view/subwidgets/desktop_address_book_scaffold.dart';
@ -105,19 +104,18 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
final managers = ref.read(walletsChangeNotifierProvider).managers; final managers = ref.read(walletsChangeNotifierProvider).managers;
for (final manager in managers) { for (final manager in managers) {
addresses.add( addresses.add(
ContactAddressEntry( ContactAddressEntry()
coin: manager.coin, ..coinName = manager.coin.name
address: await manager.currentReceivingAddress, ..address = await manager.currentReceivingAddress
label: "Current Receiving", ..label = "Current Receiving"
other: manager.walletName, ..other = manager.walletName,
),
); );
} }
final self = Contact( final self = ContactEntry(
name: "My Stack", name: "My Stack",
addresses: addresses, addresses: addresses,
isFavorite: true, isFavorite: true,
id: "default", customId: "default",
); );
await ref.read(addressBookServiceProvider).editContact(self); await ref.read(addressBookServiceProvider).editContact(self);
}); });
@ -323,14 +321,14 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
.extension<StackColors>()! .extension<StackColors>()!
.accentColorDark .accentColorDark
.withOpacity( .withOpacity(
currentContactId == favorites[i].id currentContactId == favorites[i].customId
? 0.08 ? 0.08
: 0, : 0,
), ),
child: RawMaterialButton( child: RawMaterialButton(
onPressed: () { onPressed: () {
setState(() { setState(() {
currentContactId = favorites[i].id; currentContactId = favorites[i].customId;
}); });
}, },
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -346,8 +344,8 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
), ),
child: AddressBookCard( child: AddressBookCard(
key: Key( key: Key(
"favContactCard_${favorites[i].id}_key"), "favContactCard_${favorites[i].customId}_key"),
contactId: favorites[i].id, contactId: favorites[i].customId,
desktopSendFrom: false, desktopSendFrom: false,
), ),
), ),
@ -393,14 +391,16 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
.extension<StackColors>()! .extension<StackColors>()!
.accentColorDark .accentColorDark
.withOpacity( .withOpacity(
currentContactId == allContacts[i].id currentContactId ==
allContacts[i].customId
? 0.08 ? 0.08
: 0, : 0,
), ),
child: RawMaterialButton( child: RawMaterialButton(
onPressed: () { onPressed: () {
setState(() { setState(() {
currentContactId = allContacts[i].id; currentContactId =
allContacts[i].customId;
}); });
}, },
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -416,8 +416,8 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
), ),
child: AddressBookCard( child: AddressBookCard(
key: Key( key: Key(
"favContactCard_${allContacts[i].id}_key"), "favContactCard_${allContacts[i].customId}_key"),
contactId: allContacts[i].id, contactId: allContacts[i].customId,
desktopSendFrom: false, desktopSendFrom: false,
), ),
), ),

View file

@ -2,12 +2,12 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/models/contact_address_entry.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_address_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_address_view.dart';
import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.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';

View file

@ -1,8 +1,11 @@
import 'dart:io';
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/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stackwallet/models/contact.dart'; import 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/pages/address_book_views/subviews/add_new_contact_address_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/add_new_contact_address_view.dart';
import 'package:stackwallet/pages_desktop_specific/address_book_view/subwidgets/desktop_address_card.dart'; import 'package:stackwallet/pages_desktop_specific/address_book_view/subwidgets/desktop_address_card.dart';
@ -24,8 +27,6 @@ import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/transaction_card.dart'; import 'package:stackwallet/widgets/transaction_card.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
import '../../../db/isar/main_db.dart';
class DesktopContactDetails extends ConsumerStatefulWidget { class DesktopContactDetails extends ConsumerStatefulWidget {
const DesktopContactDetails({ const DesktopContactDetails({
Key? key, Key? key,
@ -42,7 +43,7 @@ class DesktopContactDetails extends ConsumerStatefulWidget {
class _DesktopContactDetailsState extends ConsumerState<DesktopContactDetails> { class _DesktopContactDetailsState extends ConsumerState<DesktopContactDetails> {
List<Tuple2<String, Transaction>> _cachedTransactions = []; List<Tuple2<String, Transaction>> _cachedTransactions = [];
bool _contactHasAddress(String address, Contact contact) { bool _contactHasAddress(String address, ContactEntry contact) {
for (final entry in contact.addresses) { for (final entry in contact.addresses) {
if (entry.address == address) { if (entry.address == address) {
return true; return true;
@ -82,7 +83,7 @@ class _DesktopContactDetailsState extends ConsumerState<DesktopContactDetails> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// provider hack to prevent trying to update widget with deleted contact // provider hack to prevent trying to update widget with deleted contact
Contact? _contact; ContactEntry? _contact;
try { try {
_contact = ref.watch(addressBookServiceProvider _contact = ref.watch(addressBookServiceProvider
.select((value) => value.getContactById(widget.contactId))); .select((value) => value.getContactById(widget.contactId)));
@ -117,12 +118,14 @@ class _DesktopContactDetailsState extends ConsumerState<DesktopContactDetails> {
.textFieldDefaultBG, .textFieldDefaultBG,
borderRadius: BorderRadius.circular(32), borderRadius: BorderRadius.circular(32),
), ),
child: contact.id == "default" child: contact.customId == "default"
? Center( ? Center(
child: SvgPicture.asset( child: SvgPicture.file(
ref.watch( File(
themeProvider.select( ref.watch(
(value) => value.assets.stackIcon, themeProvider.select(
(value) => value.assets.stackIcon,
),
), ),
), ),
width: 32, width: 32,
@ -159,7 +162,7 @@ class _DesktopContactDetailsState extends ConsumerState<DesktopContactDetails> {
barrierColor: Colors.transparent, barrierColor: Colors.transparent,
builder: (context) { builder: (context) {
return DesktopContactOptionsMenuPopup( return DesktopContactOptionsMenuPopup(
contactId: contact.id, contactId: contact.customId,
); );
}, },
); );
@ -261,7 +264,7 @@ class _DesktopContactDetailsState extends ConsumerState<DesktopContactDetails> {
padding: const EdgeInsets.all(18), padding: const EdgeInsets.all(18),
child: DesktopAddressCard( child: DesktopAddressCard(
entry: contact.addresses[i], entry: contact.addresses[i],
contactId: contact.id, contactId: contact.customId,
), ),
), ),
], ],

View file

@ -147,7 +147,7 @@ class _DesktopContactOptionsMenuPopupState
onPressed: () { onPressed: () {
ref ref
.read(addressBookServiceProvider) .read(addressBookServiceProvider)
.removeContact(contact.id); .removeContact(contact.customId);
Navigator.of(context).pop(); Navigator.of(context).pop();
showFloatingFlushBar( showFloatingFlushBar(
type: FlushBarType.success, type: FlushBarType.success,

View file

@ -1,3 +1,5 @@
import 'dart:io';
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:flutter_svg/svg.dart';
@ -6,8 +8,8 @@ import 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
import 'package:stackwallet/pages_desktop_specific/coin_control/utxo_row.dart'; import 'package:stackwallet/pages_desktop_specific/coin_control/utxo_row.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
@ -359,8 +361,10 @@ class _DesktopCoinControlUseDialogState
color: Colors.transparent, color: Colors.transparent,
child: Row( child: Row(
children: [ children: [
SvgPicture.asset( SvgPicture.file(
ref.watch(coinIconProvider(coin)), File(
ref.watch(coinIconProvider(coin)),
),
width: 24, width: 24,
height: 24, height: 24,
), ),

View file

@ -1,3 +1,5 @@
import 'dart:io';
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:flutter_svg/svg.dart';
@ -7,8 +9,8 @@ import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
import 'package:stackwallet/pages_desktop_specific/coin_control/freeze_button.dart'; import 'package:stackwallet/pages_desktop_specific/coin_control/freeze_button.dart';
import 'package:stackwallet/pages_desktop_specific/coin_control/utxo_row.dart'; import 'package:stackwallet/pages_desktop_specific/coin_control/utxo_row.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -343,8 +345,10 @@ class _DesktopCoinControlViewState
color: Colors.transparent, color: Colors.transparent,
child: Row( child: Row(
children: [ children: [
SvgPicture.asset( SvgPicture.file(
ref.watch(coinIconProvider(coin)), File(
ref.watch(coinIconProvider(coin)),
),
width: 24, width: 24,
height: 24, height: 24,
), ),

View file

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -522,10 +523,14 @@ class _DesktopTradeRowCardState extends ConsumerState<DesktopTradeRowCard> {
borderRadius: BorderRadius.circular(32), borderRadius: BorderRadius.circular(32),
), ),
child: Center( child: Center(
child: SvgPicture.asset( child: SvgPicture.file(
_fetchIconAssetForStatus( File(
trade.status, _fetchIconAssetForStatus(
ref.watch(themeProvider.select((value) => value.assets)), trade.status,
ref.watch(
themeProvider.select((value) => value.assets),
),
),
), ),
width: 32, width: 32,
height: 32, height: 32,

View file

@ -1,3 +1,5 @@
import 'dart:io';
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:flutter_svg/svg.dart';
@ -81,28 +83,36 @@ class DesktopNotificationsIcon extends ConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
return SvgPicture.asset( return ref.watch(notificationsProvider
ref.watch(notificationsProvider .select((value) => value.hasUnreadNotifications))
.select((value) => value.hasUnreadNotifications)) ? SvgPicture.file(
? ref.watch( File(
themeProvider.select( ref.watch(
(value) => value.assets.bellNew, themeProvider.select(
(value) => value.assets.bellNew,
),
), ),
) ),
: Assets.svg.bell, width: 20,
width: 20, height: 20,
height: 20, )
color: ref.watch(notificationsProvider : SvgPicture.asset(
.select((value) => value.hasUnreadNotifications)) Assets.svg.bell,
? null width: 20,
: DesktopMenuItemId.notifications == height: 20,
ref.watch(currentDesktopMenuItemProvider.state).state color: ref.watch(notificationsProvider
? Theme.of(context).extension<StackColors>()!.accentColorDark .select((value) => value.hasUnreadNotifications))
: Theme.of(context) ? null
.extension<StackColors>()! : DesktopMenuItemId.notifications ==
.accentColorDark ref.watch(currentDesktopMenuItemProvider.state).state
.withOpacity(0.8), ? Theme.of(context)
); .extension<StackColors>()!
.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
);
} }
} }

View file

@ -1,3 +1,5 @@
import 'dart:io';
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/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
@ -53,10 +55,12 @@ class DesktopMyStackTitle extends ConsumerWidget {
SizedBox( SizedBox(
width: 32, width: 32,
height: 32, height: 32,
child: SvgPicture.asset( child: SvgPicture.file(
ref.watch( File(
themeProvider.select( ref.watch(
(value) => value.assets.stackIcon, themeProvider.select(
(value) => value.assets.stackIcon,
),
), ),
), ),
), ),

View file

@ -1,3 +1,5 @@
import 'dart:io';
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:flutter_svg/svg.dart';
@ -10,8 +12,8 @@ import 'package:stackwallet/providers/global/price_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart'; import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
import 'package:stackwallet/services/coins/firo/firo_wallet.dart'; import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart';
import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart';
@ -81,8 +83,10 @@ class _DesktopPaynymSendDialogState
// Theme.of(context).extension<StackColors>()!.textSubtitle4, // Theme.of(context).extension<StackColors>()!.textSubtitle4,
child: Row( child: Row(
children: [ children: [
SvgPicture.asset( SvgPicture.file(
ref.watch(coinIconProvider(coin)), File(
ref.watch(coinIconProvider(coin)),
),
width: 36, width: 36,
height: 36, height: 36,
), ),

View file

@ -1,10 +1,12 @@
import 'dart:io';
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:flutter_svg/svg.dart';
import 'package:stackwallet/pages/wallets_view/wallets_overview.dart'; import 'package:stackwallet/pages/wallets_view/wallets_overview.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount.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';
@ -141,8 +143,10 @@ class _DesktopWalletSummaryRowState
flex: 4, flex: 4,
child: Row( child: Row(
children: [ children: [
SvgPicture.asset( SvgPicture.file(
ref.watch(coinIconProvider(widget.coin)), File(
ref.watch(coinIconProvider(widget.coin)),
),
width: 28, width: 28,
height: 28, height: 28,
), ),

View file

@ -1,7 +1,7 @@
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/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/models/contact.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/sub_widgets/contact_list_item.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/sub_widgets/contact_list_item.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
@ -34,7 +34,7 @@ class _AddressBookAddressChooserState extends State<AddressBookAddressChooser> {
String _searchTerm = ""; String _searchTerm = "";
int _compareContactFavorite(Contact a, Contact b) { int _compareContactFavorite(ContactEntry a, ContactEntry b) {
if (a.isFavorite && b.isFavorite) { if (a.isFavorite && b.isFavorite) {
return 0; return 0;
} else if (a.isFavorite) { } else if (a.isFavorite) {
@ -44,8 +44,8 @@ class _AddressBookAddressChooserState extends State<AddressBookAddressChooser> {
} }
} }
List<Contact> pullOutFavorites(List<Contact> contacts) { List<ContactEntry> pullOutFavorites(List<ContactEntry> contacts) {
final List<Contact> favorites = []; final List<ContactEntry> favorites = [];
contacts.removeWhere((contact) { contacts.removeWhere((contact) {
if (contact.isFavorite) { if (contact.isFavorite) {
favorites.add(contact); favorites.add(contact);
@ -57,7 +57,7 @@ class _AddressBookAddressChooserState extends State<AddressBookAddressChooser> {
return favorites; return favorites;
} }
List<Contact> filter(List<Contact> contacts, String searchTerm) { List<ContactEntry> filter(List<ContactEntry> contacts, String searchTerm) {
if (widget.coin != null) { if (widget.coin != null) {
contacts.removeWhere( contacts.removeWhere(
(e) => e.addresses.where((a) => a.coin == widget.coin!).isEmpty); (e) => e.addresses.where((a) => a.coin == widget.coin!).isEmpty);
@ -75,7 +75,7 @@ class _AddressBookAddressChooserState extends State<AddressBookAddressChooser> {
return contacts; return contacts;
} }
bool _matches(String term, Contact contact) { bool _matches(String term, ContactEntry contact) {
final text = term.toLowerCase(); final text = term.toLowerCase();
if (contact.name.toLowerCase().contains(text)) { if (contact.name.toLowerCase().contains(text)) {
return true; return true;
@ -191,7 +191,7 @@ class _AddressBookAddressChooserState extends State<AddressBookAddressChooser> {
), ),
child: Consumer( child: Consumer(
builder: (context, ref, _) { builder: (context, ref, _) {
List<Contact> contacts = ref List<ContactEntry> contacts = ref
.watch(addressBookServiceProvider .watch(addressBookServiceProvider
.select((value) => value.contacts)) .select((value) => value.contacts))
.toList(); .toList();
@ -228,7 +228,7 @@ class _AddressBookAddressChooserState extends State<AddressBookAddressChooser> {
), ),
); );
} else if (index < favorites.length + 1) { } else if (index < favorites.length + 1) {
final id = favorites[index - 1].id; final id = favorites[index - 1].customId;
return ContactListItem( return ContactListItem(
key: Key("contactContactListItem_${id}_key"), key: Key("contactContactListItem_${id}_key"),
contactId: id, contactId: id,
@ -248,7 +248,8 @@ class _AddressBookAddressChooserState extends State<AddressBookAddressChooser> {
), ),
); );
} else { } else {
final id = contacts[index - favorites.length - 2].id; final id =
contacts[index - favorites.length - 2].customId;
return ContactListItem( return ContactListItem(
key: Key("contactContactListItem_${id}_key"), key: Key("contactContactListItem_${id}_key"),
contactId: id, contactId: id,

View file

@ -94,10 +94,12 @@ class _ForgotPasswordDesktopViewState
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SvgPicture.asset( SvgPicture.file(
ref.watch( File(
themeProvider.select( ref.watch(
(value) => value.assets.stackIcon, themeProvider.select(
(value) => value.assets.stackIcon,
),
), ),
), ),
width: 100, width: 100,

View file

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
@ -54,7 +55,7 @@ class _DesktopLoginViewState extends ConsumerState<DesktopLoginView> {
int dbVersion = DB.instance.get<dynamic>( int dbVersion = DB.instance.get<dynamic>(
boxName: DB.boxNameDBInfo, key: "hive_data_version") as int? ?? boxName: DB.boxNameDBInfo, key: "hive_data_version") as int? ??
0; 0;
if (dbVersion < Constants.currentHiveDbVersion) { if (dbVersion < Constants.currentDataVersion) {
try { try {
await DbVersionMigrator().migrate( await DbVersionMigrator().migrate(
dbVersion, dbVersion,
@ -166,10 +167,12 @@ class _DesktopLoginViewState extends ConsumerState<DesktopLoginView> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SvgPicture.asset( SvgPicture.file(
ref.watch( File(
themeProvider.select( ref.watch(
(value) => value.assets.stackIcon, themeProvider.select(
(value) => value.assets.stackIcon,
),
), ),
), ),
width: 100, width: 100,

View file

@ -1,3 +1,5 @@
import 'dart:io';
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:flutter_svg/svg.dart';
@ -47,10 +49,12 @@ class _ForgotPasswordDesktopViewState
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SvgPicture.asset( SvgPicture.file(
ref.watch( File(
themeProvider.select( ref.watch(
(value) => value.assets.stackIcon, themeProvider.select(
(value) => value.assets.stackIcon,
),
), ),
), ),
width: 100, width: 100,

View file

@ -2,6 +2,7 @@ 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:flutter_svg/svg.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/advanced_settings/debug_info_dialog.dart'; import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/advanced_settings/debug_info_dialog.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/advanced_settings/desktop_manage_block_explorers_dialog.dart';
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/advanced_settings/stack_privacy_dialog.dart'; import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/advanced_settings/stack_privacy_dialog.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
@ -58,7 +59,7 @@ class _AdvancedSettings extends ConsumerState<AdvancedSettings> {
), ),
TextSpan( TextSpan(
text: text:
"\n\nConfigurate these settings only if you know what you are doing!", "\n\nConfigure these settings only if you know what you are doing!",
style: STextStyles.desktopTextExtraExtraSmall( style: STextStyles.desktopTextExtraExtraSmall(
context), context),
), ),
@ -183,7 +184,7 @@ class _AdvancedSettings extends ConsumerState<AdvancedSettings> {
PrimaryButton( PrimaryButton(
label: "Change", label: "Change",
buttonHeight: ButtonHeight.xs, buttonHeight: ButtonHeight.xs,
width: 86, width: 101,
onPressed: () async { onPressed: () async {
await showDialog<dynamic>( await showDialog<dynamic>(
context: context, context: context,
@ -207,8 +208,6 @@ class _AdvancedSettings extends ConsumerState<AdvancedSettings> {
thickness: 0.5, thickness: 0.5,
), ),
), ),
/// TODO: Make a dialog popup
Padding( Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Row( child: Row(
@ -241,6 +240,44 @@ class _AdvancedSettings extends ConsumerState<AdvancedSettings> {
], ],
), ),
), ),
const Padding(
padding: EdgeInsets.all(10.0),
child: Divider(
thickness: 0.5,
),
),
Padding(
padding: const EdgeInsets.all(10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Block explorers",
style: STextStyles.desktopTextExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark),
textAlign: TextAlign.left,
),
PrimaryButton(
buttonHeight: ButtonHeight.xs,
label: "Edit",
width: 101,
onPressed: () async {
await showDialog<dynamic>(
context: context,
useSafeArea: false,
barrierDismissible: true,
builder: (context) {
return const DesktopManageBlockExplorersDialog();
},
);
},
),
],
),
),
], ],
), ),
), ),

View file

@ -0,0 +1,266 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/block_explorers.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
class DesktopManageBlockExplorersDialog extends ConsumerWidget {
const DesktopManageBlockExplorersDialog({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
bool showTestNet = ref.watch(
prefsChangeNotifierProvider.select((value) => value.showTestNetCoins),
);
final List<Coin> coins = showTestNet
? Coin.values
: Coin.values.sublist(0, Coin.values.length - kTestNetCoinCount);
return DesktopDialog(
maxHeight: 850,
maxWidth: 600,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.all(32),
child: Text(
"Manage block explorers",
style: STextStyles.desktopH3(context),
textAlign: TextAlign.center,
),
),
const DesktopDialogCloseButton(),
],
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(
left: 32,
right: 32,
bottom: 32,
),
child: ListView.separated(
itemCount: coins.length,
separatorBuilder: (_, __) => const SizedBox(
height: 12,
),
itemBuilder: (_, index) {
final coin = coins[index];
return RoundedWhiteContainer(
padding: const EdgeInsets.symmetric(
vertical: 16,
horizontal: 14,
),
borderColor: Theme.of(context)
.extension<StackColors>()!
.textSubtitle6,
child: Row(
children: [
SvgPicture.file(
File(
ref.watch(coinIconProvider(coin)),
),
width: 24,
height: 24,
),
const SizedBox(
width: 12,
),
Expanded(
child: Text(
"${coin.prettyName} block explorer",
style: STextStyles.desktopTextSmall(context),
),
),
const SizedBox(
width: 12,
),
SvgPicture.asset(
Assets.svg.chevronRight,
width: 20,
height: 20,
),
],
),
onPressed: () {
showDialog<dynamic>(
context: context,
useSafeArea: false,
barrierDismissible: true,
builder: (context) {
return _DesktopEditBlockExplorerDialog(
coin: coin,
);
},
);
},
);
},
),
),
),
],
),
);
}
}
class _DesktopEditBlockExplorerDialog extends ConsumerStatefulWidget {
const _DesktopEditBlockExplorerDialog({Key? key, required this.coin})
: super(key: key);
final Coin coin;
@override
ConsumerState<_DesktopEditBlockExplorerDialog> createState() =>
_DesktopEditBlockExplorerDialogState();
}
class _DesktopEditBlockExplorerDialogState
extends ConsumerState<_DesktopEditBlockExplorerDialog> {
late final TextEditingController _textEditingController;
late final FocusNode _focusNode;
@override
void initState() {
_textEditingController = TextEditingController(
text:
getBlockExplorerTransactionUrlFor(coin: widget.coin, txid: "[TXID]")
.toString()
.replaceAll("%5BTXID%5D", "[TXID]"));
_focusNode = FocusNode();
super.initState();
}
@override
void dispose() {
_textEditingController.dispose();
_focusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return DesktopDialog(
maxHeight: double.infinity,
maxWidth: 600,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.all(32),
child: Text(
"${widget.coin.prettyName} block explorer",
style: STextStyles.desktopH3(context),
textAlign: TextAlign.center,
),
),
const DesktopDialogCloseButton(),
],
),
Padding(
padding: const EdgeInsets.only(
left: 32,
right: 32,
bottom: 32,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autocorrect: false,
enableSuggestions: false,
key: const Key("addCustomNodeNodeAddressFieldKey"),
controller: _textEditingController,
focusNode: _focusNode,
style: STextStyles.field(context),
),
),
const SizedBox(
height: 16,
),
RoundedWhiteContainer(
borderColor:
Theme.of(context).extension<StackColors>()!.textSubtitle6,
child: Text(
"Edit your block explorer above. Keep in mind that"
" every block explorer has a slightly different URL scheme."
"\n\n"
"Paste in your block explorer of choice, then edit in"
" [TXID] where the transaction ID should go, and Stack"
" Wallet will auto fill the transaction ID in that place"
" of the URL.",
style: STextStyles.desktopTextExtraExtraSmall(context),
),
),
const SizedBox(
height: 16,
),
Row(
children: [
Expanded(
child: SecondaryButton(
label: "Cancel",
buttonHeight: ButtonHeight.l,
onPressed: Navigator.of(context).pop,
),
),
const SizedBox(
width: 16,
),
Expanded(
child: PrimaryButton(
label: "Save",
buttonHeight: ButtonHeight.l,
onPressed: () async {
_textEditingController.text =
_textEditingController.text.trim();
await setBlockExplorerForCoin(
coin: widget.coin,
url: Uri.parse(
_textEditingController.text,
),
);
if (mounted) {
Navigator.of(context).pop();
}
},
),
),
],
)
],
),
)
],
),
);
}
}

View file

@ -6,8 +6,8 @@ import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -250,8 +250,10 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
children: [ children: [
Row( Row(
children: [ children: [
SvgPicture.asset( SvgPicture.file(
ref.watch(coinIconProvider(coin)), File(
ref.watch(coinIconProvider(coin)),
),
width: 24, width: 24,
height: 24, height: 24,
), ),

View file

@ -5,7 +5,6 @@ import 'package:isar/isar.dart';
import 'package:stackwallet/models/add_wallet_list_entity/add_wallet_list_entity.dart'; import 'package:stackwallet/models/add_wallet_list_entity/add_wallet_list_entity.dart';
import 'package:stackwallet/models/add_wallet_list_entity/sub_classes/eth_token_entity.dart'; import 'package:stackwallet/models/add_wallet_list_entity/sub_classes/eth_token_entity.dart';
import 'package:stackwallet/models/buy/response_objects/quote.dart'; import 'package:stackwallet/models/buy/response_objects/quote.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart'; import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart';
@ -153,6 +152,8 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/widgets/choose_coin_view.dart'; import 'package:stackwallet/widgets/choose_coin_view.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
import 'models/isar/models/contact_entry.dart';
class RouteGenerator { class RouteGenerator {
static const bool useMaterialPageRoute = true; static const bool useMaterialPageRoute = true;

View file

@ -1,55 +1,33 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/models/contact.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/logger.dart';
class AddressBookService extends ChangeNotifier { class AddressBookService extends ChangeNotifier {
Contact getContactById(String id) { ContactEntry getContactById(String id) {
final json = DB.instance ContactEntry? contactEntry = MainDB.instance.getContactEntry(id: id);
.get<dynamic>(boxName: DB.boxNameAddressBook, key: id) as Map?; if (contactEntry == null) {
if (json == null) {
Logging.instance
.log("Attempted to get non existing contact", level: LogLevel.Fatal);
throw Exception('Contact ID "$id" not found!'); throw Exception('Contact ID "$id" not found!');
} else {
return contactEntry;
} }
return Contact.fromJson(Map<String, dynamic>.from(json));
} }
List<Contact> get contacts { List<ContactEntry> get contacts => MainDB.instance.getContactEntries();
final keys = List<String>.from(
DB.instance.keys<dynamic>(boxName: DB.boxNameAddressBook));
final _contacts = keys
.map((id) => Contact.fromJson(Map<String, dynamic>.from(DB.instance
.get<dynamic>(boxName: DB.boxNameAddressBook, key: id) as Map)))
.toList(growable: false);
_contacts
.sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase()));
return _contacts;
}
Future<List<Contact>>? _addressBookEntries;
Future<List<Contact>> get addressBookEntries =>
_addressBookEntries ??= _fetchAddressBookEntries();
// Load address book contact entries
Future<List<Contact>> _fetchAddressBookEntries() async {
return contacts;
}
/// search address book entries /// search address book entries
//TODO optimize address book search? //TODO search using isar queries
Future<List<Contact>> search(String text) async { Future<List<ContactEntry>> search(String text) async {
if (text.isEmpty) return addressBookEntries; if (text.isEmpty) return contacts;
var results = (await addressBookEntries).toList(); var results = contacts.toList();
results.retainWhere((contact) => matches(text, contact)); results.retainWhere((contact) => matches(text, contact));
return results; return results;
} }
bool matches(String term, Contact contact) { bool matches(String term, ContactEntry contact) {
if (term.isEmpty) { if (term.isEmpty) {
return true; return true;
} }
@ -73,44 +51,27 @@ class AddressBookService extends ChangeNotifier {
/// ///
/// returns false if it provided [contact]'s id already exists in the database /// returns false if it provided [contact]'s id already exists in the database
/// other true if the [contact] was saved /// other true if the [contact] was saved
Future<bool> addContact(Contact contact) async { Future<bool> addContact(ContactEntry contact) async {
if (DB.instance.containsKey<dynamic>( if (await MainDB.instance.isContactEntryExists(id: contact.customId)) {
boxName: DB.boxNameAddressBook, key: contact.id)) {
return false; return false;
} else {
await MainDB.instance.putContactEntry(contactEntry: contact);
notifyListeners();
return true;
} }
await DB.instance.put<dynamic>(
boxName: DB.boxNameAddressBook,
key: contact.id,
value: contact.toMap());
Logging.instance.log("add address book entry saved", level: LogLevel.Info);
await _refreshAddressBookEntries();
return true;
} }
/// Edit contact /// Edit contact
Future<bool> editContact(Contact editedContact) async { Future<bool> editContact(ContactEntry editedContact) async {
// over write the contact with edited version // over write the contact with edited version
await DB.instance.put<dynamic>( await MainDB.instance.putContactEntry(contactEntry: editedContact);
boxName: DB.boxNameAddressBook, notifyListeners();
key: editedContact.id,
value: editedContact.toMap());
Logging.instance.log("edit address book entry saved", level: LogLevel.Info);
await _refreshAddressBookEntries();
return true; return true;
} }
/// Remove address book contact entry from db if it exists /// Remove address book contact entry from db if it exists
Future<void> removeContact(String id) async { Future<void> removeContact(String id) async {
await DB.instance.delete<dynamic>(key: id, boxName: DB.boxNameAddressBook); await MainDB.instance.deleteContactEntry(id: id);
await _refreshAddressBookEntries();
}
Future<void> _refreshAddressBookEntries() async {
final newAddressBookEntries = await _fetchAddressBookEntries();
_addressBookEntries = Future(() => newAddressBookEntries);
notifyListeners(); notifyListeners();
} }
} }

View file

@ -53,11 +53,11 @@ import 'package:uuid/uuid.dart';
const int MINIMUM_CONFIRMATIONS = 1; const int MINIMUM_CONFIRMATIONS = 1;
final Amount DUST_LIMIT = Amount( final Amount DUST_LIMIT = Amount(
rawValue: BigInt.from(294), rawValue: BigInt.from(294),
fractionDigits: Coin.particl.decimals, fractionDigits: Coin.bitcoin.decimals,
); );
final Amount DUST_LIMIT_P2PKH = Amount( final Amount DUST_LIMIT_P2PKH = Amount(
rawValue: BigInt.from(546), rawValue: BigInt.from(546),
fractionDigits: Coin.particl.decimals, fractionDigits: Coin.bitcoin.decimals,
); );
const String GENESIS_HASH_MAINNET = const String GENESIS_HASH_MAINNET =

View file

@ -71,7 +71,6 @@ String constructDerivePath({
case 0x80: // bch mainnet wif case 0x80: // bch mainnet wif
switch (derivePathType) { switch (derivePathType) {
case DerivePathType.bip44: case DerivePathType.bip44:
case DerivePathType.bip49:
coinType = 145; // bch mainnet coinType = 145; // bch mainnet
break; break;
case DerivePathType.bch44: // bitcoin.com wallet specific case DerivePathType.bch44: // bitcoin.com wallet specific
@ -95,9 +94,6 @@ String constructDerivePath({
case DerivePathType.bch44: case DerivePathType.bch44:
purpose = 44; purpose = 44;
break; break;
case DerivePathType.bip49:
purpose = 49;
break;
default: default:
throw Exception("DerivePathType $derivePathType not supported"); throw Exception("DerivePathType $derivePathType not supported");
} }
@ -283,10 +279,6 @@ class BitcoinCashWallet extends CoinServiceAPI
return DerivePathType.bip44; return DerivePathType.bip44;
} }
if (decodeBase58[0] == _network.scriptHash) {
// P2SH
return DerivePathType.bip49;
}
throw ArgumentError('Invalid version or Network mismatch'); throw ArgumentError('Invalid version or Network mismatch');
} else { } else {
try { try {
@ -419,15 +411,6 @@ class BitcoinCashWallet extends CoinServiceAPI
addrType = isar_models.AddressType.p2pkh; addrType = isar_models.AddressType.p2pkh;
addressString = bitbox.Address.toCashAddress(addressString); addressString = bitbox.Address.toCashAddress(addressString);
break; break;
case DerivePathType.bip49:
addressString = P2SH(
data: PaymentData(
redeem: P2WPKH(data: data, network: _network).data),
network: _network)
.data
.address!;
addrType = isar_models.AddressType.p2sh;
break;
default: default:
throw Exception("DerivePathType $type not supported"); throw Exception("DerivePathType $type not supported");
} }
@ -518,7 +501,6 @@ class BitcoinCashWallet extends CoinServiceAPI
final deriveTypes = [ final deriveTypes = [
DerivePathType.bip44, DerivePathType.bip44,
DerivePathType.bip49,
]; ];
if (coin != Coin.bitcoincashTestnet) { if (coin != Coin.bitcoincashTestnet) {
@ -1397,10 +1379,6 @@ class BitcoinCashWallet extends CoinServiceAPI
// P2PKH // P2PKH
_generateAddressForChain(0, 0, DerivePathType.bip44), _generateAddressForChain(0, 0, DerivePathType.bip44),
_generateAddressForChain(1, 0, DerivePathType.bip44), _generateAddressForChain(1, 0, DerivePathType.bip44),
// P2SH
_generateAddressForChain(0, 0, DerivePathType.bip49),
_generateAddressForChain(1, 0, DerivePathType.bip49),
]); ]);
await db.putAddresses(initialAddresses); await db.putAddresses(initialAddresses);
@ -1408,7 +1386,7 @@ class BitcoinCashWallet extends CoinServiceAPI
Logging.instance.log("_generateNewWalletFinished", level: LogLevel.Info); Logging.instance.log("_generateNewWalletFinished", level: LogLevel.Info);
} }
/// Generates a new internal or external chain address for the wallet using a BIP44 or BIP49 derivation path. /// Generates a new internal or external chain address for the wallet using a BIP44 derivation path.
/// [chain] - Use 0 for receiving (external), 1 for change (internal). Should not be any other value! /// [chain] - Use 0 for receiving (external), 1 for change (internal). Should not be any other value!
/// [index] - This can be any integer >= 0 /// [index] - This can be any integer >= 0
Future<isar_models.Address> _generateAddressForChain( Future<isar_models.Address> _generateAddressForChain(
@ -1449,17 +1427,6 @@ class BitcoinCashWallet extends CoinServiceAPI
addrType = isar_models.AddressType.p2pkh; addrType = isar_models.AddressType.p2pkh;
address = bitbox.Address.toCashAddress(address); address = bitbox.Address.toCashAddress(address);
break; break;
case DerivePathType.bip49:
address = P2SH(
data: PaymentData(
redeem: P2WPKH(data: data, network: _network).data),
network: _network)
.data
.address!;
addrType = isar_models.AddressType.p2sh;
break;
case DerivePathType.bip84:
throw UnsupportedError("bip84 not supported by BCH");
default: default:
throw Exception("DerivePathType $derivePathType not supported"); throw Exception("DerivePathType $derivePathType not supported");
} }
@ -1502,13 +1469,6 @@ class BitcoinCashWallet extends CoinServiceAPI
coinType = coin == Coin.bitcoincash ? "0" : "1"; coinType = coin == Coin.bitcoincash ? "0" : "1";
purpose = "44"; purpose = "44";
break; break;
case DerivePathType.bip49:
type = isar_models.AddressType.p2sh;
coinType = coin == Coin.bitcoincash ? "145" : "1";
purpose = "49";
break;
case DerivePathType.bip84:
throw UnsupportedError("bip84 not supported by BCH");
default: default:
throw Exception("DerivePathType $derivePathType not supported"); throw Exception("DerivePathType $derivePathType not supported");
} }
@ -1537,9 +1497,6 @@ class BitcoinCashWallet extends CoinServiceAPI
case DerivePathType.bch44: case DerivePathType.bch44:
key = "${walletId}_${chainId}DerivationsBch44P2PKH"; key = "${walletId}_${chainId}DerivationsBch44P2PKH";
break; break;
case DerivePathType.bip49:
key = "${walletId}_${chainId}DerivationsP2SH";
break;
default: default:
throw UnsupportedError( throw UnsupportedError(
"${derivePathType.name} not supported by ${coin.prettyName}"); "${derivePathType.name} not supported by ${coin.prettyName}");
@ -2721,20 +2678,6 @@ class BitcoinCashWallet extends CoinServiceAPI
redeemScript = null; redeemScript = null;
break; break;
case DerivePathType.bip49:
final p2wpkh = P2WPKH(
data: PaymentData(
pubkey: Format.stringToUint8List(pubKey),
),
network: _network,
).data;
redeemScript = p2wpkh.output;
data = P2SH(
data: PaymentData(redeem: p2wpkh),
network: _network,
).data;
break;
default: default:
throw Exception("DerivePathType unsupported"); throw Exception("DerivePathType unsupported");
} }

View file

@ -12,8 +12,8 @@ import 'package:stackwallet/services/event_bus/events/global/updated_in_backgrou
import 'package:stackwallet/services/event_bus/global_event_bus.dart'; import 'package:stackwallet/services/event_bus/global_event_bus.dart';
import 'package:stackwallet/services/mixins/coin_control_interface.dart'; import 'package:stackwallet/services/mixins/coin_control_interface.dart';
import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart'; import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/services/mixins/xpubable.dart'; import 'package:stackwallet/services/mixins/xpubable.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
@ -252,7 +252,8 @@ class Manager with ChangeNotifier {
); );
} }
bool get hasXPub => _currentWallet is XPubAble; // TODO: re enable once xpubs have been redone
bool get hasXPub => false; //_currentWallet is XPubAble;
Future<String> get xpub async { Future<String> get xpub async {
if (!hasXPub) { if (!hasXPub) {

View file

@ -103,6 +103,7 @@ class StackColors extends ThemeExtension<StackColors> {
// icons // icons
final Color bottomNavIconBack; final Color bottomNavIconBack;
final Color bottomNavIconIcon; final Color bottomNavIconIcon;
final Color bottomNavIconIconHighlighted;
final Color topNavIconPrimary; final Color topNavIconPrimary;
final Color topNavIconGreen; final Color topNavIconGreen;
final Color topNavIconYellow; final Color topNavIconYellow;
@ -281,6 +282,7 @@ class StackColors extends ThemeExtension<StackColors> {
required this.snackBarTextInfo, required this.snackBarTextInfo,
required this.bottomNavIconBack, required this.bottomNavIconBack,
required this.bottomNavIconIcon, required this.bottomNavIconIcon,
required this.bottomNavIconIconHighlighted,
required this.topNavIconPrimary, required this.topNavIconPrimary,
required this.topNavIconGreen, required this.topNavIconGreen,
required this.topNavIconYellow, required this.topNavIconYellow,
@ -441,6 +443,7 @@ class StackColors extends ThemeExtension<StackColors> {
snackBarTextInfo: colorTheme.snackBarTextInfo, snackBarTextInfo: colorTheme.snackBarTextInfo,
bottomNavIconBack: colorTheme.bottomNavIconBack, bottomNavIconBack: colorTheme.bottomNavIconBack,
bottomNavIconIcon: colorTheme.bottomNavIconIcon, bottomNavIconIcon: colorTheme.bottomNavIconIcon,
bottomNavIconIconHighlighted: colorTheme.bottomNavIconIconHighlighted,
topNavIconPrimary: colorTheme.topNavIconPrimary, topNavIconPrimary: colorTheme.topNavIconPrimary,
topNavIconGreen: colorTheme.topNavIconGreen, topNavIconGreen: colorTheme.topNavIconGreen,
topNavIconYellow: colorTheme.topNavIconYellow, topNavIconYellow: colorTheme.topNavIconYellow,
@ -603,6 +606,7 @@ class StackColors extends ThemeExtension<StackColors> {
Color? snackBarTextInfo, Color? snackBarTextInfo,
Color? bottomNavIconBack, Color? bottomNavIconBack,
Color? bottomNavIconIcon, Color? bottomNavIconIcon,
Color? bottomNavIconIconHighlighted,
Color? topNavIconPrimary, Color? topNavIconPrimary,
Color? topNavIconGreen, Color? topNavIconGreen,
Color? topNavIconYellow, Color? topNavIconYellow,
@ -776,6 +780,8 @@ class StackColors extends ThemeExtension<StackColors> {
snackBarTextInfo: snackBarTextInfo ?? this.snackBarTextInfo, snackBarTextInfo: snackBarTextInfo ?? this.snackBarTextInfo,
bottomNavIconBack: bottomNavIconBack ?? this.bottomNavIconBack, bottomNavIconBack: bottomNavIconBack ?? this.bottomNavIconBack,
bottomNavIconIcon: bottomNavIconIcon ?? this.bottomNavIconIcon, bottomNavIconIcon: bottomNavIconIcon ?? this.bottomNavIconIcon,
bottomNavIconIconHighlighted:
bottomNavIconIconHighlighted ?? this.bottomNavIconIconHighlighted,
topNavIconPrimary: topNavIconPrimary ?? this.topNavIconPrimary, topNavIconPrimary: topNavIconPrimary ?? this.topNavIconPrimary,
topNavIconGreen: topNavIconGreen ?? this.topNavIconGreen, topNavIconGreen: topNavIconGreen ?? this.topNavIconGreen,
topNavIconYellow: topNavIconYellow ?? this.topNavIconYellow, topNavIconYellow: topNavIconYellow ?? this.topNavIconYellow,
@ -1279,6 +1285,11 @@ class StackColors extends ThemeExtension<StackColors> {
other.bottomNavIconIcon, other.bottomNavIconIcon,
t, t,
)!, )!,
bottomNavIconIconHighlighted: Color.lerp(
bottomNavIconIconHighlighted,
other.bottomNavIconIconHighlighted,
t,
)!,
topNavIconPrimary: Color.lerp( topNavIconPrimary: Color.lerp(
topNavIconPrimary, topNavIconPrimary,
other.topNavIconPrimary, other.topNavIconPrimary,

View file

@ -42,7 +42,7 @@ abstract class Constants {
// Enable Logger.print statements // Enable Logger.print statements
static const bool disableLogger = false; static const bool disableLogger = false;
static const int currentHiveDbVersion = 8; static const int currentDataVersion = 10;
static const int rescanV1 = 1; static const int rescanV1 = 1;

View file

@ -3,9 +3,12 @@ import 'package:isar/isar.dart';
import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/db/hive/db.dart';
import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/electrumx_rpc/electrumx.dart'; import 'package:stackwallet/electrumx_rpc/electrumx.dart';
import 'package:stackwallet/models/contact.dart';
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'; import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart'; import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
import 'package:stackwallet/models/isar/models/contact_entry.dart'
as isar_contact;
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models; import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
import 'package:stackwallet/models/models.dart'; import 'package:stackwallet/models/models.dart';
import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/models/node_model.dart';
@ -290,6 +293,48 @@ class DbVersionMigrator with WalletDB {
// try to continue migrating // try to continue migrating
return await migrate(8, secureStore: secureStore); return await migrate(8, secureStore: secureStore);
case 8:
// migrate
await Hive.openBox<dynamic>(DB.boxNameAllWalletsData);
final walletsService =
WalletsService(secureStorageInterface: secureStore);
final walletInfoList = await walletsService.walletNames;
await MainDB.instance.initMainDB();
for (final walletId in walletInfoList.keys) {
final info = walletInfoList[walletId]!;
if (info.coin == Coin.bitcoincash ||
info.coin == Coin.bitcoincashTestnet) {
final ids = await MainDB.instance
.getAddresses(walletId)
.filter()
.typeEqualTo(isar_models.AddressType.p2sh)
.idProperty()
.findAll();
await MainDB.instance.isar.writeTxn(() async {
await MainDB.instance.isar.addresses.deleteAll(ids);
});
}
}
// update version
await DB.instance.put<dynamic>(
boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 9);
// try to continue migrating
return await migrate(9, secureStore: secureStore);
case 9:
// migrate
await _v9();
// update version
await DB.instance.put<dynamic>(
boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 10);
// try to continue migrating
return await migrate(10, secureStore: secureStore);
default: default:
// finally return // finally return
return; return;
@ -447,4 +492,50 @@ class DbVersionMigrator with WalletDB {
} }
} }
} }
Future<void> _v9() async {
final addressBookBox = await Hive.openBox<dynamic>(DB.boxNameAddressBook);
await MainDB.instance.initMainDB();
final keys = List<String>.from(addressBookBox.keys);
final contacts = keys
.map((id) => Contact.fromJson(
Map<String, dynamic>.from(
addressBookBox.get(id) as Map,
),
))
.toList(growable: false);
final List<isar_contact.ContactEntry> newContacts = [];
for (final contact in contacts) {
final List<isar_contact.ContactAddressEntry> newContactAddressEntries =
[];
for (final entry in contact.addresses) {
newContactAddressEntries.add(
isar_contact.ContactAddressEntry()
..coinName = entry.coin.name
..address = entry.address
..label = entry.label
..other = entry.other,
);
}
final newContact = isar_contact.ContactEntry(
name: contact.name,
addresses: newContactAddressEntries,
isFavorite: contact.isFavorite,
customId: contact.id,
);
newContacts.add(newContact);
}
await MainDB.instance.isar.writeTxn(() async {
await MainDB.instance.isar.contactEntrys.putAll(newContacts);
});
await addressBookBox.deleteFromDisk();
}
} }

View file

@ -1,10 +1,13 @@
import 'dart:io';
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:flutter_svg/svg.dart';
import 'package:stackwallet/models/contact.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/pages/address_book_views/subviews/contact_popup.dart'; import 'package:stackwallet/pages/address_book_views/subviews/contact_popup.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/theme_providers.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -14,8 +17,6 @@ import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/expandable.dart'; import 'package:stackwallet/widgets/expandable.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
import '../themes/theme_providers.dart';
class AddressBookCard extends ConsumerStatefulWidget { class AddressBookCard extends ConsumerStatefulWidget {
const AddressBookCard({ const AddressBookCard({
Key? key, Key? key,
@ -48,7 +49,7 @@ class _AddressBookCardState extends ConsumerState<AddressBookCard> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// provider hack to prevent trying to update widget with deleted contact // provider hack to prevent trying to update widget with deleted contact
Contact? _contact; ContactEntry? _contact;
try { try {
_contact = ref.watch(addressBookServiceProvider _contact = ref.watch(addressBookServiceProvider
.select((value) => value.getContactById(contactId))); .select((value) => value.getContactById(contactId)));
@ -81,7 +82,7 @@ class _AddressBookCardState extends ConsumerState<AddressBookCard> {
width: 32, width: 32,
height: 32, height: 32,
decoration: BoxDecoration( decoration: BoxDecoration(
color: contact.id == "default" color: contact.customId == "default"
? Theme.of(context) ? Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.myStackContactIconBG .myStackContactIconBG
@ -90,12 +91,14 @@ class _AddressBookCardState extends ConsumerState<AddressBookCard> {
.textFieldDefaultBG, .textFieldDefaultBG,
borderRadius: BorderRadius.circular(32), borderRadius: BorderRadius.circular(32),
), ),
child: contact.id == "default" child: contact.customId == "default"
? Center( ? Center(
child: SvgPicture.asset( child: SvgPicture.file(
ref.watch( File(
themeProvider.select( ref.watch(
(value) => value.assets.stackIcon, themeProvider.select(
(value) => value.assets.stackIcon,
),
), ),
), ),
width: 20, width: 20,
@ -176,7 +179,7 @@ class _AddressBookCardState extends ConsumerState<AddressBookCard> {
useSafeArea: true, useSafeArea: true,
barrierDismissible: true, barrierDismissible: true,
builder: (_) => ContactPopUp( builder: (_) => ContactPopUp(
contactId: contact.id, contactId: contact.customId,
), ),
); );
}, },

View file

@ -1,3 +1,5 @@
import 'dart:io';
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/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
@ -47,10 +49,12 @@ class _LivingStackIconState extends ConsumerState<LivingStackIcon> {
child: AnimatedScale( child: AnimatedScale(
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
scale: _hovering ? 1.2 : 1, scale: _hovering ? 1.2 : 1,
child: SvgPicture.asset( child: SvgPicture.file(
ref.watch( File(
themeProvider.select( ref.watch(
(value) => value.assets.stackIcon, themeProvider.select(
(value) => value.assets.stackIcon,
),
), ),
), ),
), ),

View file

@ -46,6 +46,12 @@ class RoundedContainer extends StatelessWidget {
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius * radiusMultiplier, Constants.size.circularBorderRadius * radiusMultiplier,
), ),
side: borderColor == null
? BorderSide.none
: BorderSide(
color: borderColor!,
width: 1.2,
),
), ),
onPressed: onPressed, onPressed: onPressed,
child: child, child: child,

View file

@ -14,7 +14,7 @@ class ExchangeNavIcon extends ConsumerWidget {
File( File(
ref.watch( ref.watch(
themeProvider.select( themeProvider.select(
(value) => value.assets.buy, (value) => value.assets.exchange,
), ),
), ),
), ),

View file

@ -68,9 +68,10 @@ class WalletNavigationBarItem extends ConsumerWidget {
Text( Text(
data.label ?? "", data.label ?? "",
style: STextStyles.buttonSmall(context).copyWith( style: STextStyles.buttonSmall(context).copyWith(
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.bottomNavText), .bottomNavText,
),
), ),
], ],
), ),
@ -112,7 +113,11 @@ class WalletNavigationBarMoreItem extends ConsumerWidget {
child: Text( child: Text(
data.label ?? "", data.label ?? "",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: STextStyles.buttonSmall(context), style: STextStyles.buttonSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.bottomNavText,
),
), ),
), ),
const SizedBox( const SizedBox(

View file

@ -175,7 +175,7 @@ class _WalletNavigationBarState extends ConsumerState<WalletNavigationBar> {
height: 20, height: 20,
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.infoItemIcons, .bottomNavIconIconHighlighted,
), ),
crossFadeState: ref crossFadeState: ref
.watch(walletNavBarMore.state) .watch(walletNavBarMore.state)
@ -190,10 +190,10 @@ class _WalletNavigationBarState extends ConsumerState<WalletNavigationBar> {
style: style:
STextStyles.buttonSmall(context) STextStyles.buttonSmall(context)
.copyWith( .copyWith(
color: Theme.of(context) color: Theme.of(context)
.extension< .extension<StackColors>()!
StackColors>()! .bottomNavText,
.bottomNavText), ),
), ),
secondChild: Text( secondChild: Text(
"More", "More",
@ -202,7 +202,7 @@ class _WalletNavigationBarState extends ConsumerState<WalletNavigationBar> {
.copyWith( .copyWith(
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.infoItemIcons, .bottomNavIconIconHighlighted,
), ),
), ),
crossFadeState: ref crossFadeState: ref

View file

@ -11,7 +11,7 @@ description: Stack Wallet
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.7.8+170 version: 1.7.8+171
environment: environment:
sdk: ">=2.17.0 <3.0.0" sdk: ">=2.17.0 <3.0.0"
@ -343,14 +343,9 @@ flutter:
# exchange icons # exchange icons
- assets/svg/exchange_icons/ - assets/svg/exchange_icons/
# theme selectors
# - assets/svg/dark-theme.svg
# - assets/svg/light-mode.svg
# buy # buy
- assets/svg/buy/ - assets/svg/buy/
# lottie animations # lottie animations
# basic # basic
- assets/lottie/test2.json - assets/lottie/test2.json

View file

@ -1,174 +0,0 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:hive/hive.dart';
import 'package:hive_test/hive_test.dart';
import 'package:stackwallet/db/hive/db.dart';
import 'package:stackwallet/models/contact.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/services/address_book_service.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
void main() {
group("Empty DB tests", () {
setUp(() async {
await setUpTestHive();
await Hive.openBox<dynamic>(DB.boxNameAddressBook);
});
test("get empty contacts", () {
final service = AddressBookService();
expect(service.contacts, <Contact>[]);
});
test("get empty addressBookEntries", () async {
final service = AddressBookService();
expect(await service.addressBookEntries, <Contact>[]);
});
test("getContactById from empty db", () {
final service = AddressBookService();
expect(() => service.getContactById("some id"), throwsException);
});
tearDown(() async {
await tearDownTestHive();
});
});
group("Preloaded DB tests", () {
final contactA = Contact(name: "john", addresses: [], isFavorite: true);
final contactB = Contact(
name: "JANE",
addresses: [
const ContactAddressEntry(
coin: Coin.bitcoin,
address: "some btc address",
label: "rent",
),
],
isFavorite: false);
final contactC = Contact(
name: "Bill",
addresses: [
const ContactAddressEntry(
coin: Coin.monero,
address: "some xmr address",
label: "market",
),
const ContactAddressEntry(
coin: Coin.epicCash,
address: "some epic address",
label: "gas",
),
],
isFavorite: true);
setUp(() async {
await setUpTestHive();
await Hive.openBox<dynamic>(DB.boxNameAddressBook);
await DB.instance.put<dynamic>(
boxName: DB.boxNameAddressBook,
key: contactA.id,
value: contactA.toMap());
await DB.instance.put<dynamic>(
boxName: DB.boxNameAddressBook,
key: contactB.id,
value: contactB.toMap());
await DB.instance.put<dynamic>(
boxName: DB.boxNameAddressBook,
key: contactC.id,
value: contactC.toMap());
});
test("getContactById with non existing ID", () {
final service = AddressBookService();
expect(() => service.getContactById("some id"), throwsException);
});
test("getContactById with existing ID", () {
final service = AddressBookService();
expect(
service.getContactById(contactA.id).toString(), contactA.toString());
});
test("get contacts", () {
final service = AddressBookService();
expect(service.contacts.toString(),
[contactC, contactB, contactA].toString());
});
test("get addressBookEntries", () async {
final service = AddressBookService();
expect((await service.addressBookEntries).toString(),
[contactC, contactB, contactA].toString());
});
test("search contacts", () async {
final service = AddressBookService();
final results = await service.search("j");
expect(results.toString(), [contactB, contactA].toString());
final results2 = await service.search("ja");
expect(results2.toString(), [contactB].toString());
final results3 = await service.search("john");
expect(results3.toString(), [contactA].toString());
final results4 = await service.search("po");
expect(results4.toString(), <Contact>[].toString());
final results5 = await service.search("");
expect(results5.toString(), [contactC, contactB, contactA].toString());
final results6 = await service.search("epic address");
expect(results6.toString(), [contactC].toString());
});
test("add new contact", () async {
final service = AddressBookService();
final contactD = Contact(name: "tim", addresses: [], isFavorite: true);
final result = await service.addContact(contactD);
expect(result, true);
expect(service.contacts.length, 4);
expect(
service.getContactById(contactD.id).toString(), contactD.toString());
});
test("add duplicate contact", () async {
final service = AddressBookService();
final result = await service.addContact(contactA);
expect(result, false);
expect(service.contacts.length, 3);
expect(service.contacts.toString(),
[contactC, contactB, contactA].toString());
});
test("edit contact", () async {
final service = AddressBookService();
final editedContact = contactB.copyWith(name: "Mike");
expect(await service.editContact(editedContact), true);
expect(service.contacts.length, 3);
expect(service.contacts.toString(),
[contactC, contactA, editedContact].toString());
});
test("remove existing contact", () async {
final service = AddressBookService();
await service.removeContact(contactB.id);
expect(service.contacts.length, 2);
expect(service.contacts.toString(), [contactC, contactA].toString());
});
test("remove non existing contact", () async {
final service = AddressBookService();
await service.removeContact("some id");
expect(service.contacts.length, 3);
expect(service.contacts.toString(),
[contactC, contactB, contactA].toString());
});
tearDown(() async {
await tearDownTestHive();
});
});
}

View file

@ -1,17 +1,35 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:stackwallet/models/isar/stack_theme.dart'; import 'package:stackwallet/models/isar/stack_theme.dart';
import 'package:stackwallet/models/notification_model.dart'; import 'package:stackwallet/models/notification_model.dart';
import 'package:stackwallet/notifications/notification_card.dart'; import 'package:stackwallet/notifications/notification_card.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/theme_service.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import '../sample_data/theme_json.dart'; import '../sample_data/theme_json.dart';
import 'notification_card_test.mocks.dart';
@GenerateMocks([
ThemeService,
])
void main() { void main() {
testWidgets("test notification card", (widgetTester) async { testWidgets("test notification card", (widgetTester) async {
final key = UniqueKey(); final key = UniqueKey();
final mockThemeService = MockThemeService();
final theme = StackTheme.fromJson(
json: lightThemeJsonMap,
applicationThemesDirectoryPath: "test",
);
when(mockThemeService.getTheme(themeId: "light")).thenAnswer(
(_) => theme,
);
final notificationCard = NotificationCard( final notificationCard = NotificationCard(
key: key, key: key,
notification: NotificationModel( notification: NotificationModel(
@ -27,19 +45,21 @@ void main() {
); );
await widgetTester.pumpWidget( await widgetTester.pumpWidget(
MaterialApp( ProviderScope(
theme: ThemeData( overrides: [
extensions: [ pThemeService.overrideWithValue(mockThemeService),
StackColors.fromStackColorTheme( ],
StackTheme.fromJson( child: MaterialApp(
json: lightThemeJsonMap, theme: ThemeData(
applicationThemesDirectoryPath: "test", extensions: [
StackColors.fromStackColorTheme(
theme,
), ),
), ],
], ),
), home: Material(
home: Material( child: notificationCard,
child: notificationCard, ),
), ),
), ),
); );

View file

@ -0,0 +1,122 @@
// Mocks generated by Mockito 5.3.2 from annotations
// in stackwallet/test/notifications/notification_card_test.dart.
// Do not manually edit this file.
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i5;
import 'dart:typed_data' as _i6;
import 'package:mockito/mockito.dart' as _i1;
import 'package:stackwallet/db/isar/main_db.dart' as _i2;
import 'package:stackwallet/models/isar/stack_theme.dart' as _i4;
import 'package:stackwallet/themes/theme_service.dart' as _i3;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
class _FakeMainDB_0 extends _i1.SmartFake implements _i2.MainDB {
_FakeMainDB_0(
Object parent,
Invocation parentInvocation,
) : super(
parent,
parentInvocation,
);
}
/// A class which mocks [ThemeService].
///
/// See the documentation for Mockito's code generation for more information.
class MockThemeService extends _i1.Mock implements _i3.ThemeService {
MockThemeService() {
_i1.throwOnMissingStub(this);
}
@override
_i2.MainDB get db => (super.noSuchMethod(
Invocation.getter(#db),
returnValue: _FakeMainDB_0(
this,
Invocation.getter(#db),
),
) as _i2.MainDB);
@override
List<_i4.StackTheme> get installedThemes => (super.noSuchMethod(
Invocation.getter(#installedThemes),
returnValue: <_i4.StackTheme>[],
) as List<_i4.StackTheme>);
@override
void init(_i2.MainDB? db) => super.noSuchMethod(
Invocation.method(
#init,
[db],
),
returnValueForMissingStub: null,
);
@override
_i5.Future<void> install({required _i6.Uint8List? themeArchiveData}) =>
(super.noSuchMethod(
Invocation.method(
#install,
[],
{#themeArchiveData: themeArchiveData},
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> remove({required String? themeId}) => (super.noSuchMethod(
Invocation.method(
#remove,
[],
{#themeId: themeId},
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<bool> verifyInstalled({required String? themeId}) =>
(super.noSuchMethod(
Invocation.method(
#verifyInstalled,
[],
{#themeId: themeId},
),
returnValue: _i5.Future<bool>.value(false),
) as _i5.Future<bool>);
@override
_i5.Future<List<_i3.StackThemeMetaData>> fetchThemes() => (super.noSuchMethod(
Invocation.method(
#fetchThemes,
[],
),
returnValue: _i5.Future<List<_i3.StackThemeMetaData>>.value(
<_i3.StackThemeMetaData>[]),
) as _i5.Future<List<_i3.StackThemeMetaData>>);
@override
_i5.Future<_i6.Uint8List> fetchTheme(
{required _i3.StackThemeMetaData? themeMetaData}) =>
(super.noSuchMethod(
Invocation.method(
#fetchTheme,
[],
{#themeMetaData: themeMetaData},
),
returnValue: _i5.Future<_i6.Uint8List>.value(_i6.Uint8List(0)),
) as _i5.Future<_i6.Uint8List>);
@override
_i4.StackTheme? getTheme({required String? themeId}) =>
(super.noSuchMethod(Invocation.method(
#getTheme,
[],
{#themeId: themeId},
)) as _i4.StackTheme?);
}

View file

@ -91,6 +91,7 @@ const Map<String, dynamic> lightThemeJsonMap = {
"snack_bar_text_info": "0xFF002A78", "snack_bar_text_info": "0xFF002A78",
"bottom_nav_icon_back": "0xFFA2A2A2", "bottom_nav_icon_back": "0xFFA2A2A2",
"bottom_nav_icon_icon": "0xFF232323", "bottom_nav_icon_icon": "0xFF232323",
"bottom_nav_icon_icon_highlighted": "0xFF232323",
"top_nav_icon_primary": "0xFF232323", "top_nav_icon_primary": "0xFF232323",
"top_nav_icon_green": "0xFF00A578", "top_nav_icon_green": "0xFF00A578",
"top_nav_icon_yellow": "0xFFF4C517", "top_nav_icon_yellow": "0xFFF4C517",

View file

@ -7,7 +7,7 @@ import 'dart:async' as _i4;
import 'dart:ui' as _i5; import 'dart:ui' as _i5;
import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/mockito.dart' as _i1;
import 'package:stackwallet/models/contact.dart' as _i2; import 'package:stackwallet/models/isar/models/contact_entry.dart' as _i2;
import 'package:stackwallet/services/address_book_service.dart' as _i3; import 'package:stackwallet/services/address_book_service.dart' as _i3;
// ignore_for_file: type=lint // ignore_for_file: type=lint
@ -21,8 +21,8 @@ import 'package:stackwallet/services/address_book_service.dart' as _i3;
// ignore_for_file: camel_case_types // ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class // ignore_for_file: subtype_of_sealed_class
class _FakeContact_0 extends _i1.SmartFake implements _i2.Contact { class _FakeContactEntry_0 extends _i1.SmartFake implements _i2.ContactEntry {
_FakeContact_0( _FakeContactEntry_0(
Object parent, Object parent,
Invocation parentInvocation, Invocation parentInvocation,
) : super( ) : super(
@ -37,46 +37,43 @@ class _FakeContact_0 extends _i1.SmartFake implements _i2.Contact {
class MockAddressBookService extends _i1.Mock class MockAddressBookService extends _i1.Mock
implements _i3.AddressBookService { implements _i3.AddressBookService {
@override @override
List<_i2.Contact> get contacts => (super.noSuchMethod( List<_i2.ContactEntry> get contacts => (super.noSuchMethod(
Invocation.getter(#contacts), Invocation.getter(#contacts),
returnValue: <_i2.Contact>[], returnValue: <_i2.ContactEntry>[],
) as List<_i2.Contact>); ) as List<_i2.ContactEntry>);
@override
_i4.Future<List<_i2.Contact>> get addressBookEntries => (super.noSuchMethod(
Invocation.getter(#addressBookEntries),
returnValue: _i4.Future<List<_i2.Contact>>.value(<_i2.Contact>[]),
) as _i4.Future<List<_i2.Contact>>);
@override @override
bool get hasListeners => (super.noSuchMethod( bool get hasListeners => (super.noSuchMethod(
Invocation.getter(#hasListeners), Invocation.getter(#hasListeners),
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i2.Contact getContactById(String? id) => (super.noSuchMethod( _i2.ContactEntry getContactById(String? id) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
returnValue: _FakeContact_0( returnValue: _FakeContactEntry_0(
this, this,
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
), ),
) as _i2.Contact); ) as _i2.ContactEntry);
@override @override
_i4.Future<List<_i2.Contact>> search(String? text) => (super.noSuchMethod( _i4.Future<List<_i2.ContactEntry>> search(String? text) =>
(super.noSuchMethod(
Invocation.method( Invocation.method(
#search, #search,
[text], [text],
), ),
returnValue: _i4.Future<List<_i2.Contact>>.value(<_i2.Contact>[]), returnValue:
) as _i4.Future<List<_i2.Contact>>); _i4.Future<List<_i2.ContactEntry>>.value(<_i2.ContactEntry>[]),
) as _i4.Future<List<_i2.ContactEntry>>);
@override @override
bool matches( bool matches(
String? term, String? term,
_i2.Contact? contact, _i2.ContactEntry? contact,
) => ) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
@ -89,7 +86,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i4.Future<bool> addContact(_i2.Contact? contact) => (super.noSuchMethod( _i4.Future<bool> addContact(_i2.ContactEntry? contact) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#addContact, #addContact,
[contact], [contact],
@ -97,7 +94,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: _i4.Future<bool>.value(false), returnValue: _i4.Future<bool>.value(false),
) as _i4.Future<bool>); ) as _i4.Future<bool>);
@override @override
_i4.Future<bool> editContact(_i2.Contact? editedContact) => _i4.Future<bool> editContact(_i2.ContactEntry? editedContact) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#editContact, #editContact,

View file

@ -9,7 +9,7 @@ import 'dart:ui' as _i11;
import 'package:barcode_scan2/barcode_scan2.dart' as _i2; import 'package:barcode_scan2/barcode_scan2.dart' as _i2;
import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/mockito.dart' as _i1;
import 'package:stackwallet/models/balance.dart' as _i6; import 'package:stackwallet/models/balance.dart' as _i6;
import 'package:stackwallet/models/contact.dart' as _i3; import 'package:stackwallet/models/isar/models/contact_entry.dart' as _i3;
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i14; import 'package:stackwallet/models/isar/models/isar_models.dart' as _i14;
import 'package:stackwallet/models/models.dart' as _i5; import 'package:stackwallet/models/models.dart' as _i5;
import 'package:stackwallet/services/address_book_service.dart' as _i10; import 'package:stackwallet/services/address_book_service.dart' as _i10;
@ -40,8 +40,8 @@ class _FakeScanResult_0 extends _i1.SmartFake implements _i2.ScanResult {
); );
} }
class _FakeContact_1 extends _i1.SmartFake implements _i3.Contact { class _FakeContactEntry_1 extends _i1.SmartFake implements _i3.ContactEntry {
_FakeContact_1( _FakeContactEntry_1(
Object parent, Object parent,
Invocation parentInvocation, Invocation parentInvocation,
) : super( ) : super(
@ -126,46 +126,43 @@ class MockBarcodeScannerWrapper extends _i1.Mock
class MockAddressBookService extends _i1.Mock class MockAddressBookService extends _i1.Mock
implements _i10.AddressBookService { implements _i10.AddressBookService {
@override @override
List<_i3.Contact> get contacts => (super.noSuchMethod( List<_i3.ContactEntry> get contacts => (super.noSuchMethod(
Invocation.getter(#contacts), Invocation.getter(#contacts),
returnValue: <_i3.Contact>[], returnValue: <_i3.ContactEntry>[],
) as List<_i3.Contact>); ) as List<_i3.ContactEntry>);
@override
_i9.Future<List<_i3.Contact>> get addressBookEntries => (super.noSuchMethod(
Invocation.getter(#addressBookEntries),
returnValue: _i9.Future<List<_i3.Contact>>.value(<_i3.Contact>[]),
) as _i9.Future<List<_i3.Contact>>);
@override @override
bool get hasListeners => (super.noSuchMethod( bool get hasListeners => (super.noSuchMethod(
Invocation.getter(#hasListeners), Invocation.getter(#hasListeners),
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i3.Contact getContactById(String? id) => (super.noSuchMethod( _i3.ContactEntry getContactById(String? id) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
returnValue: _FakeContact_1( returnValue: _FakeContactEntry_1(
this, this,
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
), ),
) as _i3.Contact); ) as _i3.ContactEntry);
@override @override
_i9.Future<List<_i3.Contact>> search(String? text) => (super.noSuchMethod( _i9.Future<List<_i3.ContactEntry>> search(String? text) =>
(super.noSuchMethod(
Invocation.method( Invocation.method(
#search, #search,
[text], [text],
), ),
returnValue: _i9.Future<List<_i3.Contact>>.value(<_i3.Contact>[]), returnValue:
) as _i9.Future<List<_i3.Contact>>); _i9.Future<List<_i3.ContactEntry>>.value(<_i3.ContactEntry>[]),
) as _i9.Future<List<_i3.ContactEntry>>);
@override @override
bool matches( bool matches(
String? term, String? term,
_i3.Contact? contact, _i3.ContactEntry? contact,
) => ) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
@ -178,7 +175,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i9.Future<bool> addContact(_i3.Contact? contact) => (super.noSuchMethod( _i9.Future<bool> addContact(_i3.ContactEntry? contact) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#addContact, #addContact,
[contact], [contact],
@ -186,7 +183,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: _i9.Future<bool>.value(false), returnValue: _i9.Future<bool>.value(false),
) as _i9.Future<bool>); ) as _i9.Future<bool>);
@override @override
_i9.Future<bool> editContact(_i3.Contact? editedContact) => _i9.Future<bool> editContact(_i3.ContactEntry? editedContact) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#editContact, #editContact,

View file

@ -8,7 +8,7 @@ import 'dart:ui' as _i9;
import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/mockito.dart' as _i1;
import 'package:stackwallet/models/balance.dart' as _i5; import 'package:stackwallet/models/balance.dart' as _i5;
import 'package:stackwallet/models/contact.dart' as _i2; import 'package:stackwallet/models/isar/models/contact_entry.dart' as _i2;
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i12; import 'package:stackwallet/models/isar/models/isar_models.dart' as _i12;
import 'package:stackwallet/models/models.dart' as _i4; import 'package:stackwallet/models/models.dart' as _i4;
import 'package:stackwallet/services/address_book_service.dart' as _i7; import 'package:stackwallet/services/address_book_service.dart' as _i7;
@ -30,8 +30,8 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i11;
// ignore_for_file: camel_case_types // ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class // ignore_for_file: subtype_of_sealed_class
class _FakeContact_0 extends _i1.SmartFake implements _i2.Contact { class _FakeContactEntry_0 extends _i1.SmartFake implements _i2.ContactEntry {
_FakeContact_0( _FakeContactEntry_0(
Object parent, Object parent,
Invocation parentInvocation, Invocation parentInvocation,
) : super( ) : super(
@ -87,46 +87,43 @@ class _FakeAmount_4 extends _i1.SmartFake implements _i6.Amount {
class MockAddressBookService extends _i1.Mock class MockAddressBookService extends _i1.Mock
implements _i7.AddressBookService { implements _i7.AddressBookService {
@override @override
List<_i2.Contact> get contacts => (super.noSuchMethod( List<_i2.ContactEntry> get contacts => (super.noSuchMethod(
Invocation.getter(#contacts), Invocation.getter(#contacts),
returnValue: <_i2.Contact>[], returnValue: <_i2.ContactEntry>[],
) as List<_i2.Contact>); ) as List<_i2.ContactEntry>);
@override
_i8.Future<List<_i2.Contact>> get addressBookEntries => (super.noSuchMethod(
Invocation.getter(#addressBookEntries),
returnValue: _i8.Future<List<_i2.Contact>>.value(<_i2.Contact>[]),
) as _i8.Future<List<_i2.Contact>>);
@override @override
bool get hasListeners => (super.noSuchMethod( bool get hasListeners => (super.noSuchMethod(
Invocation.getter(#hasListeners), Invocation.getter(#hasListeners),
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i2.Contact getContactById(String? id) => (super.noSuchMethod( _i2.ContactEntry getContactById(String? id) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
returnValue: _FakeContact_0( returnValue: _FakeContactEntry_0(
this, this,
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
), ),
) as _i2.Contact); ) as _i2.ContactEntry);
@override @override
_i8.Future<List<_i2.Contact>> search(String? text) => (super.noSuchMethod( _i8.Future<List<_i2.ContactEntry>> search(String? text) =>
(super.noSuchMethod(
Invocation.method( Invocation.method(
#search, #search,
[text], [text],
), ),
returnValue: _i8.Future<List<_i2.Contact>>.value(<_i2.Contact>[]), returnValue:
) as _i8.Future<List<_i2.Contact>>); _i8.Future<List<_i2.ContactEntry>>.value(<_i2.ContactEntry>[]),
) as _i8.Future<List<_i2.ContactEntry>>);
@override @override
bool matches( bool matches(
String? term, String? term,
_i2.Contact? contact, _i2.ContactEntry? contact,
) => ) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
@ -139,7 +136,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i8.Future<bool> addContact(_i2.Contact? contact) => (super.noSuchMethod( _i8.Future<bool> addContact(_i2.ContactEntry? contact) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#addContact, #addContact,
[contact], [contact],
@ -147,7 +144,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: _i8.Future<bool>.value(false), returnValue: _i8.Future<bool>.value(false),
) as _i8.Future<bool>); ) as _i8.Future<bool>);
@override @override
_i8.Future<bool> editContact(_i2.Contact? editedContact) => _i8.Future<bool> editContact(_i2.ContactEntry? editedContact) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#editContact, #editContact,

View file

@ -8,7 +8,7 @@ import 'dart:ui' as _i9;
import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/mockito.dart' as _i1;
import 'package:stackwallet/models/balance.dart' as _i5; import 'package:stackwallet/models/balance.dart' as _i5;
import 'package:stackwallet/models/contact.dart' as _i2; import 'package:stackwallet/models/isar/models/contact_entry.dart' as _i2;
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i12; import 'package:stackwallet/models/isar/models/isar_models.dart' as _i12;
import 'package:stackwallet/models/models.dart' as _i4; import 'package:stackwallet/models/models.dart' as _i4;
import 'package:stackwallet/services/address_book_service.dart' as _i7; import 'package:stackwallet/services/address_book_service.dart' as _i7;
@ -28,8 +28,8 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i11;
// ignore_for_file: camel_case_types // ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class // ignore_for_file: subtype_of_sealed_class
class _FakeContact_0 extends _i1.SmartFake implements _i2.Contact { class _FakeContactEntry_0 extends _i1.SmartFake implements _i2.ContactEntry {
_FakeContact_0( _FakeContactEntry_0(
Object parent, Object parent,
Invocation parentInvocation, Invocation parentInvocation,
) : super( ) : super(
@ -85,46 +85,43 @@ class _FakeAmount_4 extends _i1.SmartFake implements _i6.Amount {
class MockAddressBookService extends _i1.Mock class MockAddressBookService extends _i1.Mock
implements _i7.AddressBookService { implements _i7.AddressBookService {
@override @override
List<_i2.Contact> get contacts => (super.noSuchMethod( List<_i2.ContactEntry> get contacts => (super.noSuchMethod(
Invocation.getter(#contacts), Invocation.getter(#contacts),
returnValue: <_i2.Contact>[], returnValue: <_i2.ContactEntry>[],
) as List<_i2.Contact>); ) as List<_i2.ContactEntry>);
@override
_i8.Future<List<_i2.Contact>> get addressBookEntries => (super.noSuchMethod(
Invocation.getter(#addressBookEntries),
returnValue: _i8.Future<List<_i2.Contact>>.value(<_i2.Contact>[]),
) as _i8.Future<List<_i2.Contact>>);
@override @override
bool get hasListeners => (super.noSuchMethod( bool get hasListeners => (super.noSuchMethod(
Invocation.getter(#hasListeners), Invocation.getter(#hasListeners),
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i2.Contact getContactById(String? id) => (super.noSuchMethod( _i2.ContactEntry getContactById(String? id) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
returnValue: _FakeContact_0( returnValue: _FakeContactEntry_0(
this, this,
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
), ),
) as _i2.Contact); ) as _i2.ContactEntry);
@override @override
_i8.Future<List<_i2.Contact>> search(String? text) => (super.noSuchMethod( _i8.Future<List<_i2.ContactEntry>> search(String? text) =>
(super.noSuchMethod(
Invocation.method( Invocation.method(
#search, #search,
[text], [text],
), ),
returnValue: _i8.Future<List<_i2.Contact>>.value(<_i2.Contact>[]), returnValue:
) as _i8.Future<List<_i2.Contact>>); _i8.Future<List<_i2.ContactEntry>>.value(<_i2.ContactEntry>[]),
) as _i8.Future<List<_i2.ContactEntry>>);
@override @override
bool matches( bool matches(
String? term, String? term,
_i2.Contact? contact, _i2.ContactEntry? contact,
) => ) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
@ -137,7 +134,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i8.Future<bool> addContact(_i2.Contact? contact) => (super.noSuchMethod( _i8.Future<bool> addContact(_i2.ContactEntry? contact) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#addContact, #addContact,
[contact], [contact],
@ -145,7 +142,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: _i8.Future<bool>.value(false), returnValue: _i8.Future<bool>.value(false),
) as _i8.Future<bool>); ) as _i8.Future<bool>);
@override @override
_i8.Future<bool> editContact(_i2.Contact? editedContact) => _i8.Future<bool> editContact(_i2.ContactEntry? editedContact) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#editContact, #editContact,

View file

@ -7,7 +7,7 @@ import 'dart:async' as _i4;
import 'dart:ui' as _i5; import 'dart:ui' as _i5;
import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/mockito.dart' as _i1;
import 'package:stackwallet/models/contact.dart' as _i2; import 'package:stackwallet/models/isar/models/contact_entry.dart' as _i2;
import 'package:stackwallet/services/address_book_service.dart' as _i6; import 'package:stackwallet/services/address_book_service.dart' as _i6;
import 'package:stackwallet/services/locale_service.dart' as _i7; import 'package:stackwallet/services/locale_service.dart' as _i7;
import 'package:stackwallet/services/notes_service.dart' as _i3; import 'package:stackwallet/services/notes_service.dart' as _i3;
@ -23,8 +23,8 @@ import 'package:stackwallet/services/notes_service.dart' as _i3;
// ignore_for_file: camel_case_types // ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class // ignore_for_file: subtype_of_sealed_class
class _FakeContact_0 extends _i1.SmartFake implements _i2.Contact { class _FakeContactEntry_0 extends _i1.SmartFake implements _i2.ContactEntry {
_FakeContact_0( _FakeContactEntry_0(
Object parent, Object parent,
Invocation parentInvocation, Invocation parentInvocation,
) : super( ) : super(
@ -141,46 +141,43 @@ class MockNotesService extends _i1.Mock implements _i3.NotesService {
class MockAddressBookService extends _i1.Mock class MockAddressBookService extends _i1.Mock
implements _i6.AddressBookService { implements _i6.AddressBookService {
@override @override
List<_i2.Contact> get contacts => (super.noSuchMethod( List<_i2.ContactEntry> get contacts => (super.noSuchMethod(
Invocation.getter(#contacts), Invocation.getter(#contacts),
returnValue: <_i2.Contact>[], returnValue: <_i2.ContactEntry>[],
) as List<_i2.Contact>); ) as List<_i2.ContactEntry>);
@override
_i4.Future<List<_i2.Contact>> get addressBookEntries => (super.noSuchMethod(
Invocation.getter(#addressBookEntries),
returnValue: _i4.Future<List<_i2.Contact>>.value(<_i2.Contact>[]),
) as _i4.Future<List<_i2.Contact>>);
@override @override
bool get hasListeners => (super.noSuchMethod( bool get hasListeners => (super.noSuchMethod(
Invocation.getter(#hasListeners), Invocation.getter(#hasListeners),
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i2.Contact getContactById(String? id) => (super.noSuchMethod( _i2.ContactEntry getContactById(String? id) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
returnValue: _FakeContact_0( returnValue: _FakeContactEntry_0(
this, this,
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
), ),
) as _i2.Contact); ) as _i2.ContactEntry);
@override @override
_i4.Future<List<_i2.Contact>> search(String? text) => (super.noSuchMethod( _i4.Future<List<_i2.ContactEntry>> search(String? text) =>
(super.noSuchMethod(
Invocation.method( Invocation.method(
#search, #search,
[text], [text],
), ),
returnValue: _i4.Future<List<_i2.Contact>>.value(<_i2.Contact>[]), returnValue:
) as _i4.Future<List<_i2.Contact>>); _i4.Future<List<_i2.ContactEntry>>.value(<_i2.ContactEntry>[]),
) as _i4.Future<List<_i2.ContactEntry>>);
@override @override
bool matches( bool matches(
String? term, String? term,
_i2.Contact? contact, _i2.ContactEntry? contact,
) => ) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
@ -193,7 +190,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i4.Future<bool> addContact(_i2.Contact? contact) => (super.noSuchMethod( _i4.Future<bool> addContact(_i2.ContactEntry? contact) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#addContact, #addContact,
[contact], [contact],
@ -201,7 +198,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: _i4.Future<bool>.value(false), returnValue: _i4.Future<bool>.value(false),
) as _i4.Future<bool>); ) as _i4.Future<bool>);
@override @override
_i4.Future<bool> editContact(_i2.Contact? editedContact) => _i4.Future<bool> editContact(_i2.ContactEntry? editedContact) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#editContact, #editContact,

View file

@ -7,7 +7,7 @@ import 'dart:async' as _i4;
import 'dart:ui' as _i5; import 'dart:ui' as _i5;
import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/mockito.dart' as _i1;
import 'package:stackwallet/models/contact.dart' as _i2; import 'package:stackwallet/models/isar/models/contact_entry.dart' as _i2;
import 'package:stackwallet/services/address_book_service.dart' as _i3; import 'package:stackwallet/services/address_book_service.dart' as _i3;
import 'package:stackwallet/services/notes_service.dart' as _i6; import 'package:stackwallet/services/notes_service.dart' as _i6;
@ -22,8 +22,8 @@ import 'package:stackwallet/services/notes_service.dart' as _i6;
// ignore_for_file: camel_case_types // ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class // ignore_for_file: subtype_of_sealed_class
class _FakeContact_0 extends _i1.SmartFake implements _i2.Contact { class _FakeContactEntry_0 extends _i1.SmartFake implements _i2.ContactEntry {
_FakeContact_0( _FakeContactEntry_0(
Object parent, Object parent,
Invocation parentInvocation, Invocation parentInvocation,
) : super( ) : super(
@ -38,46 +38,43 @@ class _FakeContact_0 extends _i1.SmartFake implements _i2.Contact {
class MockAddressBookService extends _i1.Mock class MockAddressBookService extends _i1.Mock
implements _i3.AddressBookService { implements _i3.AddressBookService {
@override @override
List<_i2.Contact> get contacts => (super.noSuchMethod( List<_i2.ContactEntry> get contacts => (super.noSuchMethod(
Invocation.getter(#contacts), Invocation.getter(#contacts),
returnValue: <_i2.Contact>[], returnValue: <_i2.ContactEntry>[],
) as List<_i2.Contact>); ) as List<_i2.ContactEntry>);
@override
_i4.Future<List<_i2.Contact>> get addressBookEntries => (super.noSuchMethod(
Invocation.getter(#addressBookEntries),
returnValue: _i4.Future<List<_i2.Contact>>.value(<_i2.Contact>[]),
) as _i4.Future<List<_i2.Contact>>);
@override @override
bool get hasListeners => (super.noSuchMethod( bool get hasListeners => (super.noSuchMethod(
Invocation.getter(#hasListeners), Invocation.getter(#hasListeners),
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i2.Contact getContactById(String? id) => (super.noSuchMethod( _i2.ContactEntry getContactById(String? id) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
returnValue: _FakeContact_0( returnValue: _FakeContactEntry_0(
this, this,
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
), ),
) as _i2.Contact); ) as _i2.ContactEntry);
@override @override
_i4.Future<List<_i2.Contact>> search(String? text) => (super.noSuchMethod( _i4.Future<List<_i2.ContactEntry>> search(String? text) =>
(super.noSuchMethod(
Invocation.method( Invocation.method(
#search, #search,
[text], [text],
), ),
returnValue: _i4.Future<List<_i2.Contact>>.value(<_i2.Contact>[]), returnValue:
) as _i4.Future<List<_i2.Contact>>); _i4.Future<List<_i2.ContactEntry>>.value(<_i2.ContactEntry>[]),
) as _i4.Future<List<_i2.ContactEntry>>);
@override @override
bool matches( bool matches(
String? term, String? term,
_i2.Contact? contact, _i2.ContactEntry? contact,
) => ) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
@ -90,7 +87,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i4.Future<bool> addContact(_i2.Contact? contact) => (super.noSuchMethod( _i4.Future<bool> addContact(_i2.ContactEntry? contact) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#addContact, #addContact,
[contact], [contact],
@ -98,7 +95,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: _i4.Future<bool>.value(false), returnValue: _i4.Future<bool>.value(false),
) as _i4.Future<bool>); ) as _i4.Future<bool>);
@override @override
_i4.Future<bool> editContact(_i2.Contact? editedContact) => _i4.Future<bool> editContact(_i2.ContactEntry? editedContact) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#editContact, #editContact,

View file

@ -175,17 +175,6 @@ void main() async {
verifyNoMoreInteractions(cachedClient); verifyNoMoreInteractions(cachedClient);
verifyNoMoreInteractions(tracker); verifyNoMoreInteractions(tracker);
}); });
test("Multisig/P2SH address", () {
expect(
mainnetWallet?.addressType(
address: "3DYuVEmuKWQFxJcF7jDPhwPiXLTiNnyMFb"),
DerivePathType.bip49);
expect(secureStore.interactions, 0);
verifyNoMoreInteractions(client);
verifyNoMoreInteractions(cachedClient);
verifyNoMoreInteractions(tracker);
});
}); });
group("validate mainnet bitcoincash addresses", () { group("validate mainnet bitcoincash addresses", () {

View file

@ -5,18 +5,17 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:stackwallet/models/contact.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/models/isar/stack_theme.dart'; import 'package:stackwallet/models/isar/stack_theme.dart';
import 'package:stackwallet/pages/address_book_views/subviews/contact_popup.dart'; import 'package:stackwallet/pages/address_book_views/subviews/contact_popup.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart';
import 'package:stackwallet/services/address_book_service.dart'; import 'package:stackwallet/services/address_book_service.dart';
import '../sample_data/theme_json.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/address_book_card.dart'; import 'package:stackwallet/widgets/address_book_card.dart';
import '../sample_data/theme_json.dart';
import 'address_book_card_test.mocks.dart'; import 'address_book_card_test.mocks.dart';
class MockedFunctions extends Mock { class MockedFunctions extends Mock {
@ -27,18 +26,20 @@ class MockedFunctions extends Mock {
void main() { void main() {
testWidgets('test returns Contact Address Entry', (widgetTester) async { testWidgets('test returns Contact Address Entry', (widgetTester) async {
final service = MockAddressBookService(); final service = MockAddressBookService();
final applicationThemesDirectoryPath = ""; const applicationThemesDirectoryPath = "";
when(service.getContactById("default")).thenAnswer( when(service.getContactById("default")).thenAnswer(
(realInvocation) => Contact( (realInvocation) => ContactEntry(
name: "John Doe", name: "John Doe",
addresses: [ addresses: [
const ContactAddressEntry( ContactAddressEntry()
coin: Coin.bitcoincash, ..coinName = Coin.bitcoincash.name
address: "some bch address", ..address = "some bch address"
label: "Bills") ..label = "Bills"
..other = null
], ],
isFavorite: true, isFavorite: true,
customId: '',
), ),
); );

View file

@ -7,7 +7,7 @@ import 'dart:async' as _i4;
import 'dart:ui' as _i5; import 'dart:ui' as _i5;
import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/mockito.dart' as _i1;
import 'package:stackwallet/models/contact.dart' as _i2; import 'package:stackwallet/models/isar/models/contact_entry.dart' as _i2;
import 'package:stackwallet/services/address_book_service.dart' as _i3; import 'package:stackwallet/services/address_book_service.dart' as _i3;
// ignore_for_file: type=lint // ignore_for_file: type=lint
@ -21,8 +21,8 @@ import 'package:stackwallet/services/address_book_service.dart' as _i3;
// ignore_for_file: camel_case_types // ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class // ignore_for_file: subtype_of_sealed_class
class _FakeContact_0 extends _i1.SmartFake implements _i2.Contact { class _FakeContactEntry_0 extends _i1.SmartFake implements _i2.ContactEntry {
_FakeContact_0( _FakeContactEntry_0(
Object parent, Object parent,
Invocation parentInvocation, Invocation parentInvocation,
) : super( ) : super(
@ -41,46 +41,43 @@ class MockAddressBookService extends _i1.Mock
} }
@override @override
List<_i2.Contact> get contacts => (super.noSuchMethod( List<_i2.ContactEntry> get contacts => (super.noSuchMethod(
Invocation.getter(#contacts), Invocation.getter(#contacts),
returnValue: <_i2.Contact>[], returnValue: <_i2.ContactEntry>[],
) as List<_i2.Contact>); ) as List<_i2.ContactEntry>);
@override
_i4.Future<List<_i2.Contact>> get addressBookEntries => (super.noSuchMethod(
Invocation.getter(#addressBookEntries),
returnValue: _i4.Future<List<_i2.Contact>>.value(<_i2.Contact>[]),
) as _i4.Future<List<_i2.Contact>>);
@override @override
bool get hasListeners => (super.noSuchMethod( bool get hasListeners => (super.noSuchMethod(
Invocation.getter(#hasListeners), Invocation.getter(#hasListeners),
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i2.Contact getContactById(String? id) => (super.noSuchMethod( _i2.ContactEntry getContactById(String? id) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
returnValue: _FakeContact_0( returnValue: _FakeContactEntry_0(
this, this,
Invocation.method( Invocation.method(
#getContactById, #getContactById,
[id], [id],
), ),
), ),
) as _i2.Contact); ) as _i2.ContactEntry);
@override @override
_i4.Future<List<_i2.Contact>> search(String? text) => (super.noSuchMethod( _i4.Future<List<_i2.ContactEntry>> search(String? text) =>
(super.noSuchMethod(
Invocation.method( Invocation.method(
#search, #search,
[text], [text],
), ),
returnValue: _i4.Future<List<_i2.Contact>>.value(<_i2.Contact>[]), returnValue:
) as _i4.Future<List<_i2.Contact>>); _i4.Future<List<_i2.ContactEntry>>.value(<_i2.ContactEntry>[]),
) as _i4.Future<List<_i2.ContactEntry>>);
@override @override
bool matches( bool matches(
String? term, String? term,
_i2.Contact? contact, _i2.ContactEntry? contact,
) => ) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
@ -93,7 +90,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: false, returnValue: false,
) as bool); ) as bool);
@override @override
_i4.Future<bool> addContact(_i2.Contact? contact) => (super.noSuchMethod( _i4.Future<bool> addContact(_i2.ContactEntry? contact) => (super.noSuchMethod(
Invocation.method( Invocation.method(
#addContact, #addContact,
[contact], [contact],
@ -101,7 +98,7 @@ class MockAddressBookService extends _i1.Mock
returnValue: _i4.Future<bool>.value(false), returnValue: _i4.Future<bool>.value(false),
) as _i4.Future<bool>); ) as _i4.Future<bool>);
@override @override
_i4.Future<bool> editContact(_i2.Contact? editedContact) => _i4.Future<bool> editContact(_i2.ContactEntry? editedContact) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#editContact, #editContact,