mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-16 17:27:39 +00:00
WIP refactor exchange to use isar as cache instead of in memory using riverpod
This commit is contained in:
parent
585a684ecc
commit
1455808d7a
56 changed files with 11786 additions and 4136 deletions
|
@ -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;
|
||||
|
|
|
@ -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?;
|
||||
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 = [];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
2070
lib/models/isar/exchange_cache/currency.g.dart
Normal file
2070
lib/models/isar/exchange_cache/currency.g.dart
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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,
|
1565
lib/models/isar/exchange_cache/pair.g.dart
Normal file
1565
lib/models/isar/exchange_cache/pair.g.dart
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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');
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
|
@ -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
|
@ -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!,
|
||||
|
|
|
@ -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>()!
|
||||
|
|
|
@ -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);
|
||||
// }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(),
|
||||
);
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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(
|
||||
|
|
389
lib/services/exchange/TMP.dart
Normal file
389
lib/services/exchange/TMP.dart
Normal 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();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// }
|
|
@ -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: "",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
|
1
lib/services/exchange/exchange_service.dart
Normal file
1
lib/services/exchange/exchange_service.dart
Normal file
|
@ -0,0 +1 @@
|
|||
class ExchangeService {}
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
@ -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,
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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>);
|
||||
}
|
||||
|
|
|
@ -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>);
|
||||
}
|
||||
|
|
|
@ -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>);
|
||||
}
|
||||
|
|
|
@ -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>);
|
||||
}
|
||||
|
|
|
@ -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>);
|
||||
}
|
||||
|
|
|
@ -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>);
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue