Skip to content

Commit b6b63bc

Browse files
committed
fix: swap issues
1 parent f67940a commit b6b63bc

File tree

11 files changed

+236
-232
lines changed

11 files changed

+236
-232
lines changed

lib/app_config.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ abstract class AppConfig {
2323

2424
static List<CryptoCurrency> get coins => _supportedCoins;
2525

26-
static ({String from, String to}) get swapDefaults => _swapDefaults;
26+
static ({String from, String fromFuzzyNet, String to, String toFuzzyNet})
27+
get swapDefaults => _swapDefaults;
2728

2829
static bool get isSingleCoinApp => coins.length == 1;
2930

lib/models/exchange/aggregate_currency.dart

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,29 @@ class AggregateCurrency {
4242

4343
bool get isStackCoin => _map.values.first!.isStackCoin;
4444

45+
String get fuzzyNet => _map.values.first!.getFuzzyNet();
46+
4547
@override
4648
String toString() {
4749
String str = "AggregateCurrency: {";
4850
for (final key in _map.keys) {
49-
str += " $key: ${_map[key]},";
51+
str += "\n $key: ${_map[key]},";
5052
}
51-
str += " }";
53+
str += "\n}";
5254
return str;
5355
}
56+
57+
@override
58+
bool operator ==(Object other) {
59+
return other is AggregateCurrency &&
60+
other.ticker == ticker &&
61+
other._map.isNotEmpty &&
62+
other._map.length == _map.length &&
63+
other._map.values.first!.getFuzzyNet() ==
64+
_map.values.first!.getFuzzyNet();
65+
}
66+
67+
@override
68+
int get hashCode =>
69+
Object.hash(ticker, _map.values.first!.getFuzzyNet(), _map.length);
5470
}

lib/models/exchange/change_now/estimated_exchange_amount.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class EstimatedExchangeAmount {
2929
final String? rateId;
3030

3131
/// Date and time before which the estimated amount is valid if using `rateId`.
32-
final DateTime validUntil;
32+
final DateTime? validUntil;
3333

3434
/// Dash-separated min and max estimated time in minutes.
3535
final String? transactionSpeedForecast;
@@ -87,7 +87,7 @@ class EstimatedExchangeAmount {
8787
flow: _parseFlow(json["flow"] as String),
8888
type: _parseType(json["type"] as String),
8989
rateId: json["rateId"] as String?,
90-
validUntil: DateTime.parse(json["validUntil"] as String),
90+
validUntil: DateTime.tryParse(json["validUntil"] as String? ?? ""),
9191
transactionSpeedForecast: json["transactionSpeedForecast"] as String?,
9292
warningMessage: json["warningMessage"] as String?,
9393
depositFee: Decimal.parse(json["depositFee"].toString()),
@@ -108,7 +108,7 @@ class EstimatedExchangeAmount {
108108
"flow": flow.name.replaceAll("fixedRate", "fixed-rate"),
109109
"type": type.name,
110110
"rateId": rateId,
111-
"validUntil": validUntil.toIso8601String(),
111+
"validUntil": validUntil?.toIso8601String(),
112112
"transactionSpeedForecast": transactionSpeedForecast,
113113
"warningMessage": warningMessage,
114114
"depositFee": depositFee.toString(),

lib/models/isar/exchange_cache/currency.dart

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
import 'package:isar/isar.dart';
1212

1313
import '../../../app_config.dart';
14+
import '../../../services/exchange/change_now/change_now_exchange.dart';
15+
import '../../../services/exchange/exchange.dart';
16+
import '../../../services/exchange/majestic_bank/majestic_bank_exchange.dart';
17+
import '../../../services/exchange/nanswap/nanswap_exchange.dart';
18+
import '../../../services/exchange/trocador/trocador_exchange.dart';
1419
import 'pair.dart';
1520

1621
part 'currency.g.dart';
@@ -23,12 +28,7 @@ class Currency {
2328
final String exchangeName;
2429

2530
/// Currency ticker
26-
@Index(
27-
composite: [
28-
CompositeIndex("exchangeName"),
29-
CompositeIndex("name"),
30-
],
31-
)
31+
@Index(composite: [CompositeIndex("exchangeName"), CompositeIndex("name")])
3232
final String ticker;
3333

3434
/// Currency name
@@ -68,6 +68,33 @@ class Currency {
6868
rateType == SupportedRateType.estimated ||
6969
rateType == SupportedRateType.both;
7070

71+
// used to group coins across providers
72+
@ignore
73+
String? _fuzzyCache;
74+
String getFuzzyNet() {
75+
return _fuzzyCache ??= switch (Exchange.fromName(
76+
exchangeName,
77+
).runtimeType) {
78+
// already lower case ticker basically
79+
const (ChangeNowExchange) => network,
80+
81+
// not used at the time being
82+
// case const (SimpleSwapExchange):
83+
84+
// currently a hardcoded of coins so we can just
85+
const (MajesticBankExchange) => ticker.toLowerCase(),
86+
87+
const (TrocadorExchange) =>
88+
(network == "Mainnet" ? ticker.toLowerCase() : network),
89+
90+
// only a few coins and `network` is the ticker
91+
const (NanswapExchange) =>
92+
network.isNotEmpty ? network.toLowerCase() : ticker.toLowerCase(),
93+
94+
_ => throw Exception("Unknown exchange: $exchangeName"),
95+
};
96+
}
97+
7198
Currency({
7299
required this.exchangeName,
73100
required this.ticker,

lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart

Lines changed: 71 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@ import 'dart:async';
1313
import 'package:flutter/material.dart';
1414
import 'package:flutter_svg/svg.dart';
1515
import 'package:isar/isar.dart';
16+
import 'package:tuple/tuple.dart';
1617

1718
import '../../../app_config.dart';
19+
import '../../../models/exchange/aggregate_currency.dart';
1820
import '../../../models/isar/exchange_cache/currency.dart';
1921
import '../../../models/isar/exchange_cache/pair.dart';
2022
import '../../../services/exchange/exchange.dart';
2123
import '../../../services/exchange/exchange_data_loading_service.dart';
22-
import '../../../services/exchange/majestic_bank/majestic_bank_exchange.dart';
23-
import '../../../services/exchange/nanswap/nanswap_exchange.dart';
24-
import '../../../services/exchange/trocador/trocador_exchange.dart';
2524
import '../../../themes/stack_colors.dart';
2625
import '../../../utilities/assets.dart';
2726
import '../../../utilities/constants.dart';
27+
import '../../../utilities/logger.dart';
2828
import '../../../utilities/prefs.dart';
2929
import '../../../utilities/text_styles.dart';
3030
import '../../../utilities/util.dart';
@@ -42,14 +42,12 @@ import '../../buy_view/sub_widgets/crypto_selection_view.dart';
4242
class ExchangeCurrencySelectionView extends StatefulWidget {
4343
const ExchangeCurrencySelectionView({
4444
super.key,
45-
required this.willChangeTicker,
46-
required this.pairedTicker,
45+
required this.pairedCurrency,
4746
required this.isFixedRate,
4847
required this.willChangeIsSend,
4948
});
5049

51-
final String? willChangeTicker;
52-
final String? pairedTicker;
50+
final AggregateCurrency? pairedCurrency;
5351
final bool isFixedRate;
5452
final bool willChangeIsSend;
5553

@@ -64,7 +62,7 @@ class _ExchangeCurrencySelectionViewState
6462
final _searchFocusNode = FocusNode();
6563
final isDesktop = Util.isDesktop;
6664

67-
List<Currency> _currencies = [];
65+
List<AggregateCurrency> _currencies = [];
6866

6967
bool _loaded = false;
7068
String _searchString = "";
@@ -99,26 +97,7 @@ class _ExchangeCurrencySelectionViewState
9997
return result;
10098
}
10199

102-
Future<List<Currency>> _loadCurrencies() async {
103-
if (widget.pairedTicker == null) {
104-
return await _getCurrencies();
105-
}
106-
await ExchangeDataLoadingService.instance.initDB();
107-
final List<Currency> currencies =
108-
await ExchangeDataLoadingService.instance.isar.currencies
109-
.where()
110-
.filter()
111-
.exchangeNameEqualTo(MajesticBankExchange.exchangeName)
112-
.or()
113-
.exchangeNameStartsWith(TrocadorExchange.exchangeName)
114-
.or()
115-
.exchangeNameStartsWith(NanswapExchange.exchangeName)
116-
.findAll();
117-
118-
return _getDistinctCurrenciesFrom(currencies);
119-
}
120-
121-
Future<List<Currency>> _getCurrencies() async {
100+
Future<List<AggregateCurrency>> _loadCurrencies() async {
122101
await ExchangeDataLoadingService.instance.initDB();
123102
final currencies =
124103
await ExchangeDataLoadingService.instance.isar.currencies
@@ -154,53 +133,78 @@ class _ExchangeCurrencySelectionViewState
154133
}
155134
}
156135

157-
return _getDistinctCurrenciesFrom(currencies);
136+
return await _getDistinctCurrenciesFrom(currencies);
158137
}
159138

160-
List<Currency> _getDistinctCurrenciesFrom(List<Currency> currencies) {
161-
final List<Currency> distinctCurrencies = [];
139+
Future<List<AggregateCurrency>> _getDistinctCurrenciesFrom(
140+
List<Currency> currencies,
141+
) async {
142+
final Map<String, List<Currency>> groups = {};
143+
162144
for (final currency in currencies) {
163-
if (!distinctCurrencies.any(
164-
(e) => e.ticker.toLowerCase() == currency.ticker.toLowerCase(),
165-
)) {
166-
distinctCurrencies.add(currency);
167-
}
145+
final key = '${currency.ticker.toLowerCase()}|${currency.getFuzzyNet()}';
146+
147+
groups.putIfAbsent(key, () => []).add(currency);
168148
}
169-
return distinctCurrencies;
170-
}
171149

172-
List<Currency> filter(String text) {
173-
if (widget.pairedTicker == null) {
174-
if (text.isEmpty) {
175-
return _currencies;
176-
}
150+
final Set<AggregateCurrency> results = {};
151+
152+
for (final group in groups.values) {
153+
final items = group
154+
.map((e) => Tuple2(e.exchangeName, e))
155+
.toList(growable: false);
156+
157+
results.add(AggregateCurrency(exchangeCurrencyPairs: items));
158+
}
159+
160+
if (widget.pairedCurrency != null) {
161+
results.remove(widget.pairedCurrency);
162+
}
177163

178-
return _currencies
179-
.where(
180-
(e) =>
181-
e.name.toLowerCase().contains(text.toLowerCase()) ||
182-
e.ticker.toLowerCase().contains(text.toLowerCase()),
183-
)
184-
.toList();
185-
} else {
186-
if (text.isEmpty) {
187-
return _currencies
164+
final walletCoins =
165+
results
188166
.where(
189-
(e) =>
190-
e.ticker.toLowerCase() != widget.pairedTicker!.toLowerCase(),
167+
(currency) =>
168+
AppConfig.coins
169+
.where(
170+
(coin) =>
171+
coin.ticker.toLowerCase() ==
172+
currency.ticker.toLowerCase() &&
173+
currency.fuzzyNet == coin.ticker.toLowerCase(),
174+
)
175+
.isNotEmpty,
191176
)
192177
.toList();
193-
}
194178

195-
return _currencies
196-
.where(
197-
(e) =>
198-
e.ticker.toLowerCase() != widget.pairedTicker!.toLowerCase() &&
199-
(e.name.toLowerCase().contains(text.toLowerCase()) ||
200-
e.ticker.toLowerCase().contains(text.toLowerCase())),
201-
)
202-
.toList();
179+
final list = results.toList();
180+
181+
// sort alphabetically by name
182+
list.sort((a, b) => a.name.compareTo(b.name));
183+
184+
// reverse sort walletCoins to prepare for next step
185+
walletCoins.sort((a, b) => b.name.compareTo(a.name));
186+
187+
// insert wallet coins at beginning
188+
for (final c in walletCoins) {
189+
list.remove(c);
190+
list.insert(0, c);
191+
}
192+
193+
return list;
194+
}
195+
196+
List<AggregateCurrency> filter(String text) {
197+
if (text.isEmpty) {
198+
return _currencies.toList();
203199
}
200+
201+
return _currencies
202+
.where(
203+
(e) =>
204+
e.name.toLowerCase().contains(text.toLowerCase()) ||
205+
e.ticker.toLowerCase().contains(text.toLowerCase()),
206+
)
207+
.toList();
204208
}
205209

206210
@override
@@ -325,40 +329,8 @@ class _ExchangeCurrencySelectionViewState
325329
Flexible(
326330
child: Builder(
327331
builder: (context) {
328-
final coins = AppConfig.coins.where(
329-
(e) =>
330-
e.ticker.toLowerCase() !=
331-
widget.pairedTicker?.toLowerCase(),
332-
);
333-
334332
final items = filter(_searchString);
335333

336-
final walletCoins =
337-
items
338-
.where(
339-
(currency) =>
340-
coins
341-
.where(
342-
(coin) =>
343-
coin.ticker.toLowerCase() ==
344-
currency.ticker.toLowerCase(),
345-
)
346-
.isNotEmpty,
347-
)
348-
.toList();
349-
350-
// sort alphabetically by name
351-
items.sort((a, b) => a.name.compareTo(b.name));
352-
353-
// reverse sort walletCoins to prepare for next step
354-
walletCoins.sort((a, b) => b.name.compareTo(a.name));
355-
356-
// insert wallet coins at beginning
357-
for (final c in walletCoins) {
358-
items.remove(c);
359-
items.insert(0, c);
360-
}
361-
362334
return RoundedWhiteContainer(
363335
padding: const EdgeInsets.all(0),
364336
child: ListView.builder(
@@ -373,7 +345,9 @@ class _ExchangeCurrencySelectionViewState
373345
padding: const EdgeInsets.symmetric(vertical: 4),
374346
child: GestureDetector(
375347
onTap: () {
376-
Navigator.of(context).pop(items[index]);
348+
final selected = items[index];
349+
Logging.instance.d("swap selected: $selected");
350+
Navigator.of(context).pop(selected);
377351
},
378352
child: RoundedWhiteContainer(
379353
child: Row(

0 commit comments

Comments
 (0)