/* * This file is part of Stack Wallet. * * Copyright (c) 2023 Cypher Stack * All Rights Reserved. * The code is distributed under GPLv3 license, see LICENSE file for details. * Generated by Cypher Stack on 2023-05-26 * */ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:isar/isar.dart'; import 'package:tuple/tuple.dart'; import '../../db/isar/main_db.dart'; import '../../models/isar/models/blockchain_data/transaction.dart'; import '../../providers/global/trades_service_provider.dart'; import '../../providers/providers.dart'; import '../../services/exchange/exchange_data_loading_service.dart'; import '../../themes/stack_colors.dart'; import '../../utilities/constants.dart'; import '../../utilities/text_styles.dart'; import '../../widgets/conditional_parent.dart'; import '../../widgets/custom_loading_overlay.dart'; import '../../widgets/trade_card.dart'; import 'exchange_form.dart'; import 'trade_details_view.dart'; class ExchangeView extends ConsumerStatefulWidget { const ExchangeView({super.key}); @override ConsumerState createState() => _ExchangeViewState(); } class _ExchangeViewState extends ConsumerState { 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) async { await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty( ref.read(efCurrencyPairProvider), ref.read(efRateTypeProvider), ); setState(() { _initialCachePopulationUnderway = false; }); }); }; } ExchangeDataLoadingService.instance.loadAll(); } else if (ExchangeDataLoadingService.instance.isLoading && ExchangeDataLoadingService.currentCacheVersion < ExchangeDataLoadingService.cacheVersion) { _initialCachePopulationUnderway = true; ExchangeDataLoadingService.instance.onLoadingComplete = () { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty( ref.read(efCurrencyPairProvider), ref.read(efRateTypeProvider), ); setState(() { _initialCachePopulationUnderway = false; }); }); }; } super.initState(); } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); return ConditionalParent( condition: _initialCachePopulationUnderway, builder: (child) { return Stack( children: [ child, Material( color: Theme.of(context) .extension()! .overlay .withOpacity(0.6), child: const CustomLoadingOverlay( message: "Updating exchange data", subMessage: "This could take a few minutes", eventBus: null, ), ), ], ); }, child: SafeArea( child: NestedScrollView( floatHeaderSlivers: true, headerSliverBuilder: (context, innerBoxIsScrolled) { return [ SliverOverlapAbsorber( handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), sliver: const SliverToBoxAdapter( child: Padding( padding: EdgeInsets.only( left: 16, right: 16, top: 16, ), child: ExchangeForm(), ), ), ), ]; }, body: Builder( builder: (buildContext) { final trades = ref .watch(tradesServiceProvider.select((value) => value.trades)); final tradeCount = trades.length; final hasHistory = tradeCount > 0; return Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: CustomScrollView( slivers: [ SliverOverlapInjector( handle: NestedScrollView.sliverOverlapAbsorberHandleFor( buildContext, ), ), SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox( height: 12, ), Text( "Trades", style: STextStyles.itemSubtitle(context).copyWith( color: Theme.of(context) .extension()! .textDark3, ), ), 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? walletIds = ref .read(tradeSentFromStackLookupProvider) .getWalletIdsForTradeId(tradeId); if (txid != null && walletIds != null && walletIds.isNotEmpty) { final wallet = ref .read(pWallets) .getWallet(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, wallet.info.name, ), ), ); } } 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()! .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), ), ), ), ), ), ], ), ); }, ), ), ), ); } }