currency loading performance increase

This commit is contained in:
julian 2023-02-07 11:10:35 -06:00
parent 842593d6b2
commit 2366c40dcd

View file

@ -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
); );
}, },
), ),
), );
}),
), ),
], ],
), ),