Merge remote-tracking branch 'origin_SW/staging' into add_nano

# Conflicts:
#	lib/models/isar/stack_theme.dart
#	lib/models/isar/stack_theme.g.dart
#	lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
#	lib/services/coins/firo/firo_wallet.dart
#	lib/themes/coin_icon_provider.dart
#	lib/themes/coin_image_provider.dart
#	lib/utilities/constants.dart
#	lib/utilities/enums/coin_enum.dart
This commit is contained in:
julian 2023-05-24 11:37:37 -06:00
commit 553e035ca7
128 changed files with 13031 additions and 4258 deletions

Binary file not shown.

Binary file not shown.

83
assets/svg/anonymize.svg Normal file
View file

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
version="1.1"
id="svg18"
sodipodi:docname="tx-icon-anonymize.svg"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<metadata
id="metadata22">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2262"
inkscape:window-height="1263"
id="namedview20"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="-15.813559"
inkscape:cy="12"
inkscape:window-x="1019"
inkscape:window-y="569"
inkscape:window-maximized="0"
inkscape:current-layer="g8" />
<g
clip-path="url(#clip0_5035_57299)"
id="g8">
<g
clip-path="url(#clip1_5035_57299)"
id="g6"
transform="matrix(1.6610229,0,0,1.7055051,-7.9831634,-8.2054918)">
<path
d="m 9.92728,11.6469 c 0.13122,0.5688 -0.49218,1.0145 -0.9871,0.7028 L 8.27572,11.934 6.88393,14.1606 c -0.3645,0.583 0.05479,1.3393 0.74238,1.3393 h 0.87554 c 0.48235,0 0.87446,0.3916 0.87446,0.8739 0,0.4824 -0.39211,0.8764 -0.87446,0.8764 H 7.62904 c -2.06062,0 -3.31679,-2.2651 -2.22769,-4.0141 L 6.79123,11.0098 6.12514,10.5915 C 5.62994,10.2797 5.75627,9.52505 6.32557,9.3938 L 8.8256,8.81548 C 9.06049,8.7649 9.29838,8.90709 9.35307,9.14498 Z M 12.741,7.15873 13.8689,8.96724 13.2058,9.37959 c -0.4966,0.30925 -0.3711,1.06481 0.199,1.19681 l 2.4992,0.5783 c 0.2358,0.0546 0.4712,-0.0926 0.5253,-0.3284 L 17.0046,8.32631 C 17.1356,7.75728 16.5138,7.31322 16.0183,7.62193 L 15.3522,8.03755 14.2257,6.23396 C 13.1981,4.58951 10.8023,4.58841 9.77416,6.23227 L 9.57182,6.55552 C 9.31752,6.96158 9.4433,7.50381 9.84799,7.75865 10.256,8.01456 10.7987,7.89225 11.0541,7.48412 L 11.2576,7.159 c 0.3486,-0.55754 1.1498,-0.53703 1.4834,-2.7e-4 z m 5.857,6.07957 -0.4646,-0.7454 c -0.2553,-0.4096 -0.7946,-0.5348 -1.2042,-0.2791 -0.4085,0.2548 -0.5338,0.797 -0.2784,1.2053 l 0.4646,0.7424 c 0.365,0.5829 -0.0542,1.3398 -0.7421,1.3398 h -2.6247 l 6e-4,-0.7859 c 0,-0.5846 -0.7068,-0.8774 -1.1203,-0.464 l -1.8159,1.8165 c -0.1701,0.1701 -0.1701,0.4487 2e-4,0.6188 l 1.8161,1.8139 c 0.4135,0.4129 1.1198,0.12 1.1198,-0.4643 l -7e-4,-0.7842 h 2.6212 c 2.0616,3e-4 3.3194,-2.2665 2.2284,-4.0138 z"
id="path4"
inkscape:connector-curvature="0"
style="fill:#494949" />
</g>
</g>
<defs
id="defs16">
<clipPath
id="clip0_5035_57299">
<rect
width="24"
height="24"
fill="white"
id="rect10" />
</clipPath>
<clipPath
id="clip1_5035_57299">
<rect
width="14"
height="14"
fill="white"
transform="translate(5 5)"
id="rect13" />
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

@ -1 +1 @@
Subproject commit 81659ce57952c5ab54ffe6bacfbf43da159fff3e Subproject commit 73d257ed2fe5b204cf3589822e226301b187b86d

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

@ -115,8 +115,9 @@ class CachedElectrumX {
key: groupId, key: groupId,
value: set); value: set);
Logging.instance.log( Logging.instance.log(
"Updated currently anonymity set for ${coin.name} with group ID $groupId", "Updated current anonymity set for ${coin.name} with group ID $groupId",
level: LogLevel.Info); level: LogLevel.Info,
);
} }
return set; return set;
@ -187,16 +188,17 @@ class CachedElectrumX {
} }
} }
Future<List<dynamic>> getUsedCoinSerials({ Future<List<String>> getUsedCoinSerials({
required Coin coin, required Coin coin,
int startNumber = 0, int startNumber = 0,
}) async { }) async {
try { try {
List<dynamic>? cachedSerials = DB.instance.get<dynamic>( final _list = DB.instance.get<dynamic>(
boxName: DB.instance.boxNameUsedSerialsCache(coin: coin), boxName: DB.instance.boxNameUsedSerialsCache(coin: coin),
key: "serials") as List?; key: "serials") as List?;
cachedSerials ??= []; List<String> cachedSerials =
_list == null ? [] : List<String>.from(_list);
final startNumber = cachedSerials.length; final startNumber = cachedSerials.length;
@ -210,8 +212,9 @@ class CachedElectrumX {
); );
final serials = await client.getUsedCoinSerials(startNumber: startNumber); final serials = await client.getUsedCoinSerials(startNumber: startNumber);
List newSerials = []; List<String> newSerials = [];
for (var element in (serials["serials"] as List)) {
for (final element in (serials["serials"] as List)) {
if (!isHexadecimal(element as String)) { if (!isHexadecimal(element as String)) {
newSerials.add(base64ToHex(element)); newSerials.add(base64ToHex(element));
} else { } else {
@ -221,9 +224,10 @@ class CachedElectrumX {
cachedSerials.addAll(newSerials); cachedSerials.addAll(newSerials);
await DB.instance.put<dynamic>( await DB.instance.put<dynamic>(
boxName: DB.instance.boxNameUsedSerialsCache(coin: coin), boxName: DB.instance.boxNameUsedSerialsCache(coin: coin),
key: "serials", key: "serials",
value: cachedSerials); value: cachedSerials,
);
return cachedSerials; return cachedSerials;
} catch (e, s) { } catch (e, s) {

View file

@ -70,7 +70,7 @@ final openedFromSWBFileStringStateProvider =
// runs the MyApp widget and checks for new users, caching the value in the // runs the MyApp widget and checks for new users, caching the value in the
// miscellaneous box for later use // miscellaneous box for later use
void main() async { void main() async {
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
GoogleFonts.config.allowRuntimeFetching = false; GoogleFonts.config.allowRuntimeFetching = false;
if (Platform.isIOS) { if (Platform.isIOS) {
Util.libraryPath = await getLibraryDirectory(); Util.libraryPath = await getLibraryDirectory();
@ -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,11 +178,10 @@ void main() async {
} }
} }
//Add Themes directory - TODO
// await StackFileSystem.applicationThemesDirectory();
monero.onStartup(); monero.onStartup();
wownero.onStartup(); if (!Platform.isLinux && !Platform.isWindows) {
wownero.onStartup();
}
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
// overlays: [SystemUiOverlay.bottom]); // overlays: [SystemUiOverlay.bottom]);
@ -191,33 +190,8 @@ void main() async {
await MainDB.instance.initMainDB(); await MainDB.instance.initMainDB();
ThemeService.instance.init(MainDB.instance); ThemeService.instance.init(MainDB.instance);
// install default themes // check and update or install default themes
if (!(await ThemeService.instance.verifyInstalled(themeId: "light"))) { await ThemeService.instance.checkDefaultThemesOnStartup();
Logging.instance.log(
"Installing default light theme...",
level: LogLevel.Info,
);
final lightZip = await rootBundle.load("assets/default_themes/light.zip");
await ThemeService.instance
.install(themeArchiveData: lightZip.buffer.asUint8List());
Logging.instance.log(
"Installing default light theme... finished",
level: LogLevel.Info,
);
}
if (!(await ThemeService.instance.verifyInstalled(themeId: "dark"))) {
Logging.instance.log(
"Installing default dark theme... ",
level: LogLevel.Info,
);
final darkZip = await rootBundle.load("assets/default_themes/dark.zip");
await ThemeService.instance
.install(themeArchiveData: darkZip.buffer.asUint8List());
Logging.instance.log(
"Installing default dark theme... finished",
level: LogLevel.Info,
);
}
runApp(const ProviderScope(child: MyApp())); runApp(const ProviderScope(child: MyApp()));
} }

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

@ -1,4 +1,5 @@
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
part 'contact_entry.g.dart'; part 'contact_entry.g.dart';
@ -16,9 +17,92 @@ class ContactEntry {
late final String? emojiChar; late final String? emojiChar;
late final String name; late final String name;
late final List<String> addresses; late final List<ContactAddressEntry> addresses;
late final bool isFavorite; late final bool isFavorite;
@Index(unique: true, replace: true) @Index(unique: true, replace: true)
late final String customId; 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()}";
}
}

View file

@ -20,7 +20,8 @@ const ContactEntrySchema = CollectionSchema(
r'addresses': PropertySchema( r'addresses': PropertySchema(
id: 0, id: 0,
name: r'addresses', name: r'addresses',
type: IsarType.stringList, type: IsarType.objectList,
target: r'ContactAddressEntry',
), ),
r'customId': PropertySchema( r'customId': PropertySchema(
id: 1, id: 1,
@ -64,7 +65,7 @@ const ContactEntrySchema = CollectionSchema(
) )
}, },
links: {}, links: {},
embeddedSchemas: {}, embeddedSchemas: {r'ContactAddressEntry': ContactAddressEntrySchema},
getId: _contactEntryGetId, getId: _contactEntryGetId,
getLinks: _contactEntryGetLinks, getLinks: _contactEntryGetLinks,
attach: _contactEntryAttach, attach: _contactEntryAttach,
@ -79,9 +80,11 @@ int _contactEntryEstimateSize(
var bytesCount = offsets.last; var bytesCount = offsets.last;
bytesCount += 3 + object.addresses.length * 3; bytesCount += 3 + object.addresses.length * 3;
{ {
final offsets = allOffsets[ContactAddressEntry]!;
for (var i = 0; i < object.addresses.length; i++) { for (var i = 0; i < object.addresses.length; i++) {
final value = object.addresses[i]; final value = object.addresses[i];
bytesCount += value.length * 3; bytesCount +=
ContactAddressEntrySchema.estimateSize(value, offsets, allOffsets);
} }
} }
bytesCount += 3 + object.customId.length * 3; bytesCount += 3 + object.customId.length * 3;
@ -101,7 +104,12 @@ void _contactEntrySerialize(
List<int> offsets, List<int> offsets,
Map<Type, List<int>> allOffsets, Map<Type, List<int>> allOffsets,
) { ) {
writer.writeStringList(offsets[0], object.addresses); writer.writeObjectList<ContactAddressEntry>(
offsets[0],
allOffsets,
ContactAddressEntrySchema.serialize,
object.addresses,
);
writer.writeString(offsets[1], object.customId); writer.writeString(offsets[1], object.customId);
writer.writeString(offsets[2], object.emojiChar); writer.writeString(offsets[2], object.emojiChar);
writer.writeBool(offsets[3], object.isFavorite); writer.writeBool(offsets[3], object.isFavorite);
@ -115,7 +123,13 @@ ContactEntry _contactEntryDeserialize(
Map<Type, List<int>> allOffsets, Map<Type, List<int>> allOffsets,
) { ) {
final object = ContactEntry( final object = ContactEntry(
addresses: reader.readStringList(offsets[0]) ?? [], addresses: reader.readObjectList<ContactAddressEntry>(
offsets[0],
ContactAddressEntrySchema.deserialize,
allOffsets,
ContactAddressEntry(),
) ??
[],
customId: reader.readString(offsets[1]), customId: reader.readString(offsets[1]),
emojiChar: reader.readStringOrNull(offsets[2]), emojiChar: reader.readStringOrNull(offsets[2]),
isFavorite: reader.readBool(offsets[3]), isFavorite: reader.readBool(offsets[3]),
@ -133,7 +147,13 @@ P _contactEntryDeserializeProp<P>(
) { ) {
switch (propertyId) { switch (propertyId) {
case 0: case 0:
return (reader.readStringList(offset) ?? []) as P; return (reader.readObjectList<ContactAddressEntry>(
offset,
ContactAddressEntrySchema.deserialize,
allOffsets,
ContactAddressEntry(),
) ??
[]) as P;
case 1: case 1:
return (reader.readString(offset)) as P; return (reader.readString(offset)) as P;
case 2: case 2:
@ -341,142 +361,6 @@ extension ContactEntryQueryWhere
extension ContactEntryQueryFilter extension ContactEntryQueryFilter
on QueryBuilder<ContactEntry, ContactEntry, QFilterCondition> { on QueryBuilder<ContactEntry, ContactEntry, QFilterCondition> {
QueryBuilder<ContactEntry, ContactEntry, QAfterFilterCondition>
addressesElementEqualTo(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'addresses',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactEntry, ContactEntry, QAfterFilterCondition>
addressesElementGreaterThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'addresses',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactEntry, ContactEntry, QAfterFilterCondition>
addressesElementLessThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'addresses',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactEntry, ContactEntry, QAfterFilterCondition>
addressesElementBetween(
String lower,
String upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'addresses',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactEntry, ContactEntry, QAfterFilterCondition>
addressesElementStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'addresses',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactEntry, ContactEntry, QAfterFilterCondition>
addressesElementEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'addresses',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactEntry, ContactEntry, QAfterFilterCondition>
addressesElementContains(String value, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'addresses',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactEntry, ContactEntry, QAfterFilterCondition>
addressesElementMatches(String pattern, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'addresses',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactEntry, ContactEntry, QAfterFilterCondition>
addressesElementIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'addresses',
value: '',
));
});
}
QueryBuilder<ContactEntry, ContactEntry, QAfterFilterCondition>
addressesElementIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'addresses',
value: '',
));
});
}
QueryBuilder<ContactEntry, ContactEntry, QAfterFilterCondition> QueryBuilder<ContactEntry, ContactEntry, QAfterFilterCondition>
addressesLengthEqualTo(int length) { addressesLengthEqualTo(int length) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
@ -1055,7 +939,14 @@ extension ContactEntryQueryFilter
} }
extension ContactEntryQueryObject extension ContactEntryQueryObject
on QueryBuilder<ContactEntry, ContactEntry, QFilterCondition> {} on QueryBuilder<ContactEntry, ContactEntry, QFilterCondition> {
QueryBuilder<ContactEntry, ContactEntry, QAfterFilterCondition>
addressesElement(FilterQuery<ContactAddressEntry> q) {
return QueryBuilder.apply(this, (query) {
return query.object(q, r'addresses');
});
}
}
extension ContactEntryQueryLinks extension ContactEntryQueryLinks
on QueryBuilder<ContactEntry, ContactEntry, QFilterCondition> {} on QueryBuilder<ContactEntry, ContactEntry, QFilterCondition> {}
@ -1178,12 +1069,6 @@ extension ContactEntryQuerySortThenBy
extension ContactEntryQueryWhereDistinct extension ContactEntryQueryWhereDistinct
on QueryBuilder<ContactEntry, ContactEntry, QDistinct> { on QueryBuilder<ContactEntry, ContactEntry, QDistinct> {
QueryBuilder<ContactEntry, ContactEntry, QDistinct> distinctByAddresses() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'addresses');
});
}
QueryBuilder<ContactEntry, ContactEntry, QDistinct> distinctByCustomId( QueryBuilder<ContactEntry, ContactEntry, QDistinct> distinctByCustomId(
{bool caseSensitive = true}) { {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
@ -1220,7 +1105,7 @@ extension ContactEntryQueryProperty
}); });
} }
QueryBuilder<ContactEntry, List<String>, QQueryOperations> QueryBuilder<ContactEntry, List<ContactAddressEntry>, QQueryOperations>
addressesProperty() { addressesProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'addresses'); return query.addPropertyName(r'addresses');
@ -1251,3 +1136,673 @@ extension ContactEntryQueryProperty
}); });
} }
} }
// **************************************************************************
// IsarEmbeddedGenerator
// **************************************************************************
// coverage:ignore-file
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
const ContactAddressEntrySchema = Schema(
name: r'ContactAddressEntry',
id: 2556413586404997281,
properties: {
r'address': PropertySchema(
id: 0,
name: r'address',
type: IsarType.string,
),
r'coinName': PropertySchema(
id: 1,
name: r'coinName',
type: IsarType.string,
),
r'label': PropertySchema(
id: 2,
name: r'label',
type: IsarType.string,
),
r'other': PropertySchema(
id: 3,
name: r'other',
type: IsarType.string,
)
},
estimateSize: _contactAddressEntryEstimateSize,
serialize: _contactAddressEntrySerialize,
deserialize: _contactAddressEntryDeserialize,
deserializeProp: _contactAddressEntryDeserializeProp,
);
int _contactAddressEntryEstimateSize(
ContactAddressEntry object,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
var bytesCount = offsets.last;
bytesCount += 3 + object.address.length * 3;
bytesCount += 3 + object.coinName.length * 3;
bytesCount += 3 + object.label.length * 3;
{
final value = object.other;
if (value != null) {
bytesCount += 3 + value.length * 3;
}
}
return bytesCount;
}
void _contactAddressEntrySerialize(
ContactAddressEntry object,
IsarWriter writer,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
writer.writeString(offsets[0], object.address);
writer.writeString(offsets[1], object.coinName);
writer.writeString(offsets[2], object.label);
writer.writeString(offsets[3], object.other);
}
ContactAddressEntry _contactAddressEntryDeserialize(
Id id,
IsarReader reader,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
final object = ContactAddressEntry();
object.address = reader.readString(offsets[0]);
object.coinName = reader.readString(offsets[1]);
object.label = reader.readString(offsets[2]);
object.other = reader.readStringOrNull(offsets[3]);
return object;
}
P _contactAddressEntryDeserializeProp<P>(
IsarReader reader,
int propertyId,
int offset,
Map<Type, List<int>> allOffsets,
) {
switch (propertyId) {
case 0:
return (reader.readString(offset)) as P;
case 1:
return (reader.readString(offset)) as P;
case 2:
return (reader.readString(offset)) as P;
case 3:
return (reader.readStringOrNull(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
}
}
extension ContactAddressEntryQueryFilter on QueryBuilder<ContactAddressEntry,
ContactAddressEntry, QFilterCondition> {
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
addressEqualTo(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'address',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
addressGreaterThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'address',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
addressLessThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'address',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
addressBetween(
String lower,
String upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'address',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
addressStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'address',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
addressEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'address',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
addressContains(String value, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'address',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
addressMatches(String pattern, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'address',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
addressIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'address',
value: '',
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
addressIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'address',
value: '',
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
coinNameEqualTo(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'coinName',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
coinNameGreaterThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'coinName',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
coinNameLessThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'coinName',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
coinNameBetween(
String lower,
String upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'coinName',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
coinNameStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'coinName',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
coinNameEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'coinName',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
coinNameContains(String value, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'coinName',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
coinNameMatches(String pattern, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'coinName',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
coinNameIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'coinName',
value: '',
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
coinNameIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'coinName',
value: '',
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
labelEqualTo(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'label',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
labelGreaterThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'label',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
labelLessThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'label',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
labelBetween(
String lower,
String upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'label',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
labelStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'label',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
labelEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'label',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
labelContains(String value, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'label',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
labelMatches(String pattern, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'label',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
labelIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'label',
value: '',
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
labelIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'label',
value: '',
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
otherIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'other',
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
otherIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'other',
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
otherEqualTo(
String? value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'other',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
otherGreaterThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'other',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
otherLessThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'other',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
otherBetween(
String? lower,
String? upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'other',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
otherStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'other',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
otherEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'other',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
otherContains(String value, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'other',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
otherMatches(String pattern, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'other',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
otherIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'other',
value: '',
));
});
}
QueryBuilder<ContactAddressEntry, ContactAddressEntry, QAfterFilterCondition>
otherIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'other',
value: '',
));
});
}
}
extension ContactAddressEntryQueryObject on QueryBuilder<ContactAddressEntry,
ContactAddressEntry, QFilterCondition> {}

File diff suppressed because it is too large Load diff

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(IThemeAssets 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(
themeAssetsProvider,
),
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(
themeAssetsProvider,
),
ref),
),
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.accentColorDark, .accentColorDark,

View file

@ -120,6 +120,8 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> {
if (Platform.isWindows) { if (Platform.isWindows) {
_coins.remove(Coin.monero); _coins.remove(Coin.monero);
_coins.remove(Coin.wownero); _coins.remove(Coin.wownero);
} else if (Platform.isLinux) {
_coins.remove(Coin.wownero);
} }
coinEntities.addAll(_coins.map((e) => CoinEntity(e))); coinEntities.addAll(_coins.map((e) => CoinEntity(e)));

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);
}); });
@ -102,7 +100,8 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType"); debugPrint("BUILD: $runtimeType");
final contacts = ref.watch(addressBookServiceProvider.select((value) => value.contacts)); final contacts =
ref.watch(addressBookServiceProvider.select((value) => value.contacts));
final isDesktop = Util.isDesktop; final isDesktop = Util.isDesktop;
return ConditionalParent( return ConditionalParent(
@ -305,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,
), ),
), ),
], ],
@ -351,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(
@ -268,7 +270,7 @@ class _ContactDetailsViewState extends ConsumerState<ContactDetailsView> {
onPressed: () { onPressed: () {
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
EditContactNameEmojiView.routeName, EditContactNameEmojiView.routeName,
arguments: _contact.id, arguments: _contact.customId,
); );
}, },
style: Theme.of(context) style: Theme.of(context)
@ -316,7 +318,7 @@ class _ContactDetailsViewState extends ConsumerState<ContactDetailsView> {
onTap: () { onTap: () {
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
AddNewContactAddressView.routeName, AddNewContactAddressView.routeName,
arguments: _contact.id, arguments: _contact.customId,
); );
}, },
), ),
@ -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(
@ -381,7 +385,7 @@ class _ContactDetailsViewState extends ConsumerState<ContactDetailsView> {
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
EditContactAddressView.routeName, EditContactAddressView.routeName,
arguments: Tuple2(_contact.id, e), arguments: Tuple2(_contact.customId, e),
); );
}, },
child: RoundedContainer( child: RoundedContainer(

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';
@ -108,13 +110,15 @@ class ContactPopUp extends ConsumerWidget {
.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) => themeProvider.select(
value.assets.stackIcon, (value) => value
.assets.stackIcon,
),
), ),
), ),
width: 20, width: 20,
@ -142,13 +146,13 @@ class ContactPopUp extends ConsumerWidget {
STextStyles.itemSubtitle12(context), STextStyles.itemSubtitle12(context),
), ),
), ),
if (contact.id != "default") if (contact.customId != "default")
TextButton( TextButton(
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
ContactDetailsView.routeName, ContactDetailsView.routeName,
arguments: contact.id, arguments: contact.customId,
); );
}, },
style: Theme.of(context) style: Theme.of(context)
@ -172,7 +176,7 @@ class ContactPopUp extends ConsumerWidget {
), ),
), ),
SizedBox( SizedBox(
height: contact.id == "default" ? 16 : 8, height: contact.customId == "default" ? 16 : 8,
), ),
Container( Container(
height: 1, height: 1,
@ -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,
), ),
@ -227,14 +233,14 @@ class ContactPopUp extends ConsumerWidget {
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
children: [ children: [
if (contact.id == "default") if (contact.customId == "default")
Text( Text(
e.other!, e.other!,
style: style:
STextStyles.itemSubtitle12( STextStyles.itemSubtitle12(
context), context),
), ),
if (contact.id != "default") if (contact.customId != "default")
Text( Text(
"${e.label} (${e.coin.ticker})", "${e.label} (${e.coin.ticker})",
style: style:
@ -330,13 +336,13 @@ class ContactPopUp extends ConsumerWidget {
), ),
], ],
), ),
if (contact.id != "default" && if (contact.customId != "default" &&
hasActiveWallet && hasActiveWallet &&
!isExchangeFlow) !isExchangeFlow)
const SizedBox( const SizedBox(
width: 4, width: 4,
), ),
if (contact.id != "default" && if (contact.customId != "default" &&
hasActiveWallet && hasActiveWallet &&
!isExchangeFlow) !isExchangeFlow)
Column( Column(

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

@ -113,7 +113,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
super.initState(); super.initState();
} }
String _fetchIconAssetForStatus(String statusString, ThemeAssets assets) { String _fetchIconAssetForStatus(String statusString, IThemeAssets assets) {
ChangeNowTransactionStatus? status; ChangeNowTransactionStatus? status;
try { try {
if (statusString.toLowerCase().startsWith("waiting")) { if (statusString.toLowerCase().startsWith("waiting")) {
@ -322,11 +322,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
File( File(
_fetchIconAssetForStatus( _fetchIconAssetForStatus(
trade.status, trade.status,
ref.watch( ref.watch(themeAssetsProvider),
themeProvider.select(
(value) => value.assets,
),
),
), ),
), ),
width: 32, width: 32,
@ -393,11 +389,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
File( File(
_fetchIconAssetForStatus( _fetchIconAssetForStatus(
trade.status, trade.status,
ref.watch( ref.watch(themeAssetsProvider),
themeProvider.select(
(value) => value.assets,
),
),
), ),
), ),
width: 32, width: 32,
@ -1232,7 +1224,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
if (trade.exchangeName if (trade.exchangeName
.startsWith(TrocadorExchange.exchangeName)) { .startsWith(TrocadorExchange.exchangeName)) {
url = url =
"https://trocador.app/en/checkout${trade.tradeId}"; "https://trocador.app/en/checkout/${trade.tradeId}";
} }
} }
return ConditionalParent( return ConditionalParent(

View file

@ -138,10 +138,8 @@ class _PaynymClaimViewState extends ConsumerState<PaynymClaimView> {
const Spacer( const Spacer(
flex: 1, flex: 1,
), ),
Image( SvgPicture.asset(
image: AssetImage( Assets.svg.unclaimedPaynym,
Assets.svg.unclaimedPaynym,
),
width: MediaQuery.of(context).size.width / 2, width: MediaQuery.of(context).size.width / 2,
), ),
const SizedBox( const SizedBox(

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

@ -225,14 +225,14 @@ class _IncognitoInstalledThemesState
extends ConsumerState<IncognitoInstalledThemes> { extends ConsumerState<IncognitoInstalledThemes> {
late final StreamSubscription<void> _subscription; late final StreamSubscription<void> _subscription;
List<Tuple2<String, String>> installedThemeIdNames = []; List<Tuple3<String, String, int?>> installedThemeIdNames = [];
void _updateInstalledList() { void _updateInstalledList() {
installedThemeIdNames = ref installedThemeIdNames = ref
.read(pThemeService) .read(pThemeService)
.installedThemes .installedThemes
.where((e) => e.themeId != "light" && e.themeId != "dark") .where((e) => e.themeId != "light" && e.themeId != "dark")
.map((e) => Tuple2(e.themeId, e.name)) .map((e) => Tuple3(e.themeId, e.name, e.version))
.toList(); .toList();
} }
@ -274,6 +274,7 @@ class _IncognitoInstalledThemesState
data: StackThemeMetaData( data: StackThemeMetaData(
name: e.item2, name: e.item2,
id: e.item1, id: e.item1,
version: e.item3 ?? 1,
sha256: "", sha256: "",
size: "", size: "",
previewImageUrl: "", previewImageUrl: "",

View file

@ -39,6 +39,7 @@ class _StackThemeCardState extends ConsumerState<StackThemeCard> {
late final StreamSubscription<void> _subscription; late final StreamSubscription<void> _subscription;
late bool _hasTheme; late bool _hasTheme;
bool _needsUpdate = false;
String? _cachedSize; String? _cachedSize;
Future<bool> _downloadAndInstall() async { Future<bool> _downloadAndInstall() async {
@ -84,6 +85,7 @@ class _StackThemeCardState extends ConsumerState<StackThemeCard> {
title: message, title: message,
onOkPressed: (_) { onOkPressed: (_) {
setState(() { setState(() {
_needsUpdate = !result;
_hasTheme = result; _hasTheme = result;
}); });
}, },
@ -141,16 +143,21 @@ class _StackThemeCardState extends ConsumerState<StackThemeCard> {
} }
} }
StackTheme? getInstalled() => ref
.read(mainDBProvider)
.isar
.stackThemes
.where()
.themeIdEqualTo(widget.data.id)
.findFirstSync();
@override @override
void initState() { void initState() {
_hasTheme = ref final installedTheme = getInstalled();
.read(mainDBProvider) _hasTheme = installedTheme != null;
.isar if (_hasTheme) {
.stackThemes _needsUpdate = widget.data.version > (installedTheme?.version ?? 0);
.where() }
.themeIdEqualTo(widget.data.id)
.countSync() >
0;
_subscription = ref _subscription = ref
.read(mainDBProvider) .read(mainDBProvider)
@ -158,18 +165,16 @@ class _StackThemeCardState extends ConsumerState<StackThemeCard> {
.stackThemes .stackThemes
.watchLazy() .watchLazy()
.listen((event) async { .listen((event) async {
final hasTheme = (await ref final installedTheme = getInstalled();
.read(mainDBProvider) final hasTheme = installedTheme != null;
.isar
.stackThemes
.where()
.themeIdEqualTo(widget.data.id)
.count()) >
0;
if (_hasTheme != hasTheme && mounted) { if (_hasTheme != hasTheme && mounted) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
setState(() { setState(() {
_hasTheme = hasTheme; _hasTheme = hasTheme;
if (hasTheme) {
_needsUpdate =
widget.data.version > (installedTheme.version ?? 0);
}
}); });
}); });
} }
@ -272,6 +277,16 @@ class _StackThemeCardState extends ConsumerState<StackThemeCard> {
} }
}, },
), ),
if (_hasTheme && _needsUpdate)
const SizedBox(
height: 12,
),
if (_hasTheme && _needsUpdate)
PrimaryButton(
label: "Update",
buttonHeight: isDesktop ? ButtonHeight.s : ButtonHeight.l,
onPressed: _downloadPressed,
),
const SizedBox( const SizedBox(
height: 12, height: 12,
), ),

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

@ -718,6 +718,7 @@ class _NodeFormState extends ConsumerState<NodeForm> {
case Coin.dogecoinTestNet: case Coin.dogecoinTestNet:
case Coin.epicCash: case Coin.epicCash:
case Coin.nano: case Coin.nano:
case Coin.eCash:
return false; return false;
case Coin.ethereum: case Coin.ethereum:

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

@ -190,7 +190,7 @@ class AboutItem extends StatelessWidget {
height: iconSize, height: iconSize,
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.bottomNavIconIcon, .topNavIconPrimary,
), ),
), ),
const SizedBox( const SizedBox(

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,21 +23,8 @@ 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, IThemeAssets assets) {
if (!isReceived && transaction.subType == TransactionSubType.mint) { if (!isReceived && transaction.subType == TransactionSubType.mint) {
if (isCancelled) { if (isCancelled) {
return Assets.svg.anonymizeFailed; return Assets.svg.anonymizeFailed;
@ -78,7 +65,7 @@ class TxIcon extends ConsumerWidget {
currentHeight, currentHeight,
coin.requiredConfirmations, coin.requiredConfirmations,
), ),
ref.watch(themeProvider).assets, ref.watch(themeAssetsProvider),
); );
return SizedBox( return SizedBox(

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,11 +1,13 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/foundation.dart';
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';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/receive_view/addresses/address_details_view.dart';
import 'package:stackwallet/pages/wallet_view/sub_widgets/tx_icon.dart'; import 'package:stackwallet/pages/wallet_view/sub_widgets/tx_icon.dart';
import 'package:stackwallet/pages/wallet_view/transaction_views/dialogs/cancelling_transaction_progress_dialog.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/dialogs/cancelling_transaction_progress_dialog.dart';
import 'package:stackwallet/pages/wallet_view/transaction_views/edit_note_view.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/edit_note_view.dart';
@ -605,17 +607,66 @@ class _TransactionDetailsViewState
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
children: [ children: [
Text( ConditionalParent(
_transaction.type == condition: kDebugMode,
TransactionType.outgoing builder: (child) {
? "Sent to" return Row(
: "Receiving address", mainAxisAlignment:
style: isDesktop MainAxisAlignment
? STextStyles .spaceBetween,
.desktopTextExtraExtraSmall( children: [
context) child,
: STextStyles.itemSubtitle( CustomTextButton(
context), text: "Info",
onTap: () {
if (isDesktop) {
showDialog<void>(
context: context,
builder: (_) =>
DesktopDialog(
maxHeight:
double.infinity,
child:
AddressDetailsView(
addressId:
_transaction
.address
.value!
.id,
walletId: widget
.walletId,
),
),
);
} else {
Navigator.of(context)
.pushNamed(
AddressDetailsView
.routeName,
arguments: Tuple2(
_transaction.address
.value!.id,
widget.walletId,
),
);
}
},
)
],
);
},
child: Text(
_transaction.type ==
TransactionType.outgoing
? "Sent to"
: "Receiving address",
style: isDesktop
? STextStyles
.desktopTextExtraExtraSmall(
context)
: STextStyles.itemSubtitle(
context),
),
), ),
const SizedBox( const SizedBox(
height: 8, height: 8,
@ -1099,6 +1150,46 @@ class _TransactionDetailsViewState
], ],
), ),
), ),
if (kDebugMode)
isDesktop
? const _Divider()
: const SizedBox(
height: 12,
),
if (kDebugMode)
RoundedWhiteContainer(
padding: isDesktop
? const EdgeInsets.all(16)
: const EdgeInsets.all(12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"Tx sub type",
style: isDesktop
? STextStyles
.desktopTextExtraExtraSmall(
context)
: STextStyles.itemSubtitle(context),
),
SelectableText(
_transaction.subType.toString(),
style: isDesktop
? STextStyles
.desktopTextExtraExtraSmall(
context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
)
: STextStyles.itemSubtitle12(context),
),
],
),
),
isDesktop isDesktop
? const _Divider() ? const _Divider()
: const SizedBox( : const SizedBox(

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)));
@ -110,19 +111,21 @@ class _DesktopContactDetailsState extends ConsumerState<DesktopContactDetails> {
width: 32, width: 32,
height: 32, height: 32,
decoration: BoxDecoration( decoration: BoxDecoration(
color: contact.id == "default" color: contact.customId == "default"
? Colors.transparent ? Colors.transparent
: Theme.of(context) : Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.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';
@ -287,7 +288,7 @@ class DesktopTradeRowCard extends ConsumerStatefulWidget {
class _DesktopTradeRowCardState extends ConsumerState<DesktopTradeRowCard> { class _DesktopTradeRowCardState extends ConsumerState<DesktopTradeRowCard> {
late final String tradeId; late final String tradeId;
String _fetchIconAssetForStatus(String statusString, ThemeAssets assets) { String _fetchIconAssetForStatus(String statusString, IThemeAssets assets) {
ChangeNowTransactionStatus? status; ChangeNowTransactionStatus? status;
try { try {
if (statusString.toLowerCase().startsWith("waiting")) { if (statusString.toLowerCase().startsWith("waiting")) {
@ -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(
themeAssetsProvider,
),
),
), ),
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';
@ -61,8 +63,8 @@ class DesktopBuyIcon extends ConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
return SvgPicture.asset( return SvgPicture.file(
ref.watch(themeProvider.select((value) => value.assets.buy)), File(ref.watch(themeAssetsProvider).buy),
width: 20, width: 20,
height: 20, height: 20,
color: DesktopMenuItemId.buy == color: DesktopMenuItemId.buy ==
@ -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

@ -69,7 +69,7 @@ class _MoreFeaturesDialogState extends ConsumerState<MoreFeaturesDialog> {
_MoreFeaturesItem( _MoreFeaturesItem(
label: "Anonymize funds", label: "Anonymize funds",
detail: "Anonymize funds", detail: "Anonymize funds",
iconAsset: Assets.svg.anonymize, iconAsset: Assets.svg.recycle,
onPressed: () => widget.onAnonymizeAllPressed?.call(), onPressed: () => widget.onAnonymizeAllPressed?.call(),
), ),
if (manager.hasWhirlpoolSupport) if (manager.hasWhirlpoolSupport)

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,
@ -249,7 +252,7 @@ class _DesktopLoginViewState extends ConsumerState<DesktopLoginView> {
), ),
suffixIcon: UnconstrainedBox( suffixIcon: UnconstrainedBox(
child: SizedBox( child: SizedBox(
height: 70, height: 40,
child: Row( child: Row(
children: [ children: [
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_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

@ -118,44 +118,6 @@ class _AppearanceOptionSettings
], ],
), ),
), ),
// const Padding(
// padding: EdgeInsets.all(10.0),
// child: Divider(
// thickness: 0.5,
// ),
// ),
// Padding(
// padding: const EdgeInsets.all(10.0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text(
// "System brightness",
// style: STextStyles.desktopTextExtraSmall(context)
// .copyWith(
// color: Theme.of(context)
// .extension<StackColors>()!
// .textDark),
// textAlign: TextAlign.left,
// ),
// SizedBox(
// height: 20,
// width: 40,
// child: DraggableSwitchButton(
// isOn: ref.watch(
// prefsChangeNotifierProvider.select(
// (value) => value.enableSystemBrightness),
// ),
// onValueChanged: (newValue) {
// ref
// .read(prefsChangeNotifierProvider)
// .enableSystemBrightness = newValue;
// },
// ),
// )
// ],
// ),
// ),
const Padding( const Padding(
padding: EdgeInsets.all(10.0), padding: EdgeInsets.all(10.0),
child: Divider( child: Divider(

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';
@ -58,6 +58,8 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
if (Platform.isWindows) { if (Platform.isWindows) {
_coins.remove(Coin.monero); _coins.remove(Coin.monero);
_coins.remove(Coin.wownero); _coins.remove(Coin.wownero);
} else if (Platform.isLinux) {
_coins.remove(Coin.wownero);
} }
searchNodeController = TextEditingController(); searchNodeController = TextEditingController();
@ -250,8 +252,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,107 +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/isar/main_db.dart'; import 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/models/contact.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/models/isar/models/contact_entry.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 {
ContactEntry getContactById(String id) {
ContactEntry turnContactToEntry({required Contact contact}) {
String? emojiChar = contact.emojiChar;
String name = contact.name;
List<String> addresses = [];
bool isFavorite = contact.isFavorite;
String customId = contact.id;
for (ContactAddressEntry contactAddressEntry in contact.addresses) {
String coin = contactAddressEntry.coin.ticker;
String address = contactAddressEntry.address;
String label = contactAddressEntry.label;
String? other = contactAddressEntry.other;
addresses.add("$coin,$address,$label,$other");
}
return ContactEntry(
emojiChar: emojiChar,
name: name,
addresses: addresses,
isFavorite: isFavorite,
customId: customId,
);
}
Contact turnEntryToContact({required ContactEntry contactEntry}) {
String? emojiChar = contactEntry.emojiChar;
String name = contactEntry.name;
List<ContactAddressEntry> addresses = [];
bool isFavorite = contactEntry.isFavorite;
String id = contactEntry.customId;
for (String addressEntry in contactEntry.addresses) {
List<String> addressEntrySplit = addressEntry.split(",");
Coin coin = coinFromTickerCaseInsensitive(addressEntrySplit[0]);
String address = addressEntrySplit[1];
String label = addressEntrySplit[2];
String? other = addressEntrySplit[3];
addresses.add(ContactAddressEntry(
coin: coin,
address: address,
label: label,
other: other,
));
}
return Contact(
emojiChar: emojiChar,
name: name,
addresses: addresses,
isFavorite: isFavorite,
id: id,
);
}
Contact getContactById(String id) {
ContactEntry? contactEntry = MainDB.instance.getContactEntry(id: id); ContactEntry? contactEntry = MainDB.instance.getContactEntry(id: id);
if (contactEntry == null) { if (contactEntry == null) {
return Contact( throw Exception('Contact ID "$id" not found!');
name: "Contact not found",
addresses: [],
isFavorite: false,
);
} else { } else {
return turnEntryToContact(contactEntry: contactEntry); return contactEntry;
} }
} }
List<Contact> get contacts { List<ContactEntry> get contacts => MainDB.instance.getContactEntries();
List<ContactEntry> contactEntries = MainDB.instance.getContactEntries();
List<Contact> contactsList = [];
for (ContactEntry contactEntry in contactEntries) {
contactsList.add(turnEntryToContact(contactEntry: contactEntry));
}
return contactsList;
}
List<Contact>? _addressBookEntries;
List<Contact> get addressBookEntries =>
_addressBookEntries ??= _fetchAddressBookEntries();
// Load address book contact entries
List<Contact> _fetchAddressBookEntries() {
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;
} }
@ -125,33 +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 (await MainDB.instance.isContactEntryExists(id: contact.id)) { if (await MainDB.instance.isContactEntryExists(id: contact.customId)) {
return false; return false;
} else { } else {
await MainDB.instance.putContactEntry(contactEntry: turnContactToEntry(contact: contact)); await MainDB.instance.putContactEntry(contactEntry: contact);
_refreshAddressBookEntries(); notifyListeners();
return true; 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 MainDB.instance.putContactEntry(contactEntry: turnContactToEntry(contact: editedContact)); await MainDB.instance.putContactEntry(contactEntry: editedContact);
_refreshAddressBookEntries(); notifyListeners();
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 MainDB.instance.deleteContactEntry(id: id); await MainDB.instance.deleteContactEntry(id: id);
_refreshAddressBookEntries();
}
void _refreshAddressBookEntries() {
final newAddressBookEntries = _fetchAddressBookEntries();
_addressBookEntries = 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 =
@ -1468,7 +1468,7 @@ class BitcoinWallet extends CoinServiceAPI
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', key: '${_walletId}_mnemonic',
value: bip39.generateMnemonic(strength: 256)); value: bip39.generateMnemonic(strength: 128));
await _secureStore.write(key: '${_walletId}_mnemonicPassphrase', value: ""); await _secureStore.write(key: '${_walletId}_mnemonicPassphrase', value: "");
// Generate and add addresses to relevant arrays // Generate and add addresses to relevant arrays

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) {
@ -1389,7 +1371,7 @@ class BitcoinCashWallet extends CoinServiceAPI
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', key: '${_walletId}_mnemonic',
value: bip39.generateMnemonic(strength: 256)); value: bip39.generateMnemonic(strength: 128));
await _secureStore.write(key: '${_walletId}_mnemonicPassphrase', value: ""); await _secureStore.write(key: '${_walletId}_mnemonicPassphrase', value: "");
// Generate and add addresses to relevant arrays // Generate and add addresses to relevant arrays
@ -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

@ -7,6 +7,7 @@ import 'package:stackwallet/models/paymint/fee_object_model.dart';
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart'; import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart';
import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart'; import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart';
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart'; import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart';
import 'package:stackwallet/services/coins/ecash/ecash_wallet.dart';
import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart'; import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart';
import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'; import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart';
import 'package:stackwallet/services/coins/firo/firo_wallet.dart'; import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
@ -243,6 +244,17 @@ abstract class CoinServiceAPI {
cachedClient: cachedClient, cachedClient: cachedClient,
tracker: tracker, tracker: tracker,
); );
case Coin.eCash:
return ECashWallet(
walletId: walletId,
walletName: walletName,
coin: coin,
secureStore: secureStorageInterface,
client: client,
cachedClient: cachedClient,
tracker: tracker,
);
} }
} }

View file

@ -1318,7 +1318,7 @@ class DogecoinWallet extends CoinServiceAPI
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', key: '${_walletId}_mnemonic',
value: bip39.generateMnemonic(strength: 256)); value: bip39.generateMnemonic(strength: 128));
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase', key: '${_walletId}_mnemonicPassphrase',
value: "", value: "",

File diff suppressed because it is too large Load diff

View file

@ -350,7 +350,7 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
"Attempted to overwrite mnemonic on generate new wallet!"); "Attempted to overwrite mnemonic on generate new wallet!");
} }
final String mnemonic = bip39.generateMnemonic(strength: 256); final String mnemonic = bip39.generateMnemonic(strength: 128);
await _secureStore.write(key: '${_walletId}_mnemonic', value: mnemonic); await _secureStore.write(key: '${_walletId}_mnemonic', value: mnemonic);
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase', key: '${_walletId}_mnemonicPassphrase',

File diff suppressed because it is too large Load diff

View file

@ -1498,7 +1498,7 @@ class LitecoinWallet extends CoinServiceAPI
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', key: '${_walletId}_mnemonic',
value: bip39.generateMnemonic(strength: 256)); value: bip39.generateMnemonic(strength: 128));
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase', key: '${_walletId}_mnemonicPassphrase',
value: "", value: "",

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

@ -1479,7 +1479,7 @@ class NamecoinWallet extends CoinServiceAPI
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', key: '${_walletId}_mnemonic',
value: bip39.generateMnemonic(strength: 256)); value: bip39.generateMnemonic(strength: 128));
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase', key: '${_walletId}_mnemonicPassphrase',
value: "", value: "",

View file

@ -1394,7 +1394,7 @@ class ParticlWallet extends CoinServiceAPI
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', key: '${_walletId}_mnemonic',
value: bip39.generateMnemonic(strength: 256)); value: bip39.generateMnemonic(strength: 128));
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase', key: '${_walletId}_mnemonicPassphrase',
value: "", value: "",

View file

@ -35,9 +35,10 @@ mixin FiroHive {
} }
// mintIndex // mintIndex
int? firoGetMintIndex() { int firoGetMintIndex() {
return DB.instance.get<dynamic>(boxName: _walletId, key: "mintIndex") return DB.instance.get<dynamic>(boxName: _walletId, key: "mintIndex")
as int?; as int? ??
0;
} }
Future<void> firoUpdateMintIndex(int mintIndex) async { Future<void> firoUpdateMintIndex(int mintIndex) async {

View file

@ -89,7 +89,7 @@ class PriceAPI {
final uri = final uri =
Uri.parse("https://api.coingecko.com/api/v3/coins/markets?vs_currency" Uri.parse("https://api.coingecko.com/api/v3/coins/markets?vs_currency"
"=${baseCurrency.toLowerCase()}" "=${baseCurrency.toLowerCase()}"
"&ids=monero,bitcoin,litecoin,epic-cash,zcoin,dogecoin," "&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
"bitcoin-cash,namecoin,wownero,ethereum,particl" "bitcoin-cash,namecoin,wownero,ethereum,particl"
"&order=market_cap_desc&per_page=50&page=1&sparkline=false"); "&order=market_cap_desc&per_page=50&page=1&sparkline=false");

View file

@ -1,38 +1,44 @@
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/models/isar/stack_theme.dart';
import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/themes/theme_providers.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
final coinIconProvider = Provider.family<String, Coin>((ref, coin) { final coinIconProvider = Provider.family<String, Coin>((ref, coin) {
final assets = ref.watch(themeProvider).assets; final assets = ref.watch(themeAssetsProvider);
switch (coin) {
case Coin.bitcoin: if (assets is ThemeAssets) {
case Coin.bitcoinTestNet: switch (coin) {
return assets.bitcoin; case Coin.bitcoin:
case Coin.litecoin: case Coin.bitcoinTestNet:
case Coin.litecoinTestNet: return assets.bitcoin;
return assets.litecoin; case Coin.litecoin:
case Coin.bitcoincash: case Coin.litecoinTestNet:
case Coin.bitcoincashTestnet: return assets.litecoin;
return assets.bitcoincash; case Coin.bitcoincash:
case Coin.dogecoin: case Coin.bitcoincashTestnet:
case Coin.dogecoinTestNet: return assets.bitcoincash;
return assets.dogecoin; case Coin.dogecoin:
case Coin.epicCash: case Coin.dogecoinTestNet:
return assets.epicCash; return assets.dogecoin;
case Coin.firo: case Coin.eCash:
case Coin.firoTestNet: return assets.bitcoin;
return assets.firo; case Coin.epicCash:
case Coin.monero: return assets.epicCash;
return assets.monero; case Coin.firo:
case Coin.wownero: case Coin.firoTestNet:
return assets.wownero; return assets.firo;
case Coin.namecoin: case Coin.monero:
return assets.namecoin; return assets.monero;
case Coin.particl: case Coin.wownero:
return assets.particl; return assets.wownero;
case Coin.ethereum: case Coin.namecoin:
return assets.ethereum; return assets.namecoin;
case Coin.nano: case Coin.particl:
return assets.nano; return assets.particl;
case Coin.ethereum:
return assets.ethereum;
}
} else {
return (assets as ThemeAssetsV2).coinIcons[coin.mainNetVersion]!;
} }
}); });

View file

@ -1,77 +1,92 @@
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/models/isar/stack_theme.dart';
import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/themes/theme_providers.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
final coinImageProvider = Provider.family<String, Coin>((ref, coin) { final coinImageProvider = Provider.family<String, Coin>((ref, coin) {
final assets = ref.watch(themeProvider).assets; final assets = ref.watch(themeAssetsProvider);
switch (coin) {
case Coin.bitcoin: if (assets is ThemeAssets) {
return assets.bitcoinImage; switch (coin) {
case Coin.litecoin: case Coin.bitcoin:
case Coin.litecoinTestNet: return assets.bitcoinImage;
return assets.litecoinImage; case Coin.litecoin:
case Coin.bitcoincash: case Coin.litecoinTestNet:
return assets.bitcoincashImage; return assets.litecoinImage;
case Coin.dogecoin: case Coin.bitcoincash:
return assets.dogecoinImage; return assets.bitcoincashImage;
case Coin.epicCash: case Coin.dogecoin:
return assets.epicCashImage; return assets.dogecoinImage;
case Coin.firo: case Coin.eCash:
return assets.firoImage; return assets.bitcoinImage;
case Coin.monero: case Coin.epicCash:
return assets.moneroImage; return assets.epicCashImage;
case Coin.wownero: case Coin.firo:
return assets.wowneroImage; return assets.firoImage;
case Coin.namecoin: case Coin.monero:
return assets.namecoinImage; return assets.moneroImage;
case Coin.particl: case Coin.wownero:
return assets.particlImage; return assets.wowneroImage;
case Coin.bitcoinTestNet: case Coin.namecoin:
return assets.bitcoinImage; return assets.namecoinImage;
case Coin.bitcoincashTestnet: case Coin.particl:
return assets.bitcoincashImage; return assets.particlImage;
case Coin.firoTestNet: case Coin.bitcoinTestNet:
return assets.firoImage; return assets.bitcoinImage;
case Coin.dogecoinTestNet: case Coin.bitcoincashTestnet:
return assets.dogecoinImage; return assets.bitcoincashImage;
case Coin.ethereum: case Coin.firoTestNet:
return assets.ethereumImage; return assets.firoImage;
case Coin.nano: case Coin.dogecoinTestNet:
return assets.nano; return assets.dogecoinImage;
case Coin.ethereum:
return assets.ethereumImage;
}
} else {
return (assets as ThemeAssetsV2).coinImages[coin.mainNetVersion]!;
} }
}); });
final coinImageSecondaryProvider = Provider.family<String, Coin>((ref, coin) { final coinImageSecondaryProvider = Provider.family<String, Coin>((ref, coin) {
final assets = ref.watch(themeProvider).assets; final assets = ref.watch(themeAssetsProvider);
switch (coin) {
case Coin.bitcoin: if (assets is ThemeAssets) {
case Coin.bitcoinTestNet: switch (coin) {
return assets.bitcoinImageSecondary; case Coin.bitcoin:
case Coin.litecoin: return assets.bitcoinImageSecondary;
case Coin.litecoinTestNet: case Coin.litecoin:
return assets.litecoinImageSecondary; case Coin.litecoinTestNet:
case Coin.bitcoincash: return assets.litecoinImageSecondary;
case Coin.bitcoincashTestnet: case Coin.bitcoincash:
return assets.bitcoincashImageSecondary; return assets.bitcoincashImageSecondary;
case Coin.dogecoin: case Coin.dogecoin:
case Coin.dogecoinTestNet: return assets.dogecoinImageSecondary;
return assets.dogecoinImageSecondary; case Coin.eCash:
case Coin.epicCash: return assets.bitcoinImageSecondary;
return assets.epicCashImageSecondary; case Coin.epicCash:
case Coin.firo: return assets.epicCashImageSecondary;
case Coin.firoTestNet: case Coin.firo:
return assets.firoImageSecondary; return assets.firoImageSecondary;
case Coin.monero: case Coin.monero:
return assets.moneroImageSecondary; return assets.moneroImageSecondary;
case Coin.wownero: case Coin.wownero:
return assets.wowneroImageSecondary; return assets.wowneroImageSecondary;
case Coin.namecoin: case Coin.namecoin:
return assets.namecoinImageSecondary; return assets.namecoinImageSecondary;
case Coin.particl: case Coin.particl:
return assets.particlImageSecondary; return assets.particlImageSecondary;
case Coin.ethereum: case Coin.bitcoinTestNet:
return assets.ethereumImageSecondary; return assets.bitcoinImageSecondary;
case Coin.nano: case Coin.bitcoincashTestnet:
return assets.nano; return assets.bitcoincashImageSecondary;
case Coin.firoTestNet:
return assets.firoImageSecondary;
case Coin.dogecoinTestNet:
return assets.dogecoinImageSecondary;
case Coin.ethereum:
return assets.ethereumImageSecondary;
}
} else {
return (assets as ThemeAssetsV2).coinSecondaryImages[coin.mainNetVersion]!;
} }
}); });

View file

@ -12,6 +12,7 @@ class CoinThemeColorDefault {
Color get firo => const Color(0xFFFF897A); Color get firo => const Color(0xFFFF897A);
Color get dogecoin => const Color(0xFFFFE079); Color get dogecoin => const Color(0xFFFFE079);
Color get epicCash => const Color(0xFFC5C7CB); Color get epicCash => const Color(0xFFC5C7CB);
Color get eCash => const Color(0xFFC5C7CB);
Color get ethereum => const Color(0xFFA7ADE9); Color get ethereum => const Color(0xFFA7ADE9);
Color get monero => const Color(0xFFFF9E6B); Color get monero => const Color(0xFFFF9E6B);
Color get namecoin => const Color(0xFF91B1E1); Color get namecoin => const Color(0xFF91B1E1);
@ -33,6 +34,8 @@ class CoinThemeColorDefault {
case Coin.dogecoin: case Coin.dogecoin:
case Coin.dogecoinTestNet: case Coin.dogecoinTestNet:
return dogecoin; return dogecoin;
case Coin.eCash:
return eCash;
case Coin.epicCash: case Coin.epicCash:
return epicCash; return epicCash;
case Coin.ethereum: case Coin.ethereum:

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,
@ -1671,6 +1682,8 @@ class StackColors extends ThemeExtension<StackColors> {
return _coin.dogecoin; return _coin.dogecoin;
case Coin.epicCash: case Coin.epicCash:
return _coin.epicCash; return _coin.epicCash;
case Coin.eCash:
return _coin.eCash;
case Coin.ethereum: case Coin.ethereum:
return _coin.ethereum; return _coin.ethereum;
case Coin.firo: case Coin.firo:

View file

@ -20,3 +20,11 @@ final themeProvider = StateProvider<StackTheme>(
), ),
), ),
); );
final themeAssetsProvider = StateProvider<IThemeAssets>(
(ref) => ref.watch(
themeProvider.select(
(value) => value.assets,
),
),
);

View file

@ -1,9 +1,9 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data';
import 'package:archive/archive_io.dart'; import 'package:archive/archive_io.dart';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
@ -17,6 +17,7 @@ final pThemeService = Provider<ThemeService>((ref) {
}); });
class ThemeService { class ThemeService {
static const _currentDefaultThemeVersion = 2;
ThemeService._(); ThemeService._();
static ThemeService? _instance; static ThemeService? _instance;
static ThemeService get instance => _instance ??= ThemeService._(); static ThemeService get instance => _instance ??= ThemeService._();
@ -92,6 +93,70 @@ class ThemeService {
} }
} }
Future<void> checkDefaultThemesOnStartup() async {
// install default themes
if (!(await ThemeService.instance.verifyInstalled(themeId: "light"))) {
Logging.instance.log(
"Installing default light theme...",
level: LogLevel.Info,
);
final lightZip = await rootBundle.load("assets/default_themes/light.zip");
await ThemeService.instance
.install(themeArchiveData: lightZip.buffer.asUint8List());
Logging.instance.log(
"Installing default light theme... finished",
level: LogLevel.Info,
);
} else {
// check installed version
final theme = ThemeService.instance.getTheme(themeId: "light");
if ((theme?.version ?? 1) < _currentDefaultThemeVersion) {
Logging.instance.log(
"Updating default light theme...",
level: LogLevel.Info,
);
final lightZip =
await rootBundle.load("assets/default_themes/light.zip");
await ThemeService.instance
.install(themeArchiveData: lightZip.buffer.asUint8List());
Logging.instance.log(
"Updating default light theme... finished",
level: LogLevel.Info,
);
}
}
if (!(await ThemeService.instance.verifyInstalled(themeId: "dark"))) {
Logging.instance.log(
"Installing default dark theme... ",
level: LogLevel.Info,
);
final darkZip = await rootBundle.load("assets/default_themes/dark.zip");
await ThemeService.instance
.install(themeArchiveData: darkZip.buffer.asUint8List());
Logging.instance.log(
"Installing default dark theme... finished",
level: LogLevel.Info,
);
} else {
// check installed version
final theme = ThemeService.instance.getTheme(themeId: "dark");
if ((theme?.version ?? 1) < _currentDefaultThemeVersion) {
Logging.instance.log(
"Updating default dark theme...",
level: LogLevel.Info,
);
final darkZip = await rootBundle.load("assets/default_themes/dark.zip");
await ThemeService.instance
.install(themeArchiveData: darkZip.buffer.asUint8List());
Logging.instance.log(
"Updating default dark theme... finished",
level: LogLevel.Info,
);
}
}
}
// TODO more thorough check/verification of theme // TODO more thorough check/verification of theme
Future<bool> verifyInstalled({required String themeId}) async { Future<bool> verifyInstalled({required String themeId}) async {
final dbHasTheme = final dbHasTheme =
@ -175,6 +240,7 @@ class ThemeService {
class StackThemeMetaData { class StackThemeMetaData {
final String name; final String name;
final String id; final String id;
final int version;
final String sha256; final String sha256;
final String size; final String size;
final String previewImageUrl; final String previewImageUrl;
@ -182,6 +248,7 @@ class StackThemeMetaData {
StackThemeMetaData({ StackThemeMetaData({
required this.name, required this.name,
required this.id, required this.id,
required this.version,
required this.sha256, required this.sha256,
required this.size, required this.size,
required this.previewImageUrl, required this.previewImageUrl,
@ -192,6 +259,7 @@ class StackThemeMetaData {
return StackThemeMetaData( return StackThemeMetaData(
name: map["name"] as String, name: map["name"] as String,
id: map["id"] as String, id: map["id"] as String,
version: map["version"] as int? ?? 1,
sha256: map["sha256"] as String, sha256: map["sha256"] as String,
size: map["size"] as String, size: map["size"] as String,
previewImageUrl: map["previewImageUrl"] as String, previewImageUrl: map["previewImageUrl"] as String,
@ -210,6 +278,7 @@ class StackThemeMetaData {
return "$runtimeType(" return "$runtimeType("
"name: $name, " "name: $name, "
"id: $id, " "id: $id, "
"version: $version, "
"sha256: $sha256, " "sha256: $sha256, "
"size: $size, " "size: $size, "
"previewImageUrl: $previewImageUrl" "previewImageUrl: $previewImageUrl"

View file

@ -6,6 +6,7 @@ import 'package:flutter_libepiccash/epic_cash.dart';
import 'package:nanodart/nanodart.dart'; import 'package:nanodart/nanodart.dart';
import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart'; import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart';
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart'; import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart';
import 'package:stackwallet/services/coins/ecash/ecash_wallet.dart';
import 'package:stackwallet/services/coins/firo/firo_wallet.dart'; import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
import 'package:stackwallet/services/coins/litecoin/litecoin_wallet.dart'; import 'package:stackwallet/services/coins/litecoin/litecoin_wallet.dart';
import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart'; import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart';
@ -62,6 +63,8 @@ class AddressUtils {
return true; //TODO - validate ETH address return true; //TODO - validate ETH address
case Coin.firo: case Coin.firo:
return Address.validateAddress(address, firoNetwork); return Address.validateAddress(address, firoNetwork);
case Coin.eCash:
return Address.validateAddress(address, eCashNetwork);
case Coin.monero: case Coin.monero:
return RegExp("[a-zA-Z0-9]{95}").hasMatch(address) || return RegExp("[a-zA-Z0-9]{95}").hasMatch(address) ||
RegExp("[a-zA-Z0-9]{106}").hasMatch(address); RegExp("[a-zA-Z0-9]{106}").hasMatch(address);

View file

@ -165,6 +165,7 @@ class _SVG {
String get questionMessage => "assets/svg/message-question.svg"; String get questionMessage => "assets/svg/message-question.svg";
String get envelope => "assets/svg/envelope.svg"; String get envelope => "assets/svg/envelope.svg";
String get share => "assets/svg/share-2.svg"; String get share => "assets/svg/share-2.svg";
String get recycle => "assets/svg/anonymize.svg";
String get anonymize => "assets/svg/tx-icon-anonymize.svg"; String get anonymize => "assets/svg/tx-icon-anonymize.svg";
String get anonymizePending => "assets/svg/tx-icon-anonymize-pending.svg"; String get anonymizePending => "assets/svg/tx-icon-anonymize-pending.svg";
String get anonymizeFailed => "assets/svg/tx-icon-anonymize-failed.svg"; String get anonymizeFailed => "assets/svg/tx-icon-anonymize-failed.svg";
@ -193,7 +194,7 @@ class _SVG {
String get exchange3 => "assets/svg/exchange-3.svg"; String get exchange3 => "assets/svg/exchange-3.svg";
String get messageQuestion => "assets/svg/message-question-1.svg"; String get messageQuestion => "assets/svg/message-question-1.svg";
String get list => "assets/svg/list-ul.svg"; String get list => "assets/svg/list-ul.svg";
String get unclaimedPaynym => "assets/svg/unclaimed.png"; String get unclaimedPaynym => "assets/svg/unclaimed.svg";
String get trocadorRatingA => "assets/svg/trocador_rating_a.svg"; String get trocadorRatingA => "assets/svg/trocador_rating_a.svg";
String get trocadorRatingB => "assets/svg/trocador_rating_b.svg"; String get trocadorRatingB => "assets/svg/trocador_rating_b.svg";

View file

@ -17,6 +17,8 @@ Uri getDefaultBlockExplorerUrlFor({
return Uri.parse("https://mempool.space/testnet/tx/$txid"); return Uri.parse("https://mempool.space/testnet/tx/$txid");
case Coin.dogecoin: case Coin.dogecoin:
return Uri.parse("https://chain.so/tx/DOGE/$txid"); return Uri.parse("https://chain.so/tx/DOGE/$txid");
case Coin.eCash:
return Uri.parse("https://explorer.bitcoinabc.org/tx/$txid");
case Coin.dogecoinTestNet: case Coin.dogecoinTestNet:
return Uri.parse("https://chain.so/tx/DOGETEST/$txid"); return Uri.parse("https://chain.so/tx/DOGETEST/$txid");
case Coin.epicCash: case Coin.epicCash:

View file

@ -25,6 +25,7 @@ abstract class Constants {
// static bool enableBuy = enableExchange; // static bool enableBuy = enableExchange;
// // true; // true for development, // // true; // true for development,
static const BigInt _satsPerCoinECash = BigInt.from(100);
static final BigInt _satsPerCoinEthereum = BigInt.from(1000000000000000000); static final BigInt _satsPerCoinEthereum = BigInt.from(1000000000000000000);
static final BigInt _satsPerCoinMonero = BigInt.from(1000000000000); static final BigInt _satsPerCoinMonero = BigInt.from(1000000000000);
static final BigInt _satsPerCoinWownero = BigInt.from(100000000000); static final BigInt _satsPerCoinWownero = BigInt.from(100000000000);
@ -35,6 +36,7 @@ abstract class Constants {
static const int _decimalPlacesWownero = 11; static const int _decimalPlacesWownero = 11;
static const int _decimalPlacesMonero = 12; static const int _decimalPlacesMonero = 12;
static const int _decimalPlacesEthereum = 18; static const int _decimalPlacesEthereum = 18;
static const int _decimalPlacesECash = 2;
static const int notificationsMax = 0xFFFFFFFF; static const int notificationsMax = 0xFFFFFFFF;
static const Duration networkAliveTimerDuration = Duration(seconds: 10); static const Duration networkAliveTimerDuration = Duration(seconds: 10);
@ -44,7 +46,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;
@ -76,6 +78,9 @@ abstract class Constants {
case Coin.ethereum: case Coin.ethereum:
return _satsPerCoinEthereum; return _satsPerCoinEthereum;
case Coin.eCash:
return _satsPerCoinECash;
} }
} }
@ -107,6 +112,9 @@ abstract class Constants {
case Coin.ethereum: case Coin.ethereum:
return _decimalPlacesEthereum; return _decimalPlacesEthereum;
case Coin.eCash:
return _decimalPlacesECash;
} }
} }
@ -123,6 +131,7 @@ abstract class Constants {
case Coin.bitcoinTestNet: case Coin.bitcoinTestNet:
case Coin.dogecoinTestNet: case Coin.dogecoinTestNet:
case Coin.firoTestNet: case Coin.firoTestNet:
case Coin.eCash:
case Coin.epicCash: case Coin.epicCash:
case Coin.ethereum: case Coin.ethereum:
case Coin.namecoin: case Coin.namecoin:
@ -146,10 +155,9 @@ abstract class Constants {
switch (coin) { switch (coin) {
case Coin.bitcoin: case Coin.bitcoin:
case Coin.bitcoinTestNet: case Coin.bitcoinTestNet:
return 600;
case Coin.bitcoincash: case Coin.bitcoincash:
case Coin.bitcoincashTestnet: case Coin.bitcoincashTestnet:
case Coin.eCash:
return 600; return 600;
case Coin.dogecoin: case Coin.dogecoin:
@ -187,7 +195,7 @@ abstract class Constants {
} }
} }
static const int seedPhraseWordCountBip39 = 24; static const int seedPhraseWordCountBip39 = 12;
static const int seedPhraseWordCountMonero = 25; static const int seedPhraseWordCountMonero = 25;
static const Map<int, String> monthMapShort = { static const Map<int, String> monthMapShort = {

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,6 +1,5 @@
import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/models/node_model.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
// import 'package:web3dart/browser.dart';
abstract class DefaultNodes { abstract class DefaultNodes {
static const String defaultNodeIdPrefix = "default_"; static const String defaultNodeIdPrefix = "default_";
@ -13,6 +12,7 @@ abstract class DefaultNodes {
dogecoin, dogecoin,
firo, firo,
monero, monero,
eCash,
epicCash, epicCash,
ethereum, ethereum,
bitcoincash, bitcoincash,
@ -231,6 +231,18 @@ abstract class DefaultNodes {
isDown: false, isDown: false,
); );
static NodeModel get eCash => NodeModel(
host: "electrum.bitcoinabc.org",
port: 50002,
name: defaultName,
id: _nodeId(Coin.eCash),
useSSL: true,
enabled: true,
coinName: Coin.eCash.name,
isFailover: true,
isDown: false,
);
static NodeModel getNodeFor(Coin coin) { static NodeModel getNodeFor(Coin coin) {
switch (coin) { switch (coin) {
case Coin.bitcoin: case Coin.bitcoin:
@ -245,6 +257,9 @@ abstract class DefaultNodes {
case Coin.dogecoin: case Coin.dogecoin:
return dogecoin; return dogecoin;
case Coin.eCash:
return eCash;
case Coin.epicCash: case Coin.epicCash:
return epicCash; return epicCash;

View file

@ -3,6 +3,7 @@ import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart'
as bch; as bch;
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart' import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart'
as doge; as doge;
import 'package:stackwallet/services/coins/ecash/ecash_wallet.dart' as ecash;
import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart' import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart'
as epic; as epic;
import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart' import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'
@ -23,6 +24,7 @@ enum Coin {
bitcoin, bitcoin,
bitcoincash, bitcoincash,
dogecoin, dogecoin,
eCash,
epicCash, epicCash,
ethereum, ethereum,
firo, firo,
@ -61,6 +63,8 @@ extension CoinExt on Coin {
return "Dogecoin"; return "Dogecoin";
case Coin.epicCash: case Coin.epicCash:
return "Epic Cash"; return "Epic Cash";
case Coin.eCash:
return "E-Cash";
case Coin.ethereum: case Coin.ethereum:
return "Ethereum"; return "Ethereum";
case Coin.firo: case Coin.firo:
@ -102,6 +106,8 @@ extension CoinExt on Coin {
return "EPIC"; return "EPIC";
case Coin.ethereum: case Coin.ethereum:
return "ETH"; return "ETH";
case Coin.eCash:
return "XEC";
case Coin.firo: case Coin.firo:
return "FIRO"; return "FIRO";
case Coin.monero: case Coin.monero:
@ -142,6 +148,8 @@ extension CoinExt on Coin {
return "epic"; return "epic";
case Coin.ethereum: case Coin.ethereum:
return "ethereum"; return "ethereum";
case Coin.eCash:
return "ecash";
case Coin.firo: case Coin.firo:
return "firo"; return "firo";
case Coin.monero: case Coin.monero:
@ -181,6 +189,7 @@ extension CoinExt on Coin {
case Coin.bitcoincashTestnet: case Coin.bitcoincashTestnet:
case Coin.firoTestNet: case Coin.firoTestNet:
case Coin.dogecoinTestNet: case Coin.dogecoinTestNet:
case Coin.eCash:
return true; return true;
case Coin.epicCash: case Coin.epicCash:
@ -204,6 +213,7 @@ extension CoinExt on Coin {
case Coin.firo: case Coin.firo:
case Coin.namecoin: case Coin.namecoin:
case Coin.particl: case Coin.particl:
case Coin.eCash:
case Coin.epicCash: case Coin.epicCash:
case Coin.monero: case Coin.monero:
case Coin.wownero: case Coin.wownero:
@ -231,6 +241,7 @@ extension CoinExt on Coin {
case Coin.monero: case Coin.monero:
case Coin.wownero: case Coin.wownero:
case Coin.nano: case Coin.nano:
case Coin.eCash:
return false; return false;
case Coin.dogecoinTestNet: case Coin.dogecoinTestNet:
@ -256,6 +267,7 @@ extension CoinExt on Coin {
case Coin.monero: case Coin.monero:
case Coin.wownero: case Coin.wownero:
case Coin.nano: case Coin.nano:
case Coin.eCash:
return this; return this;
case Coin.dogecoinTestNet: case Coin.dogecoinTestNet:
@ -300,6 +312,9 @@ extension CoinExt on Coin {
case Coin.epicCash: case Coin.epicCash:
return epic.MINIMUM_CONFIRMATIONS; return epic.MINIMUM_CONFIRMATIONS;
case Coin.eCash:
return ecash.MINIMUM_CONFIRMATIONS;
case Coin.ethereum: case Coin.ethereum:
return eth.MINIMUM_CONFIRMATIONS; return eth.MINIMUM_CONFIRMATIONS;
@ -354,6 +369,11 @@ Coin coinFromPrettyName(String name) {
case "firo": case "firo":
return Coin.firo; return Coin.firo;
case "E-Cash":
case "ecash":
case "eCash":
return Coin.eCash;
case "Monero": case "Monero":
case "monero": case "monero":
return Coin.monero; return Coin.monero;
@ -423,6 +443,8 @@ Coin coinFromTickerCaseInsensitive(String ticker) {
return Coin.dogecoin; return Coin.dogecoin;
case "epic": case "epic":
return Coin.epicCash; return Coin.epicCash;
case "xec":
return Coin.eCash;
case "eth": case "eth":
return Coin.ethereum; return Coin.ethereum;
case "firo": case "firo":

View file

@ -6,6 +6,7 @@ enum DerivePathType {
bip49, bip49,
bip84, bip84,
eth, eth,
eCash44,
} }
extension DerivePathTypeExt on DerivePathType { extension DerivePathTypeExt on DerivePathType {
@ -27,6 +28,9 @@ extension DerivePathTypeExt on DerivePathType {
case Coin.particl: case Coin.particl:
return DerivePathType.bip84; return DerivePathType.bip84;
case Coin.eCash:
return DerivePathType.eCash44;
case Coin.ethereum: // TODO: do we need something here? case Coin.ethereum: // TODO: do we need something here?
return DerivePathType.eth; return DerivePathType.eth;

View file

@ -1,3 +1,5 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
@ -50,4 +52,15 @@ abstract class Util {
} }
return MaterialColor(color.value, swatch); return MaterialColor(color.value, swatch);
} }
static void printJson(dynamic json) {
if (json is Map || json is List) {
final spaces = ' ' * 4;
final encoder = JsonEncoder.withIndent(spaces);
final pretty = encoder.convert(json);
log(pretty);
} else {
log(dynamic.toString());
}
}
} }

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

@ -24,7 +24,7 @@ class TradeCard extends ConsumerWidget {
final Trade trade; final Trade trade;
final VoidCallback onTap; final VoidCallback onTap;
String _fetchIconAssetForStatus(String statusString, ThemeAssets assets) { String _fetchIconAssetForStatus(String statusString, IThemeAssets assets) {
ChangeNowTransactionStatus? status; ChangeNowTransactionStatus? status;
try { try {
if (statusString.toLowerCase().startsWith("waiting")) { if (statusString.toLowerCase().startsWith("waiting")) {
@ -89,11 +89,7 @@ class TradeCard extends ConsumerWidget {
File( File(
_fetchIconAssetForStatus( _fetchIconAssetForStatus(
trade.status, trade.status,
ref.watch( ref.watch(themeAssetsProvider),
themeProvider.select(
(value) => value.assets,
),
),
), ),
), ),
width: 32, width: 32,

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(

Some files were not shown because too many files have changed in this diff Show more