mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-02-03 03:36:42 +00:00
add loading screen if not exchange data cache exists while waiting for it to be populated for the first time. Added checks for incognito mode
This commit is contained in:
parent
b9d006b6ea
commit
8206972309
5 changed files with 468 additions and 268 deletions
|
@ -17,6 +17,7 @@ import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
import 'package:keyboard_dismisser/keyboard_dismisser.dart';
|
import 'package:keyboard_dismisser/keyboard_dismisser.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:stackwallet/db/main_db.dart';
|
||||||
import 'package:stackwallet/hive/db.dart';
|
import 'package:stackwallet/hive/db.dart';
|
||||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.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/change_now/exchange_transaction_status.dart';
|
||||||
|
@ -65,8 +66,6 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||||
import 'package:stackwallet/utilities/util.dart';
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
import 'package:window_size/window_size.dart';
|
import 'package:window_size/window_size.dart';
|
||||||
|
|
||||||
import 'db/main_db.dart';
|
|
||||||
|
|
||||||
final openedFromSWBFileStringStateProvider =
|
final openedFromSWBFileStringStateProvider =
|
||||||
StateProvider<String?>((ref) => null);
|
StateProvider<String?>((ref) => null);
|
||||||
|
|
||||||
|
@ -290,10 +289,6 @@ 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
|
// TODO: this should probably run unawaited. Keep commented out for now as proper community nodes ui hasn't been implemented yet
|
||||||
// unawaited(_nodeService.updateCommunityNodes());
|
// unawaited(_nodeService.updateCommunityNodes());
|
||||||
|
|
||||||
print("================================================");
|
|
||||||
print("${ref.read(prefsChangeNotifierProvider).externalCalls}");
|
|
||||||
print("${await ref.read(prefsChangeNotifierProvider).isExternalCallsSet()}");
|
|
||||||
print("================================================");
|
|
||||||
// run without awaiting
|
// run without awaiting
|
||||||
if (ref.read(prefsChangeNotifierProvider).externalCalls &&
|
if (ref.read(prefsChangeNotifierProvider).externalCalls &&
|
||||||
await ref.read(prefsChangeNotifierProvider).isExternalCallsSet()) {
|
await ref.read(prefsChangeNotifierProvider).isExternalCallsSet()) {
|
||||||
|
|
|
@ -8,9 +8,12 @@ import 'package:stackwallet/pages/exchange_view/exchange_form.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/trade_details_view.dart';
|
import 'package:stackwallet/pages/exchange_view/trade_details_view.dart';
|
||||||
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
||||||
import 'package:stackwallet/providers/providers.dart';
|
import 'package:stackwallet/providers/providers.dart';
|
||||||
|
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
|
||||||
import 'package:stackwallet/utilities/constants.dart';
|
import 'package:stackwallet/utilities/constants.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||||
|
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||||
|
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
||||||
import 'package:stackwallet/widgets/trade_card.dart';
|
import 'package:stackwallet/widgets/trade_card.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
|
@ -24,8 +27,38 @@ class ExchangeView extends ConsumerStatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
|
bool _initialCachePopulationUnderway = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
if (!ref.read(prefsChangeNotifierProvider).externalCalls) {
|
||||||
|
if (ExchangeDataLoadingService.currentCacheVersion <
|
||||||
|
ExchangeDataLoadingService.cacheVersion) {
|
||||||
|
_initialCachePopulationUnderway = true;
|
||||||
|
ExchangeDataLoadingService.instance.onLoadingComplete = () {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||||
|
setState(() {
|
||||||
|
_initialCachePopulationUnderway = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ExchangeDataLoadingService.instance
|
||||||
|
.init()
|
||||||
|
.then((_) => ExchangeDataLoadingService.instance.loadAll());
|
||||||
|
} else if (ExchangeDataLoadingService.instance.isLoading &&
|
||||||
|
ExchangeDataLoadingService.currentCacheVersion <
|
||||||
|
ExchangeDataLoadingService.cacheVersion) {
|
||||||
|
_initialCachePopulationUnderway = true;
|
||||||
|
ExchangeDataLoadingService.instance.onLoadingComplete = () {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||||
|
setState(() {
|
||||||
|
_initialCachePopulationUnderway = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,154 +71,176 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
debugPrint("BUILD: $runtimeType");
|
debugPrint("BUILD: $runtimeType");
|
||||||
|
|
||||||
return SafeArea(
|
return ConditionalParent(
|
||||||
child: NestedScrollView(
|
condition: _initialCachePopulationUnderway,
|
||||||
floatHeaderSlivers: true,
|
builder: (child) {
|
||||||
headerSliverBuilder: (context, innerBoxIsScrolled) {
|
return Stack(
|
||||||
return [
|
children: [
|
||||||
SliverOverlapAbsorber(
|
child,
|
||||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
Material(
|
||||||
sliver: const SliverToBoxAdapter(
|
color: Theme.of(context)
|
||||||
child: Padding(
|
.extension<StackColors>()!
|
||||||
padding: EdgeInsets.only(
|
.overlay
|
||||||
left: 16,
|
.withOpacity(0.6),
|
||||||
right: 16,
|
child: const CustomLoadingOverlay(
|
||||||
top: 16,
|
message: "Updating exchange data",
|
||||||
),
|
subMessage: "This could take a few minutes",
|
||||||
child: ExchangeForm(),
|
eventBus: null,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
];
|
],
|
||||||
},
|
);
|
||||||
body: Builder(
|
},
|
||||||
builder: (buildContext) {
|
child: SafeArea(
|
||||||
final trades = ref
|
child: NestedScrollView(
|
||||||
.watch(tradesServiceProvider.select((value) => value.trades));
|
floatHeaderSlivers: true,
|
||||||
final tradeCount = trades.length;
|
headerSliverBuilder: (context, innerBoxIsScrolled) {
|
||||||
final hasHistory = tradeCount > 0;
|
return [
|
||||||
|
SliverOverlapAbsorber(
|
||||||
return Padding(
|
handle:
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
child: CustomScrollView(
|
sliver: const SliverToBoxAdapter(
|
||||||
slivers: [
|
child: Padding(
|
||||||
SliverOverlapInjector(
|
padding: EdgeInsets.only(
|
||||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
|
left: 16,
|
||||||
buildContext,
|
right: 16,
|
||||||
|
top: 16,
|
||||||
),
|
),
|
||||||
|
child: ExchangeForm(),
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
),
|
||||||
child: Padding(
|
)
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
];
|
||||||
child: Column(
|
},
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
body: Builder(
|
||||||
children: [
|
builder: (buildContext) {
|
||||||
const SizedBox(
|
final trades = ref
|
||||||
height: 12,
|
.watch(tradesServiceProvider.select((value) => value.trades));
|
||||||
),
|
final tradeCount = trades.length;
|
||||||
Text(
|
final hasHistory = tradeCount > 0;
|
||||||
"Trades",
|
|
||||||
style: STextStyles.itemSubtitle(context).copyWith(
|
return Padding(
|
||||||
color: Theme.of(context)
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
.extension<StackColors>()!
|
child: CustomScrollView(
|
||||||
.textDark3,
|
slivers: [
|
||||||
),
|
SliverOverlapInjector(
|
||||||
),
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
|
||||||
const SizedBox(
|
buildContext,
|
||||||
height: 12,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
if (hasHistory)
|
|
||||||
SliverList(
|
|
||||||
delegate: SliverChildBuilderDelegate((context, index) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(4),
|
|
||||||
child: TradeCard(
|
|
||||||
key: Key("tradeCard_${trades[index].uuid}"),
|
|
||||||
trade: trades[index],
|
|
||||||
onTap: () async {
|
|
||||||
final String tradeId = trades[index].tradeId;
|
|
||||||
|
|
||||||
final lookup = ref
|
|
||||||
.read(tradeSentFromStackLookupProvider)
|
|
||||||
.all;
|
|
||||||
|
|
||||||
//todo: check if print needed
|
|
||||||
// debugPrint("ALL: $lookup");
|
|
||||||
|
|
||||||
final String? txid = ref
|
|
||||||
.read(tradeSentFromStackLookupProvider)
|
|
||||||
.getTxidForTradeId(tradeId);
|
|
||||||
final List<String>? walletIds = ref
|
|
||||||
.read(tradeSentFromStackLookupProvider)
|
|
||||||
.getWalletIdsForTradeId(tradeId);
|
|
||||||
|
|
||||||
if (txid != null &&
|
|
||||||
walletIds != null &&
|
|
||||||
walletIds.isNotEmpty) {
|
|
||||||
final manager = ref
|
|
||||||
.read(walletsChangeNotifierProvider)
|
|
||||||
.getManager(walletIds.first);
|
|
||||||
|
|
||||||
//todo: check if print needed
|
|
||||||
// debugPrint("name: ${manager.walletName}");
|
|
||||||
|
|
||||||
final tx = await MainDB.instance
|
|
||||||
.getTransactions(walletIds.first)
|
|
||||||
.filter()
|
|
||||||
.txidEqualTo(txid)
|
|
||||||
.findFirst();
|
|
||||||
|
|
||||||
if (mounted) {
|
|
||||||
unawaited(Navigator.of(context).pushNamed(
|
|
||||||
TradeDetailsView.routeName,
|
|
||||||
arguments: Tuple4(tradeId, tx,
|
|
||||||
walletIds.first, manager.walletName),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unawaited(Navigator.of(context).pushNamed(
|
|
||||||
TradeDetailsView.routeName,
|
|
||||||
arguments: Tuple4(
|
|
||||||
tradeId, null, walletIds?.first, null),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}, childCount: tradeCount),
|
|
||||||
),
|
|
||||||
if (!hasHistory)
|
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
child: Container(
|
child: Column(
|
||||||
decoration: BoxDecoration(
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
color: Theme.of(context)
|
children: [
|
||||||
.extension<StackColors>()!
|
const SizedBox(
|
||||||
.popupBG,
|
height: 12,
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
Constants.size.circularBorderRadius,
|
|
||||||
),
|
),
|
||||||
),
|
Text(
|
||||||
child: Padding(
|
"Trades",
|
||||||
padding: const EdgeInsets.all(12),
|
style: STextStyles.itemSubtitle(context).copyWith(
|
||||||
child: Text(
|
color: Theme.of(context)
|
||||||
"Trades will appear here",
|
.extension<StackColors>()!
|
||||||
textAlign: TextAlign.center,
|
.textDark3,
|
||||||
style: STextStyles.itemSubtitle(context),
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (hasHistory)
|
||||||
|
SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate((context, index) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: TradeCard(
|
||||||
|
key: Key("tradeCard_${trades[index].uuid}"),
|
||||||
|
trade: trades[index],
|
||||||
|
onTap: () async {
|
||||||
|
final String tradeId = trades[index].tradeId;
|
||||||
|
|
||||||
|
final lookup = ref
|
||||||
|
.read(tradeSentFromStackLookupProvider)
|
||||||
|
.all;
|
||||||
|
|
||||||
|
//todo: check if print needed
|
||||||
|
// debugPrint("ALL: $lookup");
|
||||||
|
|
||||||
|
final String? txid = ref
|
||||||
|
.read(tradeSentFromStackLookupProvider)
|
||||||
|
.getTxidForTradeId(tradeId);
|
||||||
|
final List<String>? walletIds = ref
|
||||||
|
.read(tradeSentFromStackLookupProvider)
|
||||||
|
.getWalletIdsForTradeId(tradeId);
|
||||||
|
|
||||||
|
if (txid != null &&
|
||||||
|
walletIds != null &&
|
||||||
|
walletIds.isNotEmpty) {
|
||||||
|
final manager = ref
|
||||||
|
.read(walletsChangeNotifierProvider)
|
||||||
|
.getManager(walletIds.first);
|
||||||
|
|
||||||
|
//todo: check if print needed
|
||||||
|
// debugPrint("name: ${manager.walletName}");
|
||||||
|
|
||||||
|
final tx = await MainDB.instance
|
||||||
|
.getTransactions(walletIds.first)
|
||||||
|
.filter()
|
||||||
|
.txidEqualTo(txid)
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
unawaited(Navigator.of(context).pushNamed(
|
||||||
|
TradeDetailsView.routeName,
|
||||||
|
arguments: Tuple4(tradeId, tx,
|
||||||
|
walletIds.first, manager.walletName),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unawaited(Navigator.of(context).pushNamed(
|
||||||
|
TradeDetailsView.routeName,
|
||||||
|
arguments: Tuple4(
|
||||||
|
tradeId, null, walletIds?.first, null),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}, childCount: tradeCount),
|
||||||
|
),
|
||||||
|
if (!hasHistory)
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.popupBG,
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
Constants.size.circularBorderRadius,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
child: Text(
|
||||||
|
"Trades will appear here",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: STextStyles.itemSubtitle(context),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
);
|
||||||
);
|
},
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,11 +4,15 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/exchange_form.dart';
|
import 'package:stackwallet/pages/exchange_view/exchange_form.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart';
|
import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart';
|
||||||
|
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||||
|
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||||
import 'package:stackwallet/widgets/background.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/custom_buttons/app_bar_icon_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
||||||
|
|
||||||
class WalletInitiatedExchangeView extends ConsumerStatefulWidget {
|
class WalletInitiatedExchangeView extends ConsumerStatefulWidget {
|
||||||
const WalletInitiatedExchangeView({
|
const WalletInitiatedExchangeView({
|
||||||
|
@ -32,10 +36,41 @@ class _WalletInitiatedExchangeViewState
|
||||||
late final String walletId;
|
late final String walletId;
|
||||||
late final Coin coin;
|
late final Coin coin;
|
||||||
|
|
||||||
|
bool _initialCachePopulationUnderway = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
walletId = widget.walletId;
|
walletId = widget.walletId;
|
||||||
coin = widget.coin;
|
coin = widget.coin;
|
||||||
|
|
||||||
|
if (!ref.read(prefsChangeNotifierProvider).externalCalls) {
|
||||||
|
if (ExchangeDataLoadingService.currentCacheVersion <
|
||||||
|
ExchangeDataLoadingService.cacheVersion) {
|
||||||
|
_initialCachePopulationUnderway = true;
|
||||||
|
ExchangeDataLoadingService.instance.onLoadingComplete = () {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||||
|
setState(() {
|
||||||
|
_initialCachePopulationUnderway = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ExchangeDataLoadingService.instance
|
||||||
|
.init()
|
||||||
|
.then((_) => ExchangeDataLoadingService.instance.loadAll());
|
||||||
|
} else if (ExchangeDataLoadingService.instance.isLoading &&
|
||||||
|
ExchangeDataLoadingService.currentCacheVersion <
|
||||||
|
ExchangeDataLoadingService.cacheVersion) {
|
||||||
|
_initialCachePopulationUnderway = true;
|
||||||
|
ExchangeDataLoadingService.instance.onLoadingComplete = () {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||||
|
setState(() {
|
||||||
|
_initialCachePopulationUnderway = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,76 +83,98 @@ class _WalletInitiatedExchangeViewState
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
debugPrint("BUILD: $runtimeType");
|
debugPrint("BUILD: $runtimeType");
|
||||||
|
|
||||||
return Background(
|
return ConditionalParent(
|
||||||
child: Scaffold(
|
condition: _initialCachePopulationUnderway,
|
||||||
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
|
builder: (child) {
|
||||||
appBar: AppBar(
|
return Stack(
|
||||||
leading: AppBarBackButton(
|
children: [
|
||||||
onPressed: () async {
|
child,
|
||||||
if (FocusScope.of(context).hasFocus) {
|
Material(
|
||||||
FocusScope.of(context).unfocus();
|
color: Theme.of(context)
|
||||||
await Future<void>.delayed(const Duration(milliseconds: 75));
|
.extension<StackColors>()!
|
||||||
}
|
.overlay
|
||||||
if (mounted) {
|
.withOpacity(0.6),
|
||||||
Navigator.of(context).pop();
|
child: const CustomLoadingOverlay(
|
||||||
}
|
message: "Updating exchange data",
|
||||||
},
|
subMessage: "This could take a few minutes",
|
||||||
|
eventBus: null,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: 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: 75));
|
||||||
|
}
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
"Exchange",
|
||||||
|
style: STextStyles.navBarTitle(context),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
body: LayoutBuilder(
|
||||||
"Exchange",
|
builder: (context, constraints) {
|
||||||
style: STextStyles.navBarTitle(context),
|
final width = MediaQuery.of(context).size.width - 32;
|
||||||
),
|
return Padding(
|
||||||
),
|
padding: const EdgeInsets.all(12),
|
||||||
body: LayoutBuilder(
|
child: SingleChildScrollView(
|
||||||
builder: (context, constraints) {
|
child: ConstrainedBox(
|
||||||
final width = MediaQuery.of(context).size.width - 32;
|
constraints: BoxConstraints(
|
||||||
return Padding(
|
minHeight: constraints.maxHeight - 24,
|
||||||
padding: const EdgeInsets.all(12),
|
),
|
||||||
child: SingleChildScrollView(
|
child: IntrinsicHeight(
|
||||||
child: ConstrainedBox(
|
child: Padding(
|
||||||
constraints: BoxConstraints(
|
padding: const EdgeInsets.all(4),
|
||||||
minHeight: constraints.maxHeight - 24,
|
child: Column(
|
||||||
),
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
child: IntrinsicHeight(
|
children: [
|
||||||
child: Padding(
|
StepRow(
|
||||||
padding: const EdgeInsets.all(4),
|
count: 4,
|
||||||
child: Column(
|
current: 0,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
width: width,
|
||||||
children: [
|
),
|
||||||
StepRow(
|
const SizedBox(
|
||||||
count: 4,
|
height: 14,
|
||||||
current: 0,
|
),
|
||||||
width: width,
|
Text(
|
||||||
),
|
"Exchange amount",
|
||||||
const SizedBox(
|
style: STextStyles.pageTitleH1(context),
|
||||||
height: 14,
|
),
|
||||||
),
|
const SizedBox(
|
||||||
Text(
|
height: 8,
|
||||||
"Exchange amount",
|
),
|
||||||
style: STextStyles.pageTitleH1(context),
|
Text(
|
||||||
),
|
"Network fees and other exchange charges are included in the rate.",
|
||||||
const SizedBox(
|
style: STextStyles.itemSubtitle(context),
|
||||||
height: 8,
|
),
|
||||||
),
|
const SizedBox(
|
||||||
Text(
|
height: 24,
|
||||||
"Network fees and other exchange charges are included in the rate.",
|
),
|
||||||
style: STextStyles.itemSubtitle(context),
|
ExchangeForm(
|
||||||
),
|
walletId: walletId,
|
||||||
const SizedBox(
|
coin: coin,
|
||||||
height: 24,
|
),
|
||||||
),
|
],
|
||||||
ExchangeForm(
|
),
|
||||||
walletId: walletId,
|
|
||||||
coin: coin,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
},
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,79 +1,142 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/exchange_form.dart';
|
import 'package:stackwallet/pages/exchange_view/exchange_form.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/subwidgets/desktop_trade_history.dart';
|
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/subwidgets/desktop_trade_history.dart';
|
||||||
|
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||||
|
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||||
|
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||||
|
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
|
|
||||||
class DesktopExchangeView extends StatefulWidget {
|
class DesktopExchangeView extends ConsumerStatefulWidget {
|
||||||
const DesktopExchangeView({Key? key}) : super(key: key);
|
const DesktopExchangeView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
static const String routeName = "/desktopExchange";
|
static const String routeName = "/desktopExchange";
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DesktopExchangeView> createState() => _DesktopExchangeViewState();
|
ConsumerState<DesktopExchangeView> createState() =>
|
||||||
|
_DesktopExchangeViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DesktopExchangeViewState extends State<DesktopExchangeView> {
|
class _DesktopExchangeViewState extends ConsumerState<DesktopExchangeView> {
|
||||||
|
bool _initialCachePopulationUnderway = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
if (!ref.read(prefsChangeNotifierProvider).externalCalls) {
|
||||||
|
if (ExchangeDataLoadingService.currentCacheVersion <
|
||||||
|
ExchangeDataLoadingService.cacheVersion) {
|
||||||
|
_initialCachePopulationUnderway = true;
|
||||||
|
ExchangeDataLoadingService.instance.onLoadingComplete = () {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||||
|
setState(() {
|
||||||
|
_initialCachePopulationUnderway = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ExchangeDataLoadingService.instance
|
||||||
|
.init()
|
||||||
|
.then((_) => ExchangeDataLoadingService.instance.loadAll());
|
||||||
|
} else if (ExchangeDataLoadingService.instance.isLoading &&
|
||||||
|
ExchangeDataLoadingService.currentCacheVersion <
|
||||||
|
ExchangeDataLoadingService.cacheVersion) {
|
||||||
|
_initialCachePopulationUnderway = true;
|
||||||
|
ExchangeDataLoadingService.instance.onLoadingComplete = () {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||||
|
setState(() {
|
||||||
|
_initialCachePopulationUnderway = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DesktopScaffold(
|
return ConditionalParent(
|
||||||
appBar: DesktopAppBar(
|
condition: _initialCachePopulationUnderway,
|
||||||
isCompactHeight: true,
|
builder: (child) {
|
||||||
leading: Padding(
|
return Stack(
|
||||||
|
children: [
|
||||||
|
child,
|
||||||
|
Material(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.overlay
|
||||||
|
.withOpacity(0.6),
|
||||||
|
child: const CustomLoadingOverlay(
|
||||||
|
message: "Updating exchange data",
|
||||||
|
subMessage: "This could take a few minutes",
|
||||||
|
eventBus: null,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: DesktopScaffold(
|
||||||
|
appBar: DesktopAppBar(
|
||||||
|
isCompactHeight: true,
|
||||||
|
leading: Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 24,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"Exchange",
|
||||||
|
style: STextStyles.desktopH3(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
left: 24,
|
left: 24,
|
||||||
|
right: 24,
|
||||||
|
bottom: 24,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Row(
|
||||||
"Exchange",
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
style: STextStyles.desktopH3(context),
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Exchange details",
|
||||||
|
style: STextStyles.desktopTextExtraExtraSmall(context),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
const RoundedWhiteContainer(
|
||||||
|
padding: EdgeInsets.all(24),
|
||||||
|
child: ExchangeForm(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 16,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Row(
|
||||||
|
children: const [
|
||||||
|
Expanded(
|
||||||
|
child: DesktopTradeHistory(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
left: 24,
|
|
||||||
right: 24,
|
|
||||||
bottom: 24,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Exchange details",
|
|
||||||
style: STextStyles.desktopTextExtraExtraSmall(context),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
const RoundedWhiteContainer(
|
|
||||||
padding: EdgeInsets.all(24),
|
|
||||||
child: ExchangeForm(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
width: 16,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Row(
|
|
||||||
children: const [
|
|
||||||
Expanded(
|
|
||||||
child: DesktopTradeHistory(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:stackwallet/hive/db.dart';
|
||||||
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
|
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
|
||||||
import 'package:stackwallet/models/isar/exchange_cache/pair.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/change_now/change_now_exchange.dart';
|
||||||
|
@ -16,6 +17,25 @@ class ExchangeDataLoadingService {
|
||||||
Isar? _isar;
|
Isar? _isar;
|
||||||
Isar get isar => _isar!;
|
Isar get isar => _isar!;
|
||||||
|
|
||||||
|
VoidCallback? onLoadingError;
|
||||||
|
VoidCallback? onLoadingComplete;
|
||||||
|
|
||||||
|
static const int cacheVersion = 1;
|
||||||
|
|
||||||
|
static int get currentCacheVersion =>
|
||||||
|
DB.instance.get<dynamic>(
|
||||||
|
boxName: DB.boxNameDBInfo,
|
||||||
|
key: "exchange_data_cache_version") as int? ??
|
||||||
|
0;
|
||||||
|
|
||||||
|
Future<void> _updateCurrentCacheVersion(int version) async {
|
||||||
|
await DB.instance.put<dynamic>(
|
||||||
|
boxName: DB.boxNameDBInfo,
|
||||||
|
key: "exchange_data_cache_version",
|
||||||
|
value: version,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
if (_isar != null && isar.isOpen) return;
|
if (_isar != null && isar.isOpen) return;
|
||||||
_isar = await Isar.open(
|
_isar = await Isar.open(
|
||||||
|
@ -25,18 +45,23 @@ class ExchangeDataLoadingService {
|
||||||
],
|
],
|
||||||
directory: (await StackFileSystem.applicationIsarDirectory()).path,
|
directory: (await StackFileSystem.applicationIsarDirectory()).path,
|
||||||
inspector: kDebugMode,
|
inspector: kDebugMode,
|
||||||
|
// inspector: false,
|
||||||
name: "exchange_cache",
|
name: "exchange_cache",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get isLoading => _locked;
|
||||||
|
|
||||||
bool _locked = false;
|
bool _locked = false;
|
||||||
|
|
||||||
Future<void> loadAll() async {
|
Future<void> loadAll() async {
|
||||||
print("LOADINGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG: LOCKED=$_locked");
|
|
||||||
if (!_locked) {
|
if (!_locked) {
|
||||||
_locked = true;
|
_locked = true;
|
||||||
print("LOADINGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG");
|
Logging.instance.log(
|
||||||
final time = DateTime.now();
|
"ExchangeDataLoadingService.loadAll starting...",
|
||||||
|
level: LogLevel.Info,
|
||||||
|
);
|
||||||
|
final start = DateTime.now();
|
||||||
try {
|
try {
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
_loadChangeNowCurrencies(),
|
_loadChangeNowCurrencies(),
|
||||||
|
@ -46,13 +71,18 @@ class ExchangeDataLoadingService {
|
||||||
// loadSimpleswapFloatingRateCurrencies(ref),
|
// loadSimpleswapFloatingRateCurrencies(ref),
|
||||||
loadMajesticBankCurrencies(),
|
loadMajesticBankCurrencies(),
|
||||||
]);
|
]);
|
||||||
|
Logging.instance.log(
|
||||||
print(
|
"ExchangeDataLoadingService.loadAll finished in ${DateTime.now().difference(start).inSeconds} seconds",
|
||||||
"LOADINGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG done in ${DateTime.now().difference(time).inSeconds} seconds");
|
level: LogLevel.Info,
|
||||||
|
);
|
||||||
|
onLoadingComplete?.call();
|
||||||
|
await _updateCurrentCacheVersion(cacheVersion);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"ExchangeDataLoadingService.loadAll failed: $e\n$s",
|
"ExchangeDataLoadingService.loadAll failed after ${DateTime.now().difference(start).inSeconds} seconds: $e\n$s",
|
||||||
level: LogLevel.Error);
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
onLoadingError?.call();
|
||||||
}
|
}
|
||||||
_locked = false;
|
_locked = false;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +112,7 @@ class ExchangeDataLoadingService {
|
||||||
Future<void> _loadChangeNowFixedRatePairs() async {
|
Future<void> _loadChangeNowFixedRatePairs() async {
|
||||||
final exchange = ChangeNowExchange.instance;
|
final exchange = ChangeNowExchange.instance;
|
||||||
|
|
||||||
final responsePairs = await exchange.getAllPairs(true);
|
final responsePairs = await compute(exchange.getAllPairs, true);
|
||||||
|
|
||||||
if (responsePairs.value != null) {
|
if (responsePairs.value != null) {
|
||||||
await isar.writeTxn(() async {
|
await isar.writeTxn(() async {
|
||||||
|
@ -107,7 +137,7 @@ class ExchangeDataLoadingService {
|
||||||
Future<void> _loadChangeNowEstimatedRatePairs() async {
|
Future<void> _loadChangeNowEstimatedRatePairs() async {
|
||||||
final exchange = ChangeNowExchange.instance;
|
final exchange = ChangeNowExchange.instance;
|
||||||
|
|
||||||
final responsePairs = await exchange.getAllPairs(false);
|
final responsePairs = await compute(exchange.getAllPairs, false);
|
||||||
|
|
||||||
if (responsePairs.value != null) {
|
if (responsePairs.value != null) {
|
||||||
await isar.writeTxn(() async {
|
await isar.writeTxn(() async {
|
||||||
|
|
Loading…
Reference in a new issue