WIP refactor exchange to use isar as cache instead of in memory using riverpod

This commit is contained in:
julian 2023-02-05 14:32:39 -06:00
parent 585a684ecc
commit 1455808d7a
56 changed files with 11786 additions and 4136 deletions

View file

@ -1,4 +1,3 @@
import 'package:flutter/foundation.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/exceptions/main_db/main_db_exception.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
@ -30,7 +29,8 @@ class MainDB {
AddressSchema,
],
directory: (await StackFileSystem.applicationIsarDirectory()).path,
inspector: kDebugMode,
// inspector: kDebugMode,
inspector: false,
name: "wallet_data",
);
return true;

View file

@ -43,7 +43,6 @@ import 'package:stackwallet/providers/ui/color_theme_provider.dart';
import 'package:stackwallet/route_generator.dart';
// import 'package:stackwallet/services/buy/buy_data_loading_service.dart';
import 'package:stackwallet/services/debug_service.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
import 'package:stackwallet/services/locale_service.dart';
import 'package:stackwallet/services/node_service.dart';
@ -291,11 +290,16 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
// TODO: this should probably run unawaited. Keep commented out for now as proper community nodes ui hasn't been implemented yet
// unawaited(_nodeService.updateCommunityNodes());
print("================================================");
print("${ref.read(prefsChangeNotifierProvider).externalCalls}");
print("${await ref.read(prefsChangeNotifierProvider).isExternalCallsSet()}");
print("================================================");
// run without awaiting
if (ref.read(prefsChangeNotifierProvider).externalCalls &&
await ref.read(prefsChangeNotifierProvider).isExternalCallsSet()) {
if (Constants.enableExchange) {
unawaited(ExchangeDataLoadingService().loadAll(ref));
await ExchangeDataLoadingService.instance.init();
unawaited(ExchangeDataLoadingService.instance.loadAll());
}
// if (Constants.enableBuy) {
// unawaited(BuyDataLoadingService().loadAll(ref));
@ -328,7 +332,6 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
@override
void initState() {
ref.read(exchangeFormStateProvider).exchange = ChangeNowExchange();
final colorScheme = DB.instance
.get<dynamic>(boxName: DB.boxNameTheme, key: "colorScheme") as String?;

View file

@ -1,6 +1,6 @@
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart';
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
class CNAvailableCurrencies {
final List<Currency> currencies = [];

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,30 @@
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
class MBAvailableCurrencies {
final List<Currency> currencies = [];
// final List<Currency> fixedRateCurrencies = [];
final List<Pair> pairs = [];
// final List<Pair> fixedRatePairs = [];
// void updateFloatingCurrencies(List<Currency> newCurrencies) {
// floatingRateCurrencies.clear();
// floatingRateCurrencies.addAll(newCurrencies);
// }
void updateCurrencies(List<Currency> newCurrencies) {
currencies.clear();
currencies.addAll(newCurrencies);
}
// void updateFloatingPairs(List<Pair> newPairs) {
// floatingRatePairs.clear();
// floatingRatePairs.addAll(newPairs);
// }
void updatePairs(List<Pair> newPairs) {
pairs.clear();
pairs.addAll(newPairs);
}
}

View file

@ -1,5 +1,5 @@
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
class SPAvailableCurrencies {
final List<Currency> floatingRateCurrencies = [];

View file

@ -1,5 +1,20 @@
import 'package:isar/isar.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
part 'currency.g.dart';
@Collection(accessor: "currencies")
class Currency {
Id? id;
@Index()
final String exchangeName;
/// Currency ticker
@Index(composite: [
CompositeIndex("exchangeName"),
CompositeIndex("name"),
])
final String ticker;
/// Currency name
@ -11,57 +26,62 @@ class Currency {
/// Currency logo url
final String image;
/// Indicates if a currency has an Extra ID
final bool hasExternalId;
/// external id if it exists
final String? externalId;
/// Indicates if a currency is a fiat currency (EUR, USD)
final bool isFiat;
/// Indicates if a currency is popular
final bool featured;
/// Indicates if a currency is stable
final bool isStable;
/// Indicates if a currency is available on a fixed-rate flow
@Index()
final bool supportsFixedRate;
/// Indicates if a currency is available on a fixed-rate flow
final bool supportsFixedRate;
@Index()
final bool supportsEstimatedRate;
/// (Optional - based on api call) Indicates whether the pair is
/// currently supported by change now
final bool? isAvailable;
@Index()
final bool isStackCoin;
Currency({
required this.exchangeName,
required this.ticker,
required this.name,
required this.network,
required this.image,
required this.hasExternalId,
this.externalId,
required this.isFiat,
required this.featured,
required this.isStable,
required this.supportsFixedRate,
required this.supportsEstimatedRate,
this.isAvailable,
required this.isStackCoin,
});
factory Currency.fromJson(Map<String, dynamic> json) {
factory Currency.fromJson(
Map<String, dynamic> json, {
required String exchangeName,
}) {
try {
final ticker = (json["ticker"] as String).toUpperCase();
return Currency(
ticker: json["ticker"] as String,
exchangeName: exchangeName,
ticker: ticker,
name: json["name"] as String,
network: json["network"] as String? ?? "",
image: json["image"] as String,
hasExternalId: json["hasExternalId"] as bool,
externalId: json["externalId"] as String?,
isFiat: json["isFiat"] as bool,
featured: json["featured"] as bool,
isStable: json["isStable"] as bool,
supportsFixedRate: json["supportsFixedRate"] as bool,
supportsEstimatedRate: json["supportsEstimatedRate"] as bool,
isAvailable: json["isAvailable"] as bool?,
);
isStackCoin:
json["isStackCoin"] as bool? ?? Currency.checkIsStackCoin(ticker),
)..id = json["id"] as int?;
} catch (e) {
rethrow;
}
@ -69,55 +89,64 @@ class Currency {
Map<String, dynamic> toJson() {
final map = {
"id": id,
"exchangeName": exchangeName,
"ticker": ticker,
"name": name,
"network": network,
"image": image,
"hasExternalId": hasExternalId,
"externalId": externalId,
"isFiat": isFiat,
"featured": featured,
"isStable": isStable,
"supportsFixedRate": supportsFixedRate,
"supportsEstimatedRate": supportsEstimatedRate,
"isAvailable": isAvailable,
"isStackCoin": isStackCoin,
};
if (isAvailable != null) {
map["isAvailable"] = isAvailable!;
}
return map;
}
Currency copyWith({
Id? id,
String? exchangeName,
String? ticker,
String? name,
String? network,
String? image,
bool? hasExternalId,
String? externalId,
bool? isFiat,
bool? featured,
bool? isStable,
bool? supportsFixedRate,
bool? supportsEstimatedRate,
bool? isAvailable,
bool? isStackCoin,
}) {
return Currency(
exchangeName: exchangeName ?? this.exchangeName,
ticker: ticker ?? this.ticker,
name: name ?? this.name,
network: network ?? this.network,
image: image ?? this.image,
hasExternalId: hasExternalId ?? this.hasExternalId,
externalId: externalId ?? this.externalId,
isFiat: isFiat ?? this.isFiat,
featured: featured ?? this.featured,
isStable: isStable ?? this.isStable,
supportsFixedRate: supportsFixedRate ?? this.supportsFixedRate,
supportsEstimatedRate:
supportsEstimatedRate ?? this.supportsEstimatedRate,
isAvailable: isAvailable ?? this.isAvailable,
);
isStackCoin: isStackCoin ?? this.isStackCoin,
)..id = id ?? this.id;
}
@override
String toString() {
return "Currency: ${toJson()}";
}
static bool checkIsStackCoin(String ticker) {
try {
coinFromTickerCaseInsensitive(ticker);
return true;
} catch (_) {
return false;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,19 @@
import 'dart:ui';
import 'package:isar/isar.dart';
import 'package:stackwallet/utilities/logger.dart';
part 'pair.g.dart';
@collection
class Pair {
Id? id;
@Index()
final String exchangeName;
@Index(composite: [
CompositeIndex("exchangeName"),
CompositeIndex("to"),
])
final String from;
final String fromNetwork;
@ -13,6 +24,7 @@ class Pair {
final bool floatingRate;
Pair({
required this.exchangeName,
required this.from,
required this.fromNetwork,
required this.to,
@ -21,16 +33,20 @@ class Pair {
required this.floatingRate,
});
factory Pair.fromMap(Map<String, dynamic> map) {
factory Pair.fromMap(
Map<String, dynamic> map, {
required String exchangeName,
}) {
try {
return Pair(
exchangeName: exchangeName,
from: map["from"] as String,
fromNetwork: map["fromNetwork"] as String,
to: map["to"] as String,
toNetwork: map["toNetwork"] as String,
fixedRate: map["fixedRate"] as bool,
floatingRate: map["floatingRate"] as bool,
);
)..id = map["id"] as int?;
} catch (e, s) {
Logging.instance.log("Pair.fromMap(): $e\n$s", level: LogLevel.Error);
rethrow;
@ -39,6 +55,8 @@ class Pair {
Map<String, dynamic> toMap() {
return {
"id": id,
"exchangeName": exchangeName,
"from": from,
"fromNetwork": fromNetwork,
"to": to,
@ -51,6 +69,7 @@ class Pair {
@override
bool operator ==(other) =>
other is Pair &&
exchangeName == other.exchangeName &&
from == other.from &&
fromNetwork == other.fromNetwork &&
to == other.to &&
@ -59,7 +78,9 @@ class Pair {
floatingRate == other.floatingRate;
@override
int get hashCode => hashValues(
int get hashCode => Object.hash(
id,
exchangeName,
from,
fromNetwork,
to,

File diff suppressed because it is too large Load diff

View file

@ -52,23 +52,28 @@ const UTXOSchema = CollectionSchema(
name: r'name',
type: IsarType.string,
),
r'txid': PropertySchema(
r'otherData': PropertySchema(
id: 7,
name: r'otherData',
type: IsarType.string,
),
r'txid': PropertySchema(
id: 8,
name: r'txid',
type: IsarType.string,
),
r'value': PropertySchema(
id: 8,
id: 9,
name: r'value',
type: IsarType.long,
),
r'vout': PropertySchema(
id: 9,
id: 10,
name: r'vout',
type: IsarType.long,
),
r'walletId': PropertySchema(
id: 10,
id: 11,
name: r'walletId',
type: IsarType.string,
)
@ -151,6 +156,12 @@ int _uTXOEstimateSize(
}
}
bytesCount += 3 + object.name.length * 3;
{
final value = object.otherData;
if (value != null) {
bytesCount += 3 + value.length * 3;
}
}
bytesCount += 3 + object.txid.length * 3;
bytesCount += 3 + object.walletId.length * 3;
return bytesCount;
@ -169,10 +180,11 @@ void _uTXOSerialize(
writer.writeBool(offsets[4], object.isBlocked);
writer.writeBool(offsets[5], object.isCoinbase);
writer.writeString(offsets[6], object.name);
writer.writeString(offsets[7], object.txid);
writer.writeLong(offsets[8], object.value);
writer.writeLong(offsets[9], object.vout);
writer.writeString(offsets[10], object.walletId);
writer.writeString(offsets[7], object.otherData);
writer.writeString(offsets[8], object.txid);
writer.writeLong(offsets[9], object.value);
writer.writeLong(offsets[10], object.vout);
writer.writeString(offsets[11], object.walletId);
}
UTXO _uTXODeserialize(
@ -189,10 +201,11 @@ UTXO _uTXODeserialize(
isBlocked: reader.readBool(offsets[4]),
isCoinbase: reader.readBool(offsets[5]),
name: reader.readString(offsets[6]),
txid: reader.readString(offsets[7]),
value: reader.readLong(offsets[8]),
vout: reader.readLong(offsets[9]),
walletId: reader.readString(offsets[10]),
otherData: reader.readStringOrNull(offsets[7]),
txid: reader.readString(offsets[8]),
value: reader.readLong(offsets[9]),
vout: reader.readLong(offsets[10]),
walletId: reader.readString(offsets[11]),
);
object.id = id;
return object;
@ -220,12 +233,14 @@ P _uTXODeserializeProp<P>(
case 6:
return (reader.readString(offset)) as P;
case 7:
return (reader.readString(offset)) as P;
return (reader.readStringOrNull(offset)) as P;
case 8:
return (reader.readLong(offset)) as P;
return (reader.readString(offset)) as P;
case 9:
return (reader.readLong(offset)) as P;
case 10:
return (reader.readLong(offset)) as P;
case 11:
return (reader.readString(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
@ -1221,6 +1236,152 @@ extension UTXOQueryFilter on QueryBuilder<UTXO, UTXO, QFilterCondition> {
});
}
QueryBuilder<UTXO, UTXO, QAfterFilterCondition> otherDataIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'otherData',
));
});
}
QueryBuilder<UTXO, UTXO, QAfterFilterCondition> otherDataIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'otherData',
));
});
}
QueryBuilder<UTXO, UTXO, QAfterFilterCondition> otherDataEqualTo(
String? value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'otherData',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<UTXO, UTXO, QAfterFilterCondition> otherDataGreaterThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'otherData',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<UTXO, UTXO, QAfterFilterCondition> otherDataLessThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'otherData',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<UTXO, UTXO, QAfterFilterCondition> otherDataBetween(
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'otherData',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<UTXO, UTXO, QAfterFilterCondition> otherDataStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'otherData',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<UTXO, UTXO, QAfterFilterCondition> otherDataEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'otherData',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<UTXO, UTXO, QAfterFilterCondition> otherDataContains(
String value,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'otherData',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<UTXO, UTXO, QAfterFilterCondition> otherDataMatches(
String pattern,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'otherData',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<UTXO, UTXO, QAfterFilterCondition> otherDataIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'otherData',
value: '',
));
});
}
QueryBuilder<UTXO, UTXO, QAfterFilterCondition> otherDataIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'otherData',
value: '',
));
});
}
QueryBuilder<UTXO, UTXO, QAfterFilterCondition> txidEqualTo(
String value, {
bool caseSensitive = true,
@ -1672,6 +1833,18 @@ extension UTXOQuerySortBy on QueryBuilder<UTXO, UTXO, QSortBy> {
});
}
QueryBuilder<UTXO, UTXO, QAfterSortBy> sortByOtherData() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'otherData', Sort.asc);
});
}
QueryBuilder<UTXO, UTXO, QAfterSortBy> sortByOtherDataDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'otherData', Sort.desc);
});
}
QueryBuilder<UTXO, UTXO, QAfterSortBy> sortByTxid() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'txid', Sort.asc);
@ -1818,6 +1991,18 @@ extension UTXOQuerySortThenBy on QueryBuilder<UTXO, UTXO, QSortThenBy> {
});
}
QueryBuilder<UTXO, UTXO, QAfterSortBy> thenByOtherData() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'otherData', Sort.asc);
});
}
QueryBuilder<UTXO, UTXO, QAfterSortBy> thenByOtherDataDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'otherData', Sort.desc);
});
}
QueryBuilder<UTXO, UTXO, QAfterSortBy> thenByTxid() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'txid', Sort.asc);
@ -1914,6 +2099,13 @@ extension UTXOQueryWhereDistinct on QueryBuilder<UTXO, UTXO, QDistinct> {
});
}
QueryBuilder<UTXO, UTXO, QDistinct> distinctByOtherData(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'otherData', caseSensitive: caseSensitive);
});
}
QueryBuilder<UTXO, UTXO, QDistinct> distinctByTxid(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
@ -1990,6 +2182,12 @@ extension UTXOQueryProperty on QueryBuilder<UTXO, UTXO, QQueryProperty> {
});
}
QueryBuilder<UTXO, String?, QQueryOperations> otherDataProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'otherData');
});
}
QueryBuilder<UTXO, String, QQueryOperations> txidProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'txid');

View file

@ -252,12 +252,15 @@ bool isStackCoin(String? ticker) {
}
}
Widget? getIconForTicker(String ticker) {
Widget? getIconForTicker(
String ticker, {
double size = 20,
}) {
String? iconAsset = /*isStackCoin(ticker)
?*/
Assets.svg.iconFor(coin: coinFromTickerCaseInsensitive(ticker));
// : Assets.svg.buyIconFor(ticker);
return (iconAsset != null)
? SvgPicture.asset(iconAsset, height: 20, width: 20)
? SvgPicture.asset(iconAsset, height: size, width: size)
: null;
}

View file

@ -1,6 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/pages/buy_view/sub_widgets/crypto_selection_view.dart';
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -16,34 +19,57 @@ import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
class FloatingRateCurrencySelectionView extends StatefulWidget {
const FloatingRateCurrencySelectionView({
class ExchangeCurrencySelectionView extends StatefulWidget {
const ExchangeCurrencySelectionView({
Key? key,
required this.currencies,
required this.exchangeName,
required this.willChange,
required this.paired,
required this.isFixedRate,
}) : super(key: key);
final List<Currency> currencies;
final String exchangeName;
final Currency? willChange;
final Currency? paired;
final bool isFixedRate;
@override
State<FloatingRateCurrencySelectionView> createState() =>
_FloatingRateCurrencySelectionViewState();
State<ExchangeCurrencySelectionView> createState() =>
_ExchangeCurrencySelectionViewState();
}
class _FloatingRateCurrencySelectionViewState
extends State<FloatingRateCurrencySelectionView> {
class _ExchangeCurrencySelectionViewState
extends State<ExchangeCurrencySelectionView> {
late TextEditingController _searchController;
final _searchFocusNode = FocusNode();
final isDesktop = Util.isDesktop;
late final List<Currency> currencies;
late List<Currency> _currencies;
void filter(String text) {
setState(() {
_currencies = [
...currencies.where((e) =>
e.name.toLowerCase().contains(text.toLowerCase()) ||
e.ticker.toLowerCase().contains(text.toLowerCase()))
];
final query = ExchangeDataLoadingService.instance.isar.currencies
.where()
.exchangeNameEqualTo(widget.exchangeName)
.filter()
.supportsFixedRateEqualTo(widget.isFixedRate)
.and()
.group((q) => q
.nameContains(text, caseSensitive: false)
.or()
.tickerContains(text, caseSensitive: false));
if (widget.paired != null) {
_currencies = query
.and()
.not()
.tickerEqualTo(widget.paired!.ticker)
.sortByIsStackCoin()
.thenByTicker()
.findAllSync();
} else {
_currencies = query.sortByIsStackCoin().thenByTicker().findAllSync();
}
});
}
@ -51,19 +77,23 @@ class _FloatingRateCurrencySelectionViewState
void initState() {
_searchController = TextEditingController();
currencies = [...widget.currencies];
currencies.sort(
(a, b) => a.ticker.toLowerCase().compareTo(b.ticker.toLowerCase()));
for (Coin coin in Coin.values.reversed) {
int index = currencies.indexWhere((element) =>
element.ticker.toLowerCase() == coin.ticker.toLowerCase());
if (index > 0) {
final currency = currencies.removeAt(index);
currencies.insert(0, currency);
}
}
final query = ExchangeDataLoadingService.instance.isar.currencies
.where()
.exchangeNameEqualTo(widget.exchangeName)
.filter()
.supportsFixedRateEqualTo(widget.isFixedRate);
_currencies = [...currencies];
if (widget.paired != null) {
_currencies = query
.and()
.not()
.tickerEqualTo(widget.paired!.ticker)
.sortByIsStackCoin()
.thenByTicker()
.findAllSync();
} else {
_currencies = query.sortByIsStackCoin().thenByTicker().findAllSync();
}
super.initState();
}
@ -77,7 +107,11 @@ class _FloatingRateCurrencySelectionViewState
@override
Widget build(BuildContext context) {
final isDesktop = Util.isDesktop;
print("==================================================");
print("${widget.exchangeName}");
print("${widget.isFixedRate}");
print("==================================================");
return ConditionalParent(
condition: !isDesktop,
builder: (child) {
@ -210,13 +244,18 @@ class _FloatingRateCurrencySelectionViewState
SizedBox(
width: 24,
height: 24,
child: SvgPicture.network(
items[index].image,
width: 24,
height: 24,
placeholderBuilder: (_) =>
const LoadingIndicator(),
),
child: isStackCoin(items[index].ticker)
? getIconForTicker(
items[index].ticker,
size: 24,
)
: SvgPicture.network(
items[index].image,
width: 24,
height: 24,
placeholderBuilder: (_) =>
const LoadingIndicator(),
),
),
const SizedBox(
width: 10,
@ -284,13 +323,18 @@ class _FloatingRateCurrencySelectionViewState
SizedBox(
width: 24,
height: 24,
child: SvgPicture.network(
_currencies[index].image,
width: 24,
height: 24,
placeholderBuilder: (_) =>
const LoadingIndicator(),
),
child: isStackCoin(_currencies[index].ticker)
? getIconForTicker(
_currencies[index].ticker,
size: 24,
)
: SvgPicture.network(
_currencies[index].image,
width: 24,
height: 24,
placeholderBuilder: (_) =>
const LoadingIndicator(),
),
),
const SizedBox(
width: 10,

View file

@ -1,384 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart';
import 'package:stackwallet/utilities/assets.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/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/background.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/loading_indicator.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:tuple/tuple.dart';
class FixedRateMarketPairCoinSelectionView extends ConsumerStatefulWidget {
const FixedRateMarketPairCoinSelectionView({
Key? key,
required this.markets,
required this.currencies,
required this.isFrom,
}) : super(key: key);
final List<FixedRateMarket> markets;
final List<Currency> currencies;
final bool isFrom;
@override
ConsumerState<FixedRateMarketPairCoinSelectionView> createState() =>
_FixedRateMarketPairCoinSelectionViewState();
}
class _FixedRateMarketPairCoinSelectionViewState
extends ConsumerState<FixedRateMarketPairCoinSelectionView> {
late TextEditingController _searchController;
final _searchFocusNode = FocusNode();
late final List<FixedRateMarket> markets;
late List<FixedRateMarket> _markets;
late final bool isFrom;
Tuple2<String, String> _imageUrlAndNameFor(String ticker) {
final matches = widget.currencies.where(
(element) => element.ticker.toLowerCase() == ticker.toLowerCase());
if (matches.isNotEmpty) {
return Tuple2(matches.first.image, matches.first.name);
}
return Tuple2("", ticker);
}
void filter(String text) {
setState(() {
_markets = [
...markets.where((e) {
final String ticker = isFrom ? e.from : e.to;
final __currencies = widget.currencies
.where((e) => e.ticker.toLowerCase() == ticker.toLowerCase());
if (__currencies.isNotEmpty) {
return __currencies.first.name
.toLowerCase()
.contains(text.toLowerCase()) ||
ticker.toLowerCase().contains(text.toLowerCase());
}
return ticker.toLowerCase().contains(text.toLowerCase());
})
];
});
}
@override
void initState() {
_searchController = TextEditingController();
isFrom = widget.isFrom;
markets = [...widget.markets];
if (isFrom) {
markets.sort(
(a, b) => a.from.toLowerCase().compareTo(b.from.toLowerCase()),
);
for (Coin coin in Coin.values.reversed) {
int index = markets.indexWhere((element) =>
element.from.toLowerCase() == coin.ticker.toLowerCase());
if (index > 0) {
final market = markets.removeAt(index);
markets.insert(0, market);
}
}
} else {
markets.sort(
(a, b) => a.to.toLowerCase().compareTo(b.to.toLowerCase()),
);
for (Coin coin in Coin.values.reversed) {
int index = markets.indexWhere(
(element) => element.to.toLowerCase() == coin.ticker.toLowerCase());
if (index > 0) {
final market = markets.removeAt(index);
markets.insert(0, market);
}
}
}
_markets = [...markets];
super.initState();
}
@override
void dispose() {
_searchController.dispose();
_searchFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final isDesktop = Util.isDesktop;
return ConditionalParent(
condition: !isDesktop,
builder: (child) {
return Background(
child: Scaffold(
backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(
const Duration(milliseconds: 50));
}
if (mounted) {
Navigator.of(context).pop();
}
},
),
title: Text(
"Choose a coin to exchange",
style: STextStyles.pageTitleH2(context),
),
),
body: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
),
child: child,
),
),
);
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!isDesktop)
const SizedBox(
height: 16,
),
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autofocus: isDesktop,
autocorrect: !isDesktop,
enableSuggestions: !isDesktop,
controller: _searchController,
focusNode: _searchFocusNode,
onChanged: filter,
style: STextStyles.field(context),
decoration: standardInputDecoration(
"Search",
_searchFocusNode,
context,
).copyWith(
prefixIcon: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 16,
),
child: SvgPicture.asset(
Assets.svg.search,
width: 16,
height: 16,
),
),
suffixIcon: _searchController.text.isNotEmpty
? Padding(
padding: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(),
onTap: () async {
setState(() {
_searchController.text = "";
});
},
),
],
),
),
)
: null,
),
),
),
const SizedBox(
height: 10,
),
Text(
"Popular coins",
style: STextStyles.smallMed12(context),
),
const SizedBox(
height: 12,
),
Flexible(
child: Builder(builder: (context) {
final items = _markets
.where((e) => Coin.values
.where((coin) =>
coin.ticker.toLowerCase() ==
(isFrom ? e.from.toLowerCase() : e.to.toLowerCase()))
.isNotEmpty)
.toList(growable: false);
return RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
child: ListView.builder(
shrinkWrap: true,
primary: isDesktop ? false : null,
itemCount: items.length,
itemBuilder: (builderContext, index) {
final String ticker =
isFrom ? items[index].from : items[index].to;
final tuple = _imageUrlAndNameFor(ticker);
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: GestureDetector(
onTap: () {
Navigator.of(context).pop(ticker);
},
child: RoundedWhiteContainer(
child: Row(
children: [
SizedBox(
width: 24,
height: 24,
child: SvgPicture.network(
tuple.item1,
width: 24,
height: 24,
placeholderBuilder: (_) =>
const LoadingIndicator(),
),
),
const SizedBox(
width: 10,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tuple.item2,
style: STextStyles.largeMedium14(context),
),
const SizedBox(
height: 2,
),
Text(
ticker.toUpperCase(),
style: STextStyles.smallMed12(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
],
),
),
],
),
),
),
);
},
),
);
}),
),
const SizedBox(
height: 20,
),
Text(
"All coins",
style: STextStyles.smallMed12(context),
),
const SizedBox(
height: 12,
),
Flexible(
child: RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
child: ListView.builder(
shrinkWrap: true,
primary: isDesktop ? false : null,
itemCount: _markets.length,
itemBuilder: (builderContext, index) {
final String ticker =
isFrom ? _markets[index].from : _markets[index].to;
final tuple = _imageUrlAndNameFor(ticker);
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: GestureDetector(
onTap: () {
Navigator.of(context).pop(ticker);
},
child: RoundedWhiteContainer(
child: Row(
children: [
SizedBox(
width: 24,
height: 24,
child: SvgPicture.network(
tuple.item1,
width: 24,
height: 24,
placeholderBuilder: (_) =>
const LoadingIndicator(),
),
),
const SizedBox(
width: 10,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tuple.item2,
style: STextStyles.largeMedium14(context),
),
const SizedBox(
height: 2,
),
Text(
ticker.toUpperCase(),
style: STextStyles.smallMed12(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
],
),
),
],
),
),
),
);
},
),
),
),
],
),
);
}
}

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,7 @@ import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/exchange.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -139,7 +140,222 @@ class ExchangeProviderOptions extends ConsumerWidget {
fromAmount != null &&
fromAmount! > Decimal.zero)
FutureBuilder(
future: ChangeNowExchange().getEstimate(
future: ChangeNowExchange.instance.getEstimate(
from!,
to!,
reversed ? toAmount! : fromAmount!,
fixedRate,
reversed,
),
builder: (context,
AsyncSnapshot<ExchangeResponse<Estimate>>
snapshot) {
if (snapshot.connectionState ==
ConnectionState.done &&
snapshot.hasData) {
final estimate = snapshot.data?.value;
if (estimate != null) {
Decimal rate;
if (estimate.reversed) {
rate = (toAmount! /
estimate.estimatedAmount)
.toDecimal(
scaleOnInfinitePrecision: 12);
} else {
rate = (estimate.estimatedAmount /
fromAmount!)
.toDecimal(
scaleOnInfinitePrecision: 12);
}
Coin coin;
try {
coin =
coinFromTickerCaseInsensitive(to!);
} catch (_) {
coin = Coin.bitcoin;
}
return Text(
"1 ${from!.toUpperCase()} ~ ${Format.localizedStringAsFixed(
value: rate,
locale: ref.watch(
localeServiceChangeNotifierProvider
.select(
(value) => value.locale),
),
decimalPlaces:
Constants.decimalPlacesForCoin(
coin),
)} ${to!.toUpperCase()}",
style:
STextStyles.itemSubtitle12(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
);
} else {
Logging.instance.log(
"$runtimeType failed to fetch rate for ChangeNOW: ${snapshot.data}",
level: LogLevel.Warning,
);
return Text(
"Failed to fetch rate",
style:
STextStyles.itemSubtitle12(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
);
}
} else {
return AnimatedText(
stringsToLoopThrough: const [
"Loading",
"Loading.",
"Loading..",
"Loading...",
],
style: STextStyles.itemSubtitle12(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
);
}
},
),
if (!(from != null &&
to != null &&
toAmount != null &&
toAmount! > Decimal.zero &&
fromAmount != null &&
fromAmount! > Decimal.zero))
Text(
"n/a",
style: STextStyles.itemSubtitle12(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
],
),
),
],
),
),
),
),
),
if (isDesktop)
Container(
height: 1,
color: Theme.of(context).extension<StackColors>()!.background,
),
if (!isDesktop)
const SizedBox(
height: 16,
),
ConditionalParent(
condition: isDesktop,
builder: (child) => MouseRegion(
cursor: SystemMouseCursors.click,
child: child,
),
child: GestureDetector(
onTap: () {
if (ref.read(currentExchangeNameStateProvider.state).state !=
MajesticBankExchange.exchangeName) {
ref.read(currentExchangeNameStateProvider.state).state =
MajesticBankExchange.exchangeName;
ref.read(exchangeFormStateProvider).exchange =
Exchange.fromName(ref
.read(currentExchangeNameStateProvider.state)
.state);
}
},
child: Container(
color: Colors.transparent,
child: Padding(
padding: isDesktop
? const EdgeInsets.all(16)
: const EdgeInsets.all(0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 20,
height: 20,
child: Padding(
padding:
EdgeInsets.only(top: isDesktop ? 20.0 : 15.0),
child: Radio(
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value: MajesticBankExchange.exchangeName,
groupValue: ref
.watch(currentExchangeNameStateProvider.state)
.state,
onChanged: (value) {
if (value is String) {
ref
.read(
currentExchangeNameStateProvider.state)
.state = value;
ref.read(exchangeFormStateProvider).exchange =
Exchange.fromName(ref
.read(currentExchangeNameStateProvider
.state)
.state);
}
},
),
),
),
const SizedBox(
width: 14,
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: SvgPicture.asset(
Assets.exchange.changeNow,
width: isDesktop ? 32 : 24,
height: isDesktop ? 32 : 24,
),
),
const SizedBox(
width: 10,
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
MajesticBankExchange.exchangeName,
style: STextStyles.titleBold12(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark2,
),
),
if (from != null &&
to != null &&
toAmount != null &&
toAmount! > Decimal.zero &&
fromAmount != null &&
fromAmount! > Decimal.zero)
FutureBuilder(
future:
MajesticBankExchange.instance.getEstimate(
from!,
to!,
reversed ? toAmount! : fromAmount!,

View file

@ -14,28 +14,27 @@ class RateTypeToggle extends ConsumerWidget {
this.onChanged,
}) : super(key: key);
final void Function(ExchangeRateType)? onChanged;
final void Function()? onChanged;
@override
Widget build(BuildContext context, WidgetRef ref) {
debugPrint("BUILD: $runtimeType");
final isDesktop = Util.isDesktop;
final estimated = ref.watch(prefsChangeNotifierProvider
.select((value) => value.exchangeRateType)) ==
ExchangeRateType.estimated;
return Toggle(
onValueChanged: (value) {
if (!estimated) {
if (value) {
ref.read(prefsChangeNotifierProvider).exchangeRateType =
ExchangeRateType.fixed;
} else {
ref.read(prefsChangeNotifierProvider).exchangeRateType =
ExchangeRateType.estimated;
onChanged?.call(ExchangeRateType.estimated);
} else {
onChanged?.call(ExchangeRateType.fixed);
}
onChanged?.call();
},
isOn: !estimated,
isOn: ref.watch(prefsChangeNotifierProvider
.select((value) => value.exchangeRateType)) ==
ExchangeRateType.fixed,
onColor: isDesktop
? Theme.of(context)
.extension<StackColors>()!

View file

@ -4,7 +4,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/buy_view/buy_view.dart';
import 'package:stackwallet/pages/exchange_view/exchange_loading_overlay.dart';
import 'package:stackwallet/pages/exchange_view/exchange_view.dart';
import 'package:stackwallet/pages/home_view/sub_widgets/home_view_button_bar.dart';
import 'package:stackwallet/pages/notification_views/notifications_view.dart';
@ -12,13 +11,10 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/global_set
import 'package:stackwallet/pages/settings_views/global_settings_view/hidden_settings.dart';
import 'package:stackwallet/pages/wallets_view/wallets_view.dart';
import 'package:stackwallet/providers/global/notifications_provider.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/providers/ui/home_view_index_provider.dart';
import 'package:stackwallet/providers/ui/unread_notifications_provider.dart';
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/background.dart';
@ -45,7 +41,6 @@ class _HomeViewState extends ConsumerState<HomeView> {
bool _exitEnabled = false;
final _exchangeDataLoadingService = ExchangeDataLoadingService();
// final _buyDataLoadingService = BuyDataLoadingService();
Future<bool> _onWillPop() async {
@ -84,16 +79,6 @@ class _HomeViewState extends ConsumerState<HomeView> {
return _exitEnabled;
}
void _loadCNData() {
// unawaited future
if (ref.read(prefsChangeNotifierProvider).externalCalls) {
_exchangeDataLoadingService.loadAll(ref);
} else {
Logging.instance.log("User does not want to use external calls",
level: LogLevel.Info);
}
}
// void _loadSimplexData() {
// // unawaited future
// if (ref.read(prefsChangeNotifierProvider).externalCalls) {
@ -123,9 +108,9 @@ class _HomeViewState extends ConsumerState<HomeView> {
Stack(
children: [
const ExchangeView(),
ExchangeLoadingOverlayView(
unawaitedLoad: _loadCNData,
),
// ExchangeLoadingOverlayView(
// unawaitedLoad: _loadCNData,
// ),
],
),
if (Constants.enableBuy)
@ -331,9 +316,9 @@ class _HomeViewState extends ConsumerState<HomeView> {
_ref.listen(homeViewPageIndexStateProvider,
(previous, next) {
if (next is int && next >= 0 && next <= 2) {
if (next == 1) {
_exchangeDataLoadingService.loadAll(ref);
}
// if (next == 1) {
// _exchangeDataLoadingService.loadAll(ref);
// }
// if (next == 2) {
// _buyDataLoadingService.loadAll(ref);
// }

View file

@ -1,10 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/stack_dialog.dart';
class HomeViewButtonBar extends ConsumerStatefulWidget {
const HomeViewButtonBar({Key? key}) : super(key: key);
@ -19,16 +17,16 @@ class _HomeViewButtonBarState extends ConsumerState<HomeViewButtonBar> {
@override
void initState() {
ref.read(exchangeFormStateProvider).setOnError(
onError: (String message) => showDialog<dynamic>(
context: context,
barrierDismissible: true,
builder: (_) => StackDialog(
title: "Exchange API Call Failed",
message: message,
),
),
);
// ref.read(exchangeFormStateProvider).setOnError(
// onError: (String message) => showDialog<dynamic>(
// context: context,
// barrierDismissible: true,
// builder: (_) => StackDialog(
// title: "Exchange API Call Failed",
// message: message,
// ),
// ),
// );
super.initState();
}
@ -106,7 +104,7 @@ class _HomeViewButtonBarState extends ConsumerState<HomeViewButtonBar> {
// DateTime now = DateTime.now();
// if (ref.read(prefsChangeNotifierProvider).externalCalls) {
// print("loading?");
await ExchangeDataLoadingService().loadAll(ref);
// await ExchangeDataLoadingService().loadAll(ref);
// }
// if (now.difference(_lastRefreshed) > _refreshInterval) {
// await ExchangeDataLoadingService().loadAll(ref);

View file

@ -230,8 +230,13 @@ class _StackPrivacyCalls extends ConsumerState<StackPrivacyCalls> {
value: isEasy)
.then((_) {
if (isEasy) {
unawaited(ExchangeDataLoadingService()
.loadAll(ref));
unawaited(
ExchangeDataLoadingService.instance
.init()
.then((_) => ExchangeDataLoadingService
.instance
.loadAll()),
);
// unawaited(
// BuyDataLoadingService().loadAll(ref));
ref

View file

@ -37,7 +37,6 @@ import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/background.dart';
@ -80,8 +79,6 @@ class _WalletViewState extends ConsumerState<WalletView> {
late StreamSubscription<dynamic> _syncStatusSubscription;
late StreamSubscription<dynamic> _nodeStatusSubscription;
final _cnLoadingService = ExchangeDataLoadingService();
@override
void initState() {
walletId = widget.walletId;
@ -231,7 +228,8 @@ class _WalletViewState extends ConsumerState<WalletView> {
}
void _onExchangePressed(BuildContext context) async {
unawaited(_cnLoadingService.loadAll(ref));
// too expensive
// unawaited(ExchangeDataLoadingService.instance.loadAll(ref));
final coin = ref.read(managerProvider).coin;
@ -257,8 +255,6 @@ class _WalletViewState extends ConsumerState<WalletView> {
ExchangeRateType.estimated;
ref.read(exchangeFormStateProvider).exchange = ref.read(exchangeProvider);
ref.read(exchangeFormStateProvider).exchangeType =
ExchangeRateType.estimated;
final currencies = ref
.read(availableChangeNowCurrenciesProvider)
@ -311,7 +307,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
);
final firoWallet = ref.read(managerProvider).wallet as FiroWallet;
final publicBalance = await firoWallet.availablePublicBalance();
final publicBalance = firoWallet.availablePublicBalance();
if (publicBalance <= Decimal.zero) {
shouldPop = true;
if (mounted) {
@ -363,12 +359,13 @@ class _WalletViewState extends ConsumerState<WalletView> {
void _loadCNData() {
// unawaited future
if (ref.read(prefsChangeNotifierProvider).externalCalls) {
_cnLoadingService.loadAll(ref, coin: ref.read(managerProvider).coin);
} else {
Logging.instance.log("User does not want to use external calls",
level: LogLevel.Info);
}
// if (ref.read(prefsChangeNotifierProvider).externalCalls) {
ExchangeDataLoadingService.instance.loadAll();
// .loadAll(ref, coin: ref.read(managerProvider).coin);
// } else {
// Logging.instance.log("User does not want to use external calls",
// level: LogLevel.Info);
// }
}
@override

View file

@ -169,7 +169,9 @@ class _StackPrivacyDialog extends ConsumerState<StackPrivacyDialog> {
value: isEasy)
.then((_) {
if (isEasy) {
unawaited(ExchangeDataLoadingService().loadAll(ref));
unawaited(
ExchangeDataLoadingService.instance.loadAll(),
);
ref
.read(priceAnd24hChangeNotifierProvider)
.start(true);

View file

@ -0,0 +1,6 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/models/exchange/majestic_bank/mb_available_currencies.dart';
final availableMajesticBankCurrenciesProvider = Provider<MBAvailableCurrencies>(
(ref) => MBAvailableCurrencies(),
);

View file

@ -1,6 +1,6 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/exchange.dart';
final currentExchangeNameStateProvider = StateProvider<String>(
(ref) => ChangeNowExchange.exchangeName,
(ref) => Exchange.defaultExchange.name,
);

View file

@ -1,6 +1,30 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/models/exchange/exchange_form_state.dart';
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
final exchangeFormStateProvider = ChangeNotifierProvider<ExchangeFormState>(
(ref) => ExchangeFormState(),
final exchangeFormStateProvider =
ChangeNotifierProvider<ExchangeFormState>((ref) {
final type = ref.watch(
prefsChangeNotifierProvider.select(
(value) => value.exchangeRateType,
),
);
switch (type) {
case ExchangeRateType.estimated:
return ref.watch(_estimatedFormState);
case ExchangeRateType.fixed:
return ref.watch(_fixedFormState);
}
});
final _fixedInstance = ExchangeFormState(ExchangeRateType.fixed);
final _fixedFormState = ChangeNotifierProvider(
(ref) => _fixedInstance,
);
final _estimatedInstance = ExchangeFormState(ExchangeRateType.estimated);
final _estimatedFormState = ChangeNotifierProvider(
(ref) => _estimatedInstance,
);

View file

@ -28,7 +28,6 @@ import 'package:stackwallet/pages/buy_view/buy_quote_preview.dart';
import 'package:stackwallet/pages/buy_view/buy_view.dart';
import 'package:stackwallet/pages/exchange_view/choose_from_stack_view.dart';
import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart';
import 'package:stackwallet/pages/exchange_view/exchange_loading_overlay.dart';
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_1_view.dart';
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart';
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view.dart';
@ -891,7 +890,7 @@ class RouteGenerator {
return _routeError("${settings.name} invalid args: ${args.toString()}");
case WalletInitiatedExchangeView.routeName:
if (args is Tuple3<String, Coin, VoidCallback>) {
if (args is Tuple2<String, Coin>) {
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => Stack(
@ -900,9 +899,9 @@ class RouteGenerator {
walletId: args.item1,
coin: args.item2,
),
ExchangeLoadingOverlayView(
unawaitedLoad: args.item3,
),
// ExchangeLoadingOverlayView(
// unawaitedLoad: args.item3,
// ),
],
),
settings: RouteSettings(

View file

@ -0,0 +1,389 @@
// import 'package:decimal/decimal.dart';
// import 'package:flutter/foundation.dart';
// import 'package:stackwallet/models/exchange/response_objects/currency.dart';
// import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
// import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
// import 'package:stackwallet/services/exchange/exchange.dart';
// import 'package:stackwallet/utilities/logger.dart';
//
// class ExchangeFormState extends ChangeNotifier {
// ExchangeFormState(this.exchangeRateType);
// final ExchangeRateType exchangeRateType;
//
// Exchange? _exchange;
// Exchange get exchange =>
// _exchange ??= ChangeNowExchange(); // default to change now
// set exchange(Exchange value) {
// _exchange = value;
// _updateRangesAndEstimate(
// shouldNotifyListeners: true,
// );
// }
//
// bool _reversed = false;
// bool get reversed => _reversed;
// // set reversed(bool reversed) {
// // _reversed = reversed;
// // //
// // }
//
// Decimal? _rate;
// Decimal? get rate => _rate;
// // set rate(Decimal? rate) {
// // _rate = rate;
// // //
// // }
//
// Decimal? _sendAmount;
// Decimal? get sendAmount => _sendAmount;
// // set sendAmount(Decimal? sendAmount) {
// // _sendAmount = sendAmount;
// // //
// // }
//
// Decimal? _receiveAmount;
// Decimal? get receiveAmount => _receiveAmount;
// // set receiveAmount(Decimal? receiveAmount) {
// // _receiveAmount = receiveAmount;
// // //
// // }
//
// Currency? _sendCurrency;
// Currency? get sendCurrency => _sendCurrency;
// // set sendCurrency(Currency? sendCurrency) {
// // _sendCurrency = sendCurrency;
// // //
// // }
//
// Currency? _receiveCurrency;
// Currency? get receiveCurrency => _receiveCurrency;
// // set receiveCurrency(Currency? receiveCurrency) {
// // _receiveCurrency = receiveCurrency;
// // //
// // }
//
// Decimal? _minSendAmount;
// Decimal? get minSendAmount => _minSendAmount;
// // set minSendAmount(Decimal? minSendAmount) {
// // _minSendAmount = minSendAmount;
// // //
// // }
//
// Decimal? _minReceiveAmount;
// Decimal? get minReceiveAmount => _minReceiveAmount;
// // set minReceiveAmount(Decimal? minReceiveAmount) {
// // _minReceiveAmount = minReceiveAmount;
// // //
// // }
//
// Decimal? _maxSendAmount;
// Decimal? get maxSendAmount => _maxSendAmount;
// // set maxSendAmount(Decimal? maxSendAmount) {
// // _maxSendAmount = maxSendAmount;
// // //
// // }
//
// Decimal? _maxReceiveAmount;
// Decimal? get maxReceiveAmount => _maxReceiveAmount;
// // set maxReceiveAmount(Decimal? maxReceiveAmount) {
// // _maxReceiveAmount = maxReceiveAmount;
// // //
// // }
//
// //============================================================================
// // computed properties
// //============================================================================
//
// String? get fromTicker => _sendCurrency?.ticker;
//
// String? get toTicker => _receiveCurrency?.ticker;
//
// String get warning {
// if (reversed) {
// if (_receiveCurrency != null && _receiveAmount != null) {
// if (_minReceiveAmount != null &&
// _receiveAmount! < _minReceiveAmount! &&
// _receiveAmount! > Decimal.zero) {
// return "Minimum amount ${_minReceiveAmount!.toString()} ${_receiveCurrency!.ticker.toUpperCase()}";
// } else if (_maxReceiveAmount != null &&
// _receiveAmount! > _maxReceiveAmount!) {
// return "Maximum amount ${_maxReceiveAmount!.toString()} ${_receiveCurrency!.ticker.toUpperCase()}";
// }
// }
// } else {
// if (_sendCurrency != null && _sendAmount != null) {
// if (_minSendAmount != null &&
// _sendAmount! < _minSendAmount! &&
// _sendAmount! > Decimal.zero) {
// return "Minimum amount ${_minSendAmount!.toString()} ${_sendCurrency!.ticker.toUpperCase()}";
// } else if (_maxSendAmount != null && _sendAmount! > _maxSendAmount!) {
// return "Maximum amount ${_maxSendAmount!.toString()} ${_sendCurrency!.ticker.toUpperCase()}";
// }
// }
// }
//
// return "";
// }
//
// //============================================================================
// // public state updaters
// //============================================================================
//
// void reset(bool shouldNotifyListeners) {
// _exchange = null;
// _reversed = false;
// _rate = null;
// _sendAmount = null;
// _receiveAmount = null;
// _sendCurrency = null;
// _receiveCurrency = null;
// _minSendAmount = null;
// _minReceiveAmount = null;
// _maxSendAmount = null;
// _maxReceiveAmount = null;
//
// if (shouldNotifyListeners) {
// notifyListeners();
// }
// }
//
// Future<void> setFromAmountAndCalculateToAmount(
// Decimal? newSendAmount,
// bool shouldNotifyListeners,
// ) async {
// if (newSendAmount == null) {
// // todo: check if this breaks things and stuff
// _receiveAmount = null;
// _sendAmount = null;
// } else {
// if (newSendAmount <= Decimal.zero) {
// _receiveAmount = Decimal.zero;
// }
//
// _sendAmount = newSendAmount;
// _reversed = false;
//
// await _updateRangesAndEstimate(
// shouldNotifyListeners: false,
// );
// }
//
// if (shouldNotifyListeners) {
// notifyListeners();
// }
// }
//
// Future<void> setToAmountAndCalculateFromAmount(
// Decimal? newReceiveAmount,
// bool shouldNotifyListeners,
// ) async {
// if (newReceiveAmount == null) {
// // todo: check if this breaks things and stuff
// _receiveAmount = null;
// _sendAmount = null;
// } else {
// if (newReceiveAmount <= Decimal.zero) {
// _sendAmount = Decimal.zero;
// }
//
// _receiveAmount = newReceiveAmount;
// _reversed = true;
//
// await _updateRangesAndEstimate(
// shouldNotifyListeners: false,
// );
// }
//
// if (shouldNotifyListeners) {
// notifyListeners();
// }
// }
//
// Future<void> updateFrom(
// Currency sendCurrency,
// bool shouldNotifyListeners,
// ) async {
// try {
// _sendCurrency = sendCurrency;
// if (_receiveCurrency == null) {
// _rate = null;
// } else {
// await _updateRangesAndEstimate(
// shouldNotifyListeners: false,
// );
// }
// } catch (e, s) {
// Logging.instance.log("$e\n$s", level: LogLevel.Error);
// }
// if (shouldNotifyListeners) {
// notifyListeners();
// }
// }
//
// Future<void> updateTo(
// Currency receiveCurrency,
// bool shouldNotifyListeners,
// ) async {
// try {
// _receiveCurrency = receiveCurrency;
//
// if (_sendCurrency == null) {
// _rate = null;
// } else {
// await _updateRangesAndEstimate(
// shouldNotifyListeners: false,
// );
// }
// } catch (e, s) {
// Logging.instance.log("$e\n$s", level: LogLevel.Error);
// }
// if (shouldNotifyListeners) {
// notifyListeners();
// }
// }
//
// Future<void> swap(
// {required bool shouldNotifyListeners,}) async {
// final Decimal? temp = sendAmount;
// _sendAmount = receiveAmount;
// _receiveAmount = temp;
//
// _minSendAmount = null;
// _maxSendAmount = null;
// _minReceiveAmount = null;
// _maxReceiveAmount = null;
//
// final Currency? tmp = sendCurrency;
// _sendCurrency = receiveCurrency;
// _receiveCurrency = tmp;
//
// await _updateRangesAndEstimate(
// shouldNotifyListeners: false,
// );
// }
//
// //============================================================================
// // private state updaters
// //============================================================================
//
// Future<void> _updateRangesAndEstimate(
// {required bool shouldNotifyListeners,}) async {
// await _updateRanges(shouldNotifyListeners: false);
// await _updateEstimate(shouldNotifyListeners: false);
// if (shouldNotifyListeners) {
// notifyListeners();
// }
// }
//
// Future<void> _updateRanges({required bool shouldNotifyListeners,}) async {
// // if (exchange?.name == SimpleSwapExchange.exchangeName) {
// // reversed = false;
// // }
// final _send = sendCurrency;
// final _receive = receiveCurrency;
// if (_send == null || _receive == null) {
// Logging.instance.log(
// "Tried to $runtimeType.updateRanges where ( $_send || $_receive) for: $exchange",
// level: LogLevel.Info,
// );
// return;
// }
// final response = await exchange.getRange(
// _send.ticker,
// _receive.ticker,
// exchangeRateType == ExchangeRateType.fixed,
// );
//
// if (response.value == null) {
// Logging.instance.log(
// "Tried to $runtimeType.updateRanges for: $exchange where response: $response",
// level: LogLevel.Info,
// );
// return;
// }
// final responseReversed = await exchange.getRange(
// _receive.ticker,
// _send.ticker,
// exchangeRateType == ExchangeRateType.fixed,
// );
//
// if (responseReversed.value == null) {
// Logging.instance.log(
// "Tried to $runtimeType.updateRanges for: $exchange where response: $responseReversed",
// level: LogLevel.Info,
// );
// return;
// }
//
// final range = response.value!;
// final rangeReversed = responseReversed.value!;
//
// _minSendAmount = range.min;
// _maxSendAmount = range.max;
// _minReceiveAmount = rangeReversed.min;
// _maxReceiveAmount = rangeReversed.max;
//
// //todo: check if print needed
// // debugPrint(
// // "updated range for: $exchange for $_fromTicker-$_toTicker: $range");
//
// if (shouldNotifyListeners) {
// notifyListeners();
// }
// }
//
// Future<void> _updateEstimate({
// required bool shouldNotifyListeners,
// }) async {
// // if (exchange?.name == SimpleSwapExchange.exchangeName) {
// // reversed = false;
// // }
// final amount = reversed ? receiveAmount : sendAmount;
// if (sendCurrency == null ||
// receiveCurrency == null ||
// amount == null ||
// amount <= Decimal.zero) {
// Logging.instance.log(
// "Tried to $runtimeType.updateEstimate for: $exchange where (from: $sendCurrency || to: $receiveCurrency || amount: $amount)",
// level: LogLevel.Info,
// );
// return;
// }
// final response = await exchange.getEstimate(
// sendCurrency!.ticker,
// receiveCurrency!.ticker,
// amount,
// exchangeRateType == ExchangeRateType.fixed,
// reversed,
// );
//
// if (response.value == null) {
// Logging.instance.log(
// "Tried to $runtimeType.updateEstimate for: $exchange where response: $response",
// level: LogLevel.Info,
// );
// return;
// }
//
// final estimate = response.value!;
//
// if (reversed) {
// _sendAmount = estimate.estimatedAmount;
// } else {
// _receiveAmount = estimate.estimatedAmount;
// }
//
// _rate =
// (receiveAmount! / sendAmount!).toDecimal(scaleOnInfinitePrecision: 12);
//
// //todo: check if print needed
// // debugPrint(
// // "updated estimate for: $exchange for $fromTicker-$toTicker: $estimate");
//
// if (shouldNotifyListeners) {
// notifyListeners();
// }
// }
//
//
// }

View file

@ -9,13 +9,15 @@ import 'package:stackwallet/models/exchange/change_now/cn_exchange_estimate.dart
import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart';
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart';
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart';
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
import 'package:stackwallet/models/exchange/response_objects/range.dart';
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:tuple/tuple.dart';
class ChangeNowAPI {
static const String scheme = "https";
@ -127,7 +129,9 @@ class ChangeNowAPI {
try {
final result = await compute(
_parseAvailableCurrenciesJson, jsonArray as List<dynamic>);
_parseAvailableCurrenciesJson,
Tuple2(jsonArray as List<dynamic>, fixedRate == true),
);
return result;
} catch (e, s) {
Logging.instance.log("getAvailableCurrencies exception: $e\n$s",
@ -152,14 +156,21 @@ class ChangeNowAPI {
}
ExchangeResponse<List<Currency>> _parseAvailableCurrenciesJson(
List<dynamic> jsonArray) {
Tuple2<List<dynamic>, bool> args,
) {
try {
List<Currency> currencies = [];
for (final json in jsonArray) {
for (final json in args.item1) {
try {
currencies
.add(Currency.fromJson(Map<String, dynamic>.from(json as Map)));
final map = Map<String, dynamic>.from(json as Map);
map["supportsEstimatedRate"] = !args.item2;
currencies.add(
Currency.fromJson(
map,
exchangeName: ChangeNowExchange.exchangeName,
),
);
} catch (_) {
return ExchangeResponse(
exception: ExchangeException("Failed to serialize $json",
@ -199,8 +210,14 @@ class ChangeNowAPI {
try {
for (final json in jsonArray) {
try {
currencies
.add(Currency.fromJson(Map<String, dynamic>.from(json as Map)));
final map = Map<String, dynamic>.from(json as Map);
map["supportsEstimatedRate"] = !(fixedRate == true);
currencies.add(
Currency.fromJson(
map,
exchangeName: ChangeNowExchange.exchangeName,
),
);
} catch (_) {
return ExchangeResponse(
exception: ExchangeException(
@ -823,6 +840,7 @@ class ChangeNowAPI {
final List<String> stringPair = (json as String).split("_");
pairs.add(
Pair(
exchangeName: ChangeNowExchange.exchangeName,
from: stringPair[0],
to: stringPair[1],
fromNetwork: "",

View file

@ -1,16 +1,21 @@
import 'package:decimal/decimal.dart';
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
import 'package:stackwallet/models/exchange/response_objects/range.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_api.dart';
import 'package:stackwallet/services/exchange/exchange.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:uuid/uuid.dart';
class ChangeNowExchange extends Exchange {
ChangeNowExchange._();
static ChangeNowExchange? _instance;
static ChangeNowExchange get instance => _instance ??= ChangeNowExchange._();
static const exchangeName = "ChangeNOW";
@override
@ -85,8 +90,32 @@ class ChangeNowExchange extends Exchange {
@override
Future<ExchangeResponse<List<Pair>>> getAllPairs(bool fixedRate) async {
// TODO: implement getAllPairs
throw UnimplementedError();
if (fixedRate) {
final markets =
await ChangeNowAPI.instance.getAvailableFixedRateMarkets();
if (markets.value == null) {
return ExchangeResponse(exception: markets.exception);
}
final List<Pair> pairs = [];
for (final market in markets.value!) {
pairs.add(
Pair(
exchangeName: ChangeNowExchange.exchangeName,
from: market.from,
fromNetwork: "",
to: market.to,
toNetwork: "",
fixedRate: true,
floatingRate: false,
),
);
}
return ExchangeResponse(value: pairs);
} else {
return await ChangeNowAPI.instance.getAvailableFloatingRatePairs();
}
}
@override

View file

@ -1,20 +1,25 @@
import 'package:decimal/decimal.dart';
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
import 'package:stackwallet/models/exchange/response_objects/range.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
abstract class Exchange {
static Exchange get defaultExchange => ChangeNowExchange.instance;
static Exchange fromName(String name) {
switch (name) {
case ChangeNowExchange.exchangeName:
return ChangeNowExchange();
return ChangeNowExchange.instance;
case SimpleSwapExchange.exchangeName:
return SimpleSwapExchange();
return SimpleSwapExchange.instance;
case MajesticBankExchange.exchangeName:
return MajesticBankExchange.instance;
default:
throw ArgumentError("Unknown exchange name");
}

View file

@ -1,200 +1,230 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_api.dart';
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:flutter/foundation.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/stack_file_system.dart';
class ExchangeDataLoadingService {
Future<void> loadAll(WidgetRef ref, {Coin? coin}) async {
try {
await Future.wait([
_loadFixedRateMarkets(ref, coin: coin),
_loadChangeNowStandardCurrencies(ref, coin: coin),
loadSimpleswapFixedRateCurrencies(ref),
loadSimpleswapFloatingRateCurrencies(ref),
]);
} catch (e, s) {
Logging.instance.log("ExchangeDataLoadingService.loadAll failed: $e\n$s",
level: LogLevel.Error);
}
ExchangeDataLoadingService._();
static final ExchangeDataLoadingService _instance =
ExchangeDataLoadingService._();
static ExchangeDataLoadingService get instance => _instance;
Isar? _isar;
Isar get isar => _isar!;
Future<void> init() async {
if (_isar != null && isar.isOpen) return;
_isar = await Isar.open(
[
CurrencySchema,
PairSchema,
],
directory: (await StackFileSystem.applicationIsarDirectory()).path,
inspector: kDebugMode,
name: "exchange_cache",
);
}
Future<void> _loadFixedRateMarkets(WidgetRef ref, {Coin? coin}) async {
if (ref.read(changeNowFixedInitialLoadStatusStateProvider.state).state ==
ChangeNowLoadStatus.loading) {
// already in progress so just
return;
}
bool _locked = false;
ref.read(changeNowFixedInitialLoadStatusStateProvider.state).state =
ChangeNowLoadStatus.loading;
Future<void> loadAll() async {
print("LOADINGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG: LOCKED=$_locked");
if (!_locked) {
_locked = true;
print("LOADINGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG");
final time = DateTime.now();
try {
await Future.wait([
_loadFixedRateMarkets(),
_loadChangeNowStandardCurrencies(),
// loadSimpleswapFixedRateCurrencies(ref),
// loadSimpleswapFloatingRateCurrencies(ref),
loadMajesticBankCurrencies(),
]);
final response3 =
await ChangeNowAPI.instance.getAvailableFixedRateMarkets();
if (response3.value != null) {
ref
.read(availableChangeNowCurrenciesProvider)
.updateMarkets(response3.value!);
if (ref.read(exchangeFormStateProvider).market == null) {
String fromTicker = "btc";
String toTicker = "xmr";
if (coin != null) {
fromTicker = coin.ticker.toLowerCase();
}
final matchingMarkets = response3.value!
.where((e) => e.to == toTicker && e.from == fromTicker);
if (matchingMarkets.isNotEmpty) {
await ref
.read(exchangeFormStateProvider)
.updateMarket(matchingMarkets.first, true);
}
print(
"LOADINGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG done in ${DateTime.now().difference(time).inSeconds} seconds");
} catch (e, s) {
Logging.instance.log(
"ExchangeDataLoadingService.loadAll failed: $e\n$s",
level: LogLevel.Error);
}
} else {
Logging.instance.log(
"Failed to load changeNOW fixed rate markets: ${response3.exception?.message}",
level: LogLevel.Error);
ref.read(changeNowFixedInitialLoadStatusStateProvider.state).state =
ChangeNowLoadStatus.failed;
return;
_locked = false;
}
ref.read(changeNowFixedInitialLoadStatusStateProvider.state).state =
ChangeNowLoadStatus.success;
}
Future<void> _loadChangeNowStandardCurrencies(
WidgetRef ref, {
Coin? coin,
}) async {
if (ref
.read(changeNowEstimatedInitialLoadStatusStateProvider.state)
.state ==
ChangeNowLoadStatus.loading) {
// already in progress so just
return;
}
Future<void> _loadFixedRateMarkets() async {
final exchange = ChangeNowExchange.instance;
final responseCurrencies = await exchange.getAllCurrencies(true);
if (responseCurrencies.value != null) {
final responsePairs = await exchange.getAllPairs(true);
ref.read(changeNowEstimatedInitialLoadStatusStateProvider.state).state =
ChangeNowLoadStatus.loading;
if (responsePairs.value != null) {
await isar.writeTxn(() async {
final idsToDelete = await isar.currencies
.where()
.exchangeNameEqualTo(ChangeNowExchange.exchangeName)
.idProperty()
.findAll();
await isar.currencies.deleteAll(idsToDelete);
await isar.currencies.putAll(responseCurrencies.value!);
final response = await ChangeNowAPI.instance.getAvailableCurrencies();
final response2 =
await ChangeNowAPI.instance.getAvailableFloatingRatePairs();
if (response.value != null) {
ref
.read(availableChangeNowCurrenciesProvider)
.updateCurrencies(response.value!);
if (response2.value != null) {
ref
.read(availableChangeNowCurrenciesProvider)
.updateFloatingPairs(response2.value!);
String fromTicker = "btc";
String toTicker = "xmr";
if (coin != null) {
fromTicker = coin.ticker.toLowerCase();
}
if (response.value!.length > 1) {
if (ref.read(exchangeFormStateProvider).from == null) {
if (response.value!
.where((e) => e.ticker == fromTicker)
.isNotEmpty) {
await ref.read(exchangeFormStateProvider).updateFrom(
response.value!.firstWhere((e) => e.ticker == fromTicker),
false);
}
}
if (ref.read(exchangeFormStateProvider).to == null) {
if (response.value!.where((e) => e.ticker == toTicker).isNotEmpty) {
await ref.read(exchangeFormStateProvider).updateTo(
response.value!.firstWhere((e) => e.ticker == toTicker),
false);
}
}
}
final idsToDelete2 = await isar.pairs
.where()
.exchangeNameEqualTo(ChangeNowExchange.exchangeName)
.idProperty()
.findAll();
await isar.pairs.deleteAll(idsToDelete2);
await isar.pairs.putAll(responsePairs.value!);
});
} else {
Logging.instance.log(
"Failed to load changeNOW available floating rate pairs: ${response2.exception?.message}",
"Failed to load changeNOW available fixed rate pairs: ${responsePairs.exception?.message}",
level: LogLevel.Error);
ref.read(changeNowEstimatedInitialLoadStatusStateProvider.state).state =
ChangeNowLoadStatus.failed;
return;
}
} else {
Logging.instance.log(
"Failed to load changeNOW currencies: ${response.exception?.message}",
"Failed to load changeNOW fixed rate currencies: ${responseCurrencies.exception?.message}",
level: LogLevel.Error);
await Future<void>.delayed(const Duration(seconds: 3));
ref.read(changeNowEstimatedInitialLoadStatusStateProvider.state).state =
ChangeNowLoadStatus.failed;
return;
}
ref.read(changeNowEstimatedInitialLoadStatusStateProvider.state).state =
ChangeNowLoadStatus.success;
}
Future<void> loadSimpleswapFloatingRateCurrencies(WidgetRef ref) async {
final exchange = SimpleSwapExchange();
Future<void> _loadChangeNowStandardCurrencies() async {
final exchange = ChangeNowExchange.instance;
final responseCurrencies = await exchange.getAllCurrencies(false);
if (responseCurrencies.value != null) {
ref
.read(availableSimpleswapCurrenciesProvider)
.updateFloatingCurrencies(responseCurrencies.value!);
final responsePairs = await exchange.getAllPairs(false);
if (responsePairs.value != null) {
ref
.read(availableSimpleswapCurrenciesProvider)
.updateFloatingPairs(responsePairs.value!);
await isar.writeTxn(() async {
final idsToDelete = await isar.currencies
.where()
.exchangeNameEqualTo(ChangeNowExchange.exchangeName)
.idProperty()
.findAll();
await isar.currencies.deleteAll(idsToDelete);
await isar.currencies.putAll(responseCurrencies.value!);
final idsToDelete2 = await isar.pairs
.where()
.exchangeNameEqualTo(ChangeNowExchange.exchangeName)
.idProperty()
.findAll();
await isar.pairs.deleteAll(idsToDelete2);
await isar.pairs.putAll(responsePairs.value!);
});
} else {
Logging.instance.log(
"loadSimpleswapFloatingRateCurrencies: $responsePairs",
level: LogLevel.Warning,
);
"Failed to load changeNOW available floating rate pairs: ${responsePairs.exception?.message}",
level: LogLevel.Error);
return;
}
} else {
Logging.instance.log(
"loadSimpleswapFloatingRateCurrencies: $responseCurrencies",
level: LogLevel.Warning,
);
"Failed to load changeNOW currencies: ${responseCurrencies.exception?.message}",
level: LogLevel.Error);
return;
}
}
//
// Future<void> loadSimpleswapFloatingRateCurrencies(WidgetRef ref) async {
// final exchange = SimpleSwapExchange();
// final responseCurrencies = await exchange.getAllCurrencies(false);
//
// if (responseCurrencies.value != null) {
// ref
// .read(availableSimpleswapCurrenciesProvider)
// .updateFloatingCurrencies(responseCurrencies.value!);
//
// final responsePairs = await exchange.getAllPairs(false);
//
// if (responsePairs.value != null) {
// ref
// .read(availableSimpleswapCurrenciesProvider)
// .updateFloatingPairs(responsePairs.value!);
// } else {
// Logging.instance.log(
// "loadSimpleswapFloatingRateCurrencies: $responsePairs",
// level: LogLevel.Warning,
// );
// }
// } else {
// Logging.instance.log(
// "loadSimpleswapFloatingRateCurrencies: $responseCurrencies",
// level: LogLevel.Warning,
// );
// }
// }
//
// Future<void> loadSimpleswapFixedRateCurrencies(WidgetRef ref) async {
// final exchange = SimpleSwapExchange();
// final responseCurrencies = await exchange.getAllCurrencies(true);
//
// if (responseCurrencies.value != null) {
// ref
// .read(availableSimpleswapCurrenciesProvider)
// .updateFixedCurrencies(responseCurrencies.value!);
//
// final responsePairs = await exchange.getAllPairs(true);
//
// if (responsePairs.value != null) {
// ref
// .read(availableSimpleswapCurrenciesProvider)
// .updateFixedPairs(responsePairs.value!);
// } else {
// Logging.instance.log(
// "loadSimpleswapFixedRateCurrencies: $responsePairs",
// level: LogLevel.Warning,
// );
// }
// } else {
// Logging.instance.log(
// "loadSimpleswapFixedRateCurrencies: $responseCurrencies",
// level: LogLevel.Warning,
// );
// }
// }
Future<void> loadSimpleswapFixedRateCurrencies(WidgetRef ref) async {
final exchange = SimpleSwapExchange();
final responseCurrencies = await exchange.getAllCurrencies(true);
Future<void> loadMajesticBankCurrencies() async {
final exchange = MajesticBankExchange.instance;
final responseCurrencies = await exchange.getAllCurrencies(false);
if (responseCurrencies.value != null) {
ref
.read(availableSimpleswapCurrenciesProvider)
.updateFixedCurrencies(responseCurrencies.value!);
final responsePairs = await exchange.getAllPairs(true);
final responsePairs = await exchange.getAllPairs(false);
if (responsePairs.value != null) {
ref
.read(availableSimpleswapCurrenciesProvider)
.updateFixedPairs(responsePairs.value!);
await isar.writeTxn(() async {
final idsToDelete = await isar.currencies
.where()
.exchangeNameEqualTo(MajesticBankExchange.exchangeName)
.idProperty()
.findAll();
await isar.currencies.deleteAll(idsToDelete);
await isar.currencies.putAll(responseCurrencies.value!);
final idsToDelete2 = await isar.pairs
.where()
.exchangeNameEqualTo(MajesticBankExchange.exchangeName)
.idProperty()
.findAll();
await isar.pairs.deleteAll(idsToDelete2);
await isar.pairs.putAll(responsePairs.value!);
});
} else {
Logging.instance.log(
"loadSimpleswapFixedRateCurrencies: $responsePairs",
"loadMajesticBankCurrencies: $responsePairs",
level: LogLevel.Warning,
);
}
} else {
Logging.instance.log(
"loadSimpleswapFixedRateCurrencies: $responseCurrencies",
"loadMajesticBankCurrencies: $responseCurrencies",
level: LogLevel.Warning,
);
}

View file

@ -0,0 +1 @@
class ExchangeService {}

View file

@ -2,18 +2,24 @@ import 'package:decimal/decimal.dart';
import 'package:stackwallet/exceptions/exchange/exchange_exception.dart';
import 'package:stackwallet/exceptions/exchange/majestic_bank/mb_exception.dart';
import 'package:stackwallet/models/exchange/majestic_bank/mb_order.dart';
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
import 'package:stackwallet/models/exchange/response_objects/range.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
import 'package:stackwallet/services/exchange/exchange.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_api.dart';
import 'package:uuid/uuid.dart';
class MajesticBankExchange extends Exchange {
static const exchangeName = "MajesticBank";
MajesticBankExchange._();
static MajesticBankExchange? _instance;
static MajesticBankExchange get instance =>
_instance ??= MajesticBankExchange._();
static const exchangeName = "Majestic Bank";
@override
Future<ExchangeResponse<Trade>> createTrade({
@ -102,15 +108,16 @@ class MajesticBankExchange extends Exchange {
for (final limit in limits) {
final currency = Currency(
exchangeName: MajesticBankExchange.exchangeName,
ticker: limit.currency,
name: limit.currency,
name: limit.currency, // todo: get full coin name
network: "",
image: "",
hasExternalId: false,
isFiat: false,
featured: false,
isStable: false,
supportsFixedRate: true,
supportsEstimatedRate: true,
isAvailable: true,
isStackCoin: Currency.checkIsStackCoin(limit.currency),
);
currencies.add(currency);
}
@ -130,6 +137,7 @@ class MajesticBankExchange extends Exchange {
for (final rate in rates) {
final pair = Pair(
exchangeName: MajesticBankExchange.exchangeName,
from: rate.fromCurrency,
fromNetwork: "",
to: rate.toCurrency,

View file

@ -6,10 +6,10 @@ import 'package:http/http.dart' as http;
import 'package:stackwallet/exceptions/exchange/exchange_exception.dart';
import 'package:stackwallet/external_api_keys.dart';
import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart';
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
import 'package:stackwallet/models/exchange/response_objects/range.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/models/exchange/simpleswap/sp_currency.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
import 'package:stackwallet/utilities/logger.dart';
@ -272,6 +272,7 @@ class SimpleSwapAPI {
for (final to in entry.value as List) {
pairs.add(
Pair(
exchangeName: SimpleSwapExchange.exchangeName,
from: from,
fromNetwork: "",
to: to as String,

View file

@ -1,14 +1,20 @@
import 'package:decimal/decimal.dart';
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
import 'package:stackwallet/models/exchange/response_objects/range.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
import 'package:stackwallet/services/exchange/exchange.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_api.dart';
class SimpleSwapExchange extends Exchange {
SimpleSwapExchange._();
static SimpleSwapExchange? _instance;
static SimpleSwapExchange get instance =>
_instance ??= SimpleSwapExchange._();
static const exchangeName = "SimpleSwap";
@override
@ -47,18 +53,21 @@ class SimpleSwapExchange extends Exchange {
await SimpleSwapAPI.instance.getAllCurrencies(fixedRate: fixedRate);
if (response.value != null) {
final List<Currency> currencies = response.value!
.map((e) => Currency(
ticker: e.symbol,
name: e.name,
network: e.network,
image: e.image,
hasExternalId: e.hasExtraId,
externalId: e.extraId,
isFiat: false,
featured: false,
isStable: false,
supportsFixedRate: fixedRate,
))
.map(
(e) => Currency(
exchangeName: exchangeName,
ticker: e.symbol,
name: e.name,
network: e.network,
image: e.image,
externalId: e.extraId,
isFiat: false,
supportsFixedRate: fixedRate,
supportsEstimatedRate: true,
isAvailable: true,
isStackCoin: Currency.checkIsStackCoin(e.symbol),
),
)
.toList();
return ExchangeResponse<List<Currency>>(
value: currencies,

View file

@ -6,9 +6,7 @@ import 'package:stackwallet/exceptions/electrumx/no_such_transaction.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/models/notification_model.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
import 'package:stackwallet/services/node_service.dart';
import 'package:stackwallet/services/notifications_api.dart';
import 'package:stackwallet/services/trade_service.dart';
@ -16,6 +14,8 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/prefs.dart';
import 'exchange/exchange.dart';
class NotificationsService extends ChangeNotifier {
late NodeService nodeService;
late TradesService tradesService;
@ -196,15 +196,12 @@ class NotificationsService extends ChangeNotifier {
}
final oldTrade = trades.first;
late final ExchangeResponse<Trade> response;
switch (oldTrade.exchangeName) {
case SimpleSwapExchange.exchangeName:
response = await SimpleSwapExchange().updateTrade(oldTrade);
break;
case ChangeNowExchange.exchangeName:
response = await ChangeNowExchange().updateTrade(oldTrade);
break;
default:
return;
try {
final exchange = Exchange.fromName(oldTrade.exchangeName);
response = await exchange.updateTrade(oldTrade);
} catch (_) {
return;
}
if (response.value == null) {

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/buy_view/sub_widgets/crypto_selection_view.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
@ -156,12 +157,18 @@ class _ExchangeTextFieldState extends State<ExchangeTextField> {
),
child: Builder(
builder: (context) {
final image = widget.image;
if (image != null && image.isNotEmpty) {
if (isStackCoin(widget.ticker)) {
return Center(
child: getIconForTicker(
widget.ticker!,
size: 18,
),
);
} else if (widget.image != null &&
widget.image!.isNotEmpty) {
return Center(
child: SvgPicture.network(
image,
widget.image!,
height: 18,
placeholderBuilder: (_) => Container(
width: 18,

View file

@ -699,6 +699,24 @@ class MockPrefs extends _i1.Mock implements _i5.Prefs {
returnValue: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);
@override
_i4.Future<void> saveUserID(String? userId) => (super.noSuchMethod(
Invocation.method(
#saveUserID,
[userId],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
_i4.Future<void> saveSignupEpoch(int? signupEpoch) => (super.noSuchMethod(
Invocation.method(
#saveSignupEpoch,
[signupEpoch],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
void addListener(_i9.VoidCallback? listener) => super.noSuchMethod(
Invocation.method(
#addListener,

View file

@ -420,6 +420,24 @@ class MockPrefs extends _i1.Mock implements _i4.Prefs {
returnValue: _i3.Future<bool>.value(false),
) as _i3.Future<bool>);
@override
_i3.Future<void> saveUserID(String? userId) => (super.noSuchMethod(
Invocation.method(
#saveUserID,
[userId],
),
returnValue: _i3.Future<void>.value(),
returnValueForMissingStub: _i3.Future<void>.value(),
) as _i3.Future<void>);
@override
_i3.Future<void> saveSignupEpoch(int? signupEpoch) => (super.noSuchMethod(
Invocation.method(
#saveSignupEpoch,
[signupEpoch],
),
returnValue: _i3.Future<void>.value(),
returnValueForMissingStub: _i3.Future<void>.value(),
) as _i3.Future<void>);
@override
void addListener(_i8.VoidCallback? listener) => super.noSuchMethod(
Invocation.method(
#addListener,

File diff suppressed because it is too large Load diff

View file

@ -15,17 +15,16 @@ import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart
as _i20;
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart'
as _i21;
import 'package:stackwallet/models/exchange/response_objects/currency.dart'
as _i14;
import 'package:stackwallet/models/exchange/response_objects/estimate.dart'
as _i17;
import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart'
as _i19;
import 'package:stackwallet/models/exchange/response_objects/pair.dart' as _i22;
import 'package:stackwallet/models/exchange/response_objects/range.dart'
as _i16;
import 'package:stackwallet/models/exchange/response_objects/trade.dart'
as _i10;
import 'package:stackwallet/models/isar/exchange_cache/currency.dart' as _i14;
import 'package:stackwallet/models/isar/exchange_cache/pair.dart' as _i22;
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'
as _i5;
import 'package:stackwallet/services/exchange/change_now/change_now_api.dart'
@ -371,6 +370,24 @@ class MockPrefs extends _i1.Mock implements _i3.Prefs {
returnValue: _i7.Future<bool>.value(false),
) as _i7.Future<bool>);
@override
_i7.Future<void> saveUserID(String? userId) => (super.noSuchMethod(
Invocation.method(
#saveUserID,
[userId],
),
returnValue: _i7.Future<void>.value(),
returnValueForMissingStub: _i7.Future<void>.value(),
) as _i7.Future<void>);
@override
_i7.Future<void> saveSignupEpoch(int? signupEpoch) => (super.noSuchMethod(
Invocation.method(
#saveSignupEpoch,
[signupEpoch],
),
returnValue: _i7.Future<void>.value(),
returnValueForMissingStub: _i7.Future<void>.value(),
) as _i7.Future<void>);
@override
void addListener(_i8.VoidCallback? listener) => super.noSuchMethod(
Invocation.method(
#addListener,

View file

@ -5,13 +5,12 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart';
import 'package:stackwallet/exceptions/exchange/exchange_exception.dart';
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart';
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_api.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'change_now_sample_data.dart';
import 'change_now_test.mocks.dart';

View file

@ -573,4 +573,13 @@ class MockTransactionNotificationTracker extends _i1.Mock
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> deleteTransaction(String? txid) => (super.noSuchMethod(
Invocation.method(
#deleteTransaction,
[txid],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
}

View file

@ -573,4 +573,13 @@ class MockTransactionNotificationTracker extends _i1.Mock
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> deleteTransaction(String? txid) => (super.noSuchMethod(
Invocation.method(
#deleteTransaction,
[txid],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
}

View file

@ -573,4 +573,13 @@ class MockTransactionNotificationTracker extends _i1.Mock
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> deleteTransaction(String? txid) => (super.noSuchMethod(
Invocation.method(
#deleteTransaction,
[txid],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
}

View file

@ -573,4 +573,13 @@ class MockTransactionNotificationTracker extends _i1.Mock
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> deleteTransaction(String? txid) => (super.noSuchMethod(
Invocation.method(
#deleteTransaction,
[txid],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
}

View file

@ -573,4 +573,13 @@ class MockTransactionNotificationTracker extends _i1.Mock
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> deleteTransaction(String? txid) => (super.noSuchMethod(
Invocation.method(
#deleteTransaction,
[txid],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
}

View file

@ -573,4 +573,13 @@ class MockTransactionNotificationTracker extends _i1.Mock
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> deleteTransaction(String? txid) => (super.noSuchMethod(
Invocation.method(
#deleteTransaction,
[txid],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
}

View file

@ -30,6 +30,11 @@ class MockSecureStorageWrapper extends _i1.Mock
_i1.throwOnMissingStub(this);
}
@override
_i3.Future<List<String>> get keys => (super.noSuchMethod(
Invocation.getter(#keys),
returnValue: _i3.Future<List<String>>.value(<String>[]),
) as _i3.Future<List<String>>);
@override
_i3.Future<String?> read({
required String? key,

File diff suppressed because it is too large Load diff

View file

@ -604,6 +604,24 @@ class MockPrefs extends _i1.Mock implements _i11.Prefs {
returnValue: _i10.Future<bool>.value(false),
) as _i10.Future<bool>);
@override
_i10.Future<void> saveUserID(String? userId) => (super.noSuchMethod(
Invocation.method(
#saveUserID,
[userId],
),
returnValue: _i10.Future<void>.value(),
returnValueForMissingStub: _i10.Future<void>.value(),
) as _i10.Future<void>);
@override
_i10.Future<void> saveSignupEpoch(int? signupEpoch) => (super.noSuchMethod(
Invocation.method(
#saveSignupEpoch,
[signupEpoch],
),
returnValue: _i10.Future<void>.value(),
returnValueForMissingStub: _i10.Future<void>.value(),
) as _i10.Future<void>);
@override
void addListener(_i12.VoidCallback? listener) => super.noSuchMethod(
Invocation.method(
#addListener,

File diff suppressed because it is too large Load diff

View file

@ -2317,6 +2317,24 @@ class MockPrefs extends _i1.Mock implements _i19.Prefs {
returnValue: _i18.Future<bool>.value(false),
) as _i18.Future<bool>);
@override
_i18.Future<void> saveUserID(String? userId) => (super.noSuchMethod(
Invocation.method(
#saveUserID,
[userId],
),
returnValue: _i18.Future<void>.value(),
returnValueForMissingStub: _i18.Future<void>.value(),
) as _i18.Future<void>);
@override
_i18.Future<void> saveSignupEpoch(int? signupEpoch) => (super.noSuchMethod(
Invocation.method(
#saveSignupEpoch,
[signupEpoch],
),
returnValue: _i18.Future<void>.value(),
returnValueForMissingStub: _i18.Future<void>.value(),
) as _i18.Future<void>);
@override
void addListener(_i20.VoidCallback? listener) => super.noSuchMethod(
Invocation.method(
#addListener,

File diff suppressed because it is too large Load diff