mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-23 19:05:51 +00:00
currency loading performance increase
This commit is contained in:
parent
842593d6b2
commit
2366c40dcd
1 changed files with 213 additions and 150 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
@ -14,6 +16,7 @@ import 'package:stackwallet/utilities/util.dart';
|
||||||
import 'package:stackwallet/widgets/background.dart';
|
import 'package:stackwallet/widgets/background.dart';
|
||||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
||||||
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
||||||
import 'package:stackwallet/widgets/loading_indicator.dart';
|
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
|
@ -47,14 +50,68 @@ class _ExchangeCurrencySelectionViewState
|
||||||
final _searchFocusNode = FocusNode();
|
final _searchFocusNode = FocusNode();
|
||||||
final isDesktop = Util.isDesktop;
|
final isDesktop = Util.isDesktop;
|
||||||
|
|
||||||
late List<Currency> _currencies;
|
List<Currency> _currencies = [];
|
||||||
late final List<Pair> pairs;
|
List<Pair> pairs = [];
|
||||||
|
|
||||||
List<Pair> getAvailablePairs() {
|
bool _loaded = false;
|
||||||
final filter = ExchangeDataLoadingService.instance.isar.pairs
|
String _searchString = "";
|
||||||
|
|
||||||
|
Future<T> _showUpdatingCurrencies<T>({
|
||||||
|
required Future<T> whileFuture,
|
||||||
|
}) async {
|
||||||
|
unawaited(
|
||||||
|
showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (_) => WillPopScope(
|
||||||
|
onWillPop: () async => false,
|
||||||
|
child: Container(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.overlay
|
||||||
|
.withOpacity(0.6),
|
||||||
|
child: const CustomLoadingOverlay(
|
||||||
|
message: "Loading currencies",
|
||||||
|
eventBus: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await whileFuture;
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.of(context, rootNavigator: isDesktop).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Currency>> _loadCurrencies() async {
|
||||||
|
if (widget.paired == null) {
|
||||||
|
return await _getCurrencies();
|
||||||
|
}
|
||||||
|
|
||||||
|
final pairs = await _loadAvailablePairs();
|
||||||
|
List<Currency> currencies = [];
|
||||||
|
for (final pair in pairs) {
|
||||||
|
final currency =
|
||||||
|
await _getCurrency(widget.willChangeIsSend ? pair.from : pair.to);
|
||||||
|
if (currency != null) {
|
||||||
|
currencies.add(currency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return currencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Currency?> _getCurrency(String ticker) {
|
||||||
|
return ExchangeDataLoadingService.instance.isar.currencies
|
||||||
.where()
|
.where()
|
||||||
.exchangeNameEqualTo(widget.exchangeName)
|
.exchangeNameEqualTo(widget.exchangeName)
|
||||||
.filter()
|
.filter()
|
||||||
|
.tickerEqualTo(ticker, caseSensitive: false)
|
||||||
.group((q) => widget.isFixedRate
|
.group((q) => widget.isFixedRate
|
||||||
? q
|
? q
|
||||||
.rateTypeEqualTo(SupportedRateType.both)
|
.rateTypeEqualTo(SupportedRateType.both)
|
||||||
|
@ -63,30 +120,15 @@ class _ExchangeCurrencySelectionViewState
|
||||||
: q
|
: q
|
||||||
.rateTypeEqualTo(SupportedRateType.both)
|
.rateTypeEqualTo(SupportedRateType.both)
|
||||||
.or()
|
.or()
|
||||||
.rateTypeEqualTo(SupportedRateType.estimated));
|
.rateTypeEqualTo(SupportedRateType.estimated))
|
||||||
|
.findFirst();
|
||||||
if (widget.paired != null) {
|
|
||||||
return filter
|
|
||||||
.and()
|
|
||||||
.group((q) => widget.willChangeIsSend
|
|
||||||
? q.toEqualTo(widget.paired!.ticker, caseSensitive: false)
|
|
||||||
: q.fromEqualTo(widget.paired!.ticker, caseSensitive: false))
|
|
||||||
.findAllSync();
|
|
||||||
} else {
|
|
||||||
return filter.findAllSync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter(String text) {
|
Future<List<Pair>> _loadAvailablePairs() {
|
||||||
setState(() {
|
final query = ExchangeDataLoadingService.instance.isar.pairs
|
||||||
final query = ExchangeDataLoadingService.instance.isar.currencies
|
|
||||||
.where()
|
.where()
|
||||||
.exchangeNameEqualTo(widget.exchangeName)
|
.exchangeNameEqualTo(widget.exchangeName)
|
||||||
.filter()
|
.filter()
|
||||||
.anyOf<String, Currency>(
|
|
||||||
pairs.map((e) => widget.willChangeIsSend ? e.to : e.from),
|
|
||||||
(q, ticker) => q.tickerEqualTo(ticker),
|
|
||||||
)
|
|
||||||
.group((q) => widget.isFixedRate
|
.group((q) => widget.isFixedRate
|
||||||
? q
|
? q
|
||||||
.rateTypeEqualTo(SupportedRateType.both)
|
.rateTypeEqualTo(SupportedRateType.both)
|
||||||
|
@ -97,31 +139,19 @@ class _ExchangeCurrencySelectionViewState
|
||||||
.or()
|
.or()
|
||||||
.rateTypeEqualTo(SupportedRateType.estimated))
|
.rateTypeEqualTo(SupportedRateType.estimated))
|
||||||
.and()
|
.and()
|
||||||
.group((q) => q
|
.group((q) => widget.willChangeIsSend
|
||||||
.nameContains(text, caseSensitive: false)
|
? q.toEqualTo(widget.paired!.ticker, caseSensitive: false)
|
||||||
.or()
|
: q.fromEqualTo(widget.paired!.ticker, caseSensitive: false));
|
||||||
.tickerContains(text, caseSensitive: false));
|
|
||||||
|
|
||||||
if (widget.paired != null) {
|
if (widget.willChangeIsSend) {
|
||||||
_currencies = query
|
return query.sortByFrom().findAll();
|
||||||
.and()
|
|
||||||
.not()
|
|
||||||
.tickerEqualTo(widget.paired!.ticker)
|
|
||||||
.sortByIsStackCoin()
|
|
||||||
.thenByTicker()
|
|
||||||
.findAllSync();
|
|
||||||
} else {
|
} else {
|
||||||
_currencies = query.sortByIsStackCoin().thenByTicker().findAllSync();
|
return query.sortByTo().findAll();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
Future<List<Currency>> _getCurrencies() async {
|
||||||
void initState() {
|
return ExchangeDataLoadingService.instance.isar.currencies
|
||||||
_searchController = TextEditingController();
|
|
||||||
pairs = getAvailablePairs();
|
|
||||||
|
|
||||||
final query = ExchangeDataLoadingService.instance.isar.currencies
|
|
||||||
.where()
|
.where()
|
||||||
.exchangeNameEqualTo(widget.exchangeName)
|
.exchangeNameEqualTo(widget.exchangeName)
|
||||||
.filter()
|
.filter()
|
||||||
|
@ -133,20 +163,37 @@ class _ExchangeCurrencySelectionViewState
|
||||||
: q
|
: q
|
||||||
.rateTypeEqualTo(SupportedRateType.both)
|
.rateTypeEqualTo(SupportedRateType.both)
|
||||||
.or()
|
.or()
|
||||||
.rateTypeEqualTo(SupportedRateType.estimated));
|
.rateTypeEqualTo(SupportedRateType.estimated))
|
||||||
|
|
||||||
if (widget.paired != null) {
|
|
||||||
_currencies = query
|
|
||||||
.and()
|
|
||||||
.not()
|
|
||||||
.tickerEqualTo(widget.paired!.ticker)
|
|
||||||
.sortByIsStackCoin()
|
.sortByIsStackCoin()
|
||||||
.thenByTicker()
|
.thenByName()
|
||||||
.findAllSync();
|
.findAll();
|
||||||
} else {
|
|
||||||
_currencies = query.sortByIsStackCoin().thenByTicker().findAllSync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Currency> filter(String text) {
|
||||||
|
if (text.isEmpty) {
|
||||||
|
return _currencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget.paired == null) {
|
||||||
|
return _currencies
|
||||||
|
.where((e) =>
|
||||||
|
e.name.toLowerCase().contains(text.toLowerCase()) ||
|
||||||
|
e.ticker.toLowerCase().contains(text.toLowerCase()))
|
||||||
|
.toList(growable: false);
|
||||||
|
} else {
|
||||||
|
return _currencies
|
||||||
|
.where((e) =>
|
||||||
|
e.ticker.toLowerCase() != widget.paired!.ticker.toLowerCase() &&
|
||||||
|
(e.name.toLowerCase().contains(text.toLowerCase()) ||
|
||||||
|
e.ticker.toLowerCase().contains(text.toLowerCase())))
|
||||||
|
.toList(growable: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_searchController = TextEditingController();
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +206,15 @@ class _ExchangeCurrencySelectionViewState
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
if (!_loaded) {
|
||||||
|
_loaded = true;
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||||
|
_currencies =
|
||||||
|
await _showUpdatingCurrencies(whileFuture: _loadCurrencies());
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return ConditionalParent(
|
return ConditionalParent(
|
||||||
condition: !isDesktop,
|
condition: !isDesktop,
|
||||||
builder: (child) {
|
builder: (child) {
|
||||||
|
@ -211,7 +267,7 @@ class _ExchangeCurrencySelectionViewState
|
||||||
enableSuggestions: !isDesktop,
|
enableSuggestions: !isDesktop,
|
||||||
controller: _searchController,
|
controller: _searchController,
|
||||||
focusNode: _searchFocusNode,
|
focusNode: _searchFocusNode,
|
||||||
onChanged: filter,
|
onChanged: (value) => setState(() => _searchString = value),
|
||||||
style: STextStyles.field(context),
|
style: STextStyles.field(context),
|
||||||
decoration: standardInputDecoration(
|
decoration: standardInputDecoration(
|
||||||
"Search",
|
"Search",
|
||||||
|
@ -241,8 +297,8 @@ class _ExchangeCurrencySelectionViewState
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
setState(() {
|
setState(() {
|
||||||
_searchController.text = "";
|
_searchController.text = "";
|
||||||
|
_searchString = "";
|
||||||
});
|
});
|
||||||
filter("");
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -265,8 +321,12 @@ class _ExchangeCurrencySelectionViewState
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Builder(builder: (context) {
|
child: Builder(builder: (context) {
|
||||||
final items = _currencies
|
final coins = Coin.values.where((e) =>
|
||||||
.where((e) => Coin.values
|
e.ticker.toLowerCase() !=
|
||||||
|
widget.paired?.ticker.toLowerCase());
|
||||||
|
|
||||||
|
final items = filter(_searchString)
|
||||||
|
.where((e) => coins
|
||||||
.where((coin) =>
|
.where((coin) =>
|
||||||
coin.ticker.toLowerCase() == e.ticker.toLowerCase())
|
coin.ticker.toLowerCase() == e.ticker.toLowerCase())
|
||||||
.isNotEmpty)
|
.isNotEmpty)
|
||||||
|
@ -358,20 +418,22 @@ class _ExchangeCurrencySelectionViewState
|
||||||
height: 12,
|
height: 12,
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: RoundedWhiteContainer(
|
child: Builder(builder: (context) {
|
||||||
|
final filtered = filter(_searchString);
|
||||||
|
return RoundedWhiteContainer(
|
||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
primary: isDesktop ? false : null,
|
primary: isDesktop ? false : null,
|
||||||
itemCount: _currencies.length,
|
itemCount: filtered.length,
|
||||||
itemBuilder: (builderContext, index) {
|
itemBuilder: (builderContext, index) {
|
||||||
final bool hasImageUrl =
|
final bool hasImageUrl =
|
||||||
_currencies[index].image.startsWith("http");
|
filtered[index].image.startsWith("http");
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).pop(_currencies[index]);
|
Navigator.of(context).pop(filtered[index]);
|
||||||
},
|
},
|
||||||
child: RoundedWhiteContainer(
|
child: RoundedWhiteContainer(
|
||||||
child: Row(
|
child: Row(
|
||||||
|
@ -379,14 +441,14 @@ class _ExchangeCurrencySelectionViewState
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 24,
|
width: 24,
|
||||||
height: 24,
|
height: 24,
|
||||||
child: isStackCoin(_currencies[index].ticker)
|
child: isStackCoin(filtered[index].ticker)
|
||||||
? getIconForTicker(
|
? getIconForTicker(
|
||||||
_currencies[index].ticker,
|
filtered[index].ticker,
|
||||||
size: 24,
|
size: 24,
|
||||||
)
|
)
|
||||||
: hasImageUrl
|
: hasImageUrl
|
||||||
? SvgPicture.network(
|
? SvgPicture.network(
|
||||||
_currencies[index].image,
|
filtered[index].image,
|
||||||
width: 24,
|
width: 24,
|
||||||
height: 24,
|
height: 24,
|
||||||
placeholderBuilder: (_) =>
|
placeholderBuilder: (_) =>
|
||||||
|
@ -405,14 +467,14 @@ class _ExchangeCurrencySelectionViewState
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
_currencies[index].name,
|
filtered[index].name,
|
||||||
style: STextStyles.largeMedium14(context),
|
style: STextStyles.largeMedium14(context),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 2,
|
height: 2,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
_currencies[index].ticker.toUpperCase(),
|
filtered[index].ticker.toUpperCase(),
|
||||||
style: STextStyles.smallMed12(context)
|
style: STextStyles.smallMed12(context)
|
||||||
.copyWith(
|
.copyWith(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
|
@ -430,7 +492,8 @@ class _ExchangeCurrencySelectionViewState
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue