From 1f1ba779f851d194e0eb5c1174d3ad96075f0d22 Mon Sep 17 00:00:00 2001 From: malik1004x Date: Mon, 5 Oct 2026 14:58:05 +0200 Subject: [PATCH] make charts respect fiat api mode (#3678) * make charts respect fiat api mode * remove unused blocprovider * https -> http * https -> http --- lib/di.dart | 2 +- lib/new-ui/model/charts/price_api_client.dart | 4 +- lib/new-ui/model/charts/price_store.dart | 15 +- lib/new-ui/pages/charts_page.dart | 169 ++++++++++-------- lib/new-ui/viewmodels/charts/charts_bloc.dart | 12 +- .../viewmodels/charts/charts_state.dart | 4 + .../widgets/charts_page/asset_grid.dart | 16 +- .../charts_page/asset_grid_header.dart | 6 +- .../widgets/charts_page/chart_header.dart | 6 +- .../widgets/charts_page/chart_modal.dart | 13 +- res/values/strings_en.arb | 2 + 11 files changed, 151 insertions(+), 98 deletions(-) diff --git a/lib/di.dart b/lib/di.dart index 5d4834ca9..e8933b0ea 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -571,7 +571,7 @@ Future setup({ (displayMode == BitcoinAmountDisplayMode.satoshiForLightning && lightningMode))); }); - getIt.registerLazySingleton(() => PriceStore()); + getIt.registerLazySingleton(() => PriceStore(settingsStore: getIt.get())); getIt.registerFactory( () => ChartsBloc(appStore: getIt.get(), priceStore: getIt.get())); diff --git a/lib/new-ui/model/charts/price_api_client.dart b/lib/new-ui/model/charts/price_api_client.dart index 0c3fa0e25..fdd73b60b 100644 --- a/lib/new-ui/model/charts/price_api_client.dart +++ b/lib/new-ui/model/charts/price_api_client.dart @@ -22,7 +22,7 @@ class LatestPriceRequest { "quote": to.apiString, }); - Uri get onionUri => Uri.https(priceApiHostOnion, uri.path, uri.queryParameters); + Uri get onionUri => Uri.http(priceApiHostOnion, uri.path, uri.queryParameters); } class PriceRequest { @@ -49,7 +49,7 @@ class PriceRequest { "base": to.apiString, }); - Uri get onionUri => Uri.https(priceApiHostOnion, uri.path, uri.queryParameters); + Uri get onionUri => Uri.http(priceApiHostOnion, uri.path, uri.queryParameters); } class PriceApiClient { diff --git a/lib/new-ui/model/charts/price_store.dart b/lib/new-ui/model/charts/price_store.dart index 705a17fc7..1beee9506 100644 --- a/lib/new-ui/model/charts/price_store.dart +++ b/lib/new-ui/model/charts/price_store.dart @@ -1,6 +1,8 @@ +import "package:cake_wallet/entities/fiat_api_mode.dart"; import "package:cake_wallet/new-ui/model/charts/price_api_client.dart"; import "package:cake_wallet/new-ui/model/charts/price_data.dart"; import "package:cake_wallet/new-ui/model/charts/util/chart_range.dart"; +import "package:cake_wallet/store/settings_store.dart"; import "package:cw_core/currency.dart"; import "package:cw_core/utils/print_verbose.dart"; @@ -13,6 +15,7 @@ abstract class PriceSource { Currency from, Currency to, Duration interval, + {required bool torOnly,} ); } @@ -30,6 +33,7 @@ class DatabasePriceSource extends PriceSource with UpdatablePriceSource { Currency from, Currency to, Duration interval, + {required bool torOnly,} ) => PriceData.get(from, to, start, end); @@ -49,13 +53,19 @@ class ApiPriceSource extends PriceSource { Currency from, Currency to, Duration interval, - ) => + {required bool torOnly,} + ) => PriceApiClient.getPrices( + torOnly: torOnly, PriceRequest(beginTime: start, interval: interval, from: from, to: to), ); } class PriceStore { + const PriceStore({required this.settingsStore}); + + final SettingsStore settingsStore; + static const priceSources = [ // TODO InMemoryPriceSource() - easily implementable w this pattern but idk if we need to optimize this that much DatabasePriceSource(), @@ -76,7 +86,8 @@ class PriceStore { final alignedStart = start; for (final source in priceSources) { - final sourceData = await source.get(start!, end, from, to, range.dataPrecision); + final sourceData = await source.get(start!, end, from, to, range.dataPrecision, + torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly,); data.addAll(sourceData); start = _firstUnavailablePrice(data.toList(), range.dataPrecision, start, end); if (start == null) { diff --git a/lib/new-ui/pages/charts_page.dart b/lib/new-ui/pages/charts_page.dart index 3502ed2fd..4ac755277 100644 --- a/lib/new-ui/pages/charts_page.dart +++ b/lib/new-ui/pages/charts_page.dart @@ -1,3 +1,4 @@ +import "package:cake_wallet/generated/i18n.dart"; import "package:cake_wallet/new-ui/page_open_listener.dart"; import "package:cake_wallet/new-ui/viewmodels/charts/charts_bloc.dart"; import "package:cake_wallet/new-ui/widgets/charts_page/asset_grid.dart"; @@ -20,84 +21,104 @@ class ChartsPage extends StatelessWidget implements PageOpenListener { } @override - Widget build(BuildContext context) => BlocProvider( - create: (context) => chartsBloc, - child: BlocBuilder( - builder: (context, state) { - if (state is ChartsInitial) { - return const Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - spacing: 24, - children: [ - CakeImageWidget( - width: 36, - height: 36, - imageUrl: "assets/new-ui/navbar/charts.svg", - ), - CupertinoActivityIndicator(), - if (kDebugMode) - Text( - "devs: if this doesn't go away in a few seconds, either your device is painfully slow or the db is messed up", - ), - ], - ), - ); - } - - return Container( - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - Theme.of(context).colorScheme.surface, - Theme.of(context).colorScheme.surfaceDim, - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: CustomScrollView( - physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), - slivers: [ - SliverPadding( - padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top), - sliver: CupertinoSliverRefreshControl( - refreshTriggerPullDistance: 160, - refreshIndicatorExtent: 90, - onRefresh: () async => chartsBloc.add(PageRefreshed()), - ), + Widget build(BuildContext context) => BlocBuilder( + bloc: chartsBloc, + builder: (context, state) { + if (state is ChartsInitial) { + return const Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 24, + children: [ + CakeImageWidget( + width: 36, + height: 36, + imageUrl: "assets/new-ui/navbar/charts.svg", ), - SliverToBoxAdapter( - child: SafeArea( - child: Column( - spacing: 24, - children: [ - if (state is ChartsStateWithData) - ChartHeader( - currency: state.pinnedCurrency, - chartHeight: 100, - chartPadding: 22, - centered: false, - favorite: true, - ), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 18), - child: Column( - spacing: 24, - children: [ChartsAssetGridHeader(), ChartsAssetGrid()], - ), - ), - const SizedBox( - height: 96, - ), - ], - ), + CupertinoActivityIndicator(), + if (kDebugMode) + Text( + "devs: if this doesn't go away in a few seconds, either your device is painfully slow or the db is messed up", ), - ), ], ), ); - }, - ), + } + + if (state is ChartsDisabled) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 12, + children: [ + CakeImageWidget( + width: 36, + height: 36, + imageUrl: "assets/new-ui/navbar/charts.svg", + ), + Text( + S.of(context).charts_unavailable, + style: const TextStyle(fontSize: 24, fontWeight: FontWeight.w600), + ), + Text(S.of(context).charts_unavailable_desc), + ], + ), + ); + } + + return Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Theme.of(context).colorScheme.surface, + Theme.of(context).colorScheme.surfaceDim, + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: CustomScrollView( + physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), + slivers: [ + SliverPadding( + padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top), + sliver: CupertinoSliverRefreshControl( + refreshTriggerPullDistance: 160, + refreshIndicatorExtent: 90, + onRefresh: () async => chartsBloc.add(PageRefreshed()), + ), + ), + SliverToBoxAdapter( + child: SafeArea( + child: Column( + spacing: 24, + children: [ + if (state is ChartsStateWithData) + ChartHeader( + bloc: chartsBloc, + currency: state.pinnedCurrency, + chartHeight: 100, + chartPadding: 22, + centered: false, + favorite: true, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 18), + child: Column( + spacing: 24, + children: [ChartsAssetGridHeader(bloc: chartsBloc), ChartsAssetGrid(bloc: chartsBloc)], + ), + ), + const SizedBox( + height: 96, + ), + ], + ), + ), + ), + ], + ), + ); + }, ); } diff --git a/lib/new-ui/viewmodels/charts/charts_bloc.dart b/lib/new-ui/viewmodels/charts/charts_bloc.dart index 45b877dd2..9e73e49eb 100644 --- a/lib/new-ui/viewmodels/charts/charts_bloc.dart +++ b/lib/new-ui/viewmodels/charts/charts_bloc.dart @@ -3,6 +3,7 @@ import "dart:async"; import "package:bloc/bloc.dart"; import "package:bloc_concurrency/bloc_concurrency.dart"; import "package:cake_wallet/core/utilities.dart"; +import "package:cake_wallet/entities/fiat_api_mode.dart"; import "package:cake_wallet/entities/fiat_currency.dart"; import "package:cake_wallet/new-ui/model/charts/charts_asset.dart"; import "package:cake_wallet/new-ui/model/charts/price_data.dart"; @@ -13,7 +14,6 @@ import "package:cake_wallet/new-ui/model/charts/util/price_change_direction.dart import "package:cake_wallet/new-ui/model/charts/util/price_data_sort_criteria.dart"; import "package:cake_wallet/store/app_store.dart"; import "package:cw_core/amount/money.dart"; -import "package:cw_core/crypto_amount_format.dart"; import "package:cw_core/crypto_currency.dart"; import "package:flutter/foundation.dart"; @@ -30,17 +30,23 @@ class ChartsBloc extends Bloc { on(_onCurrencyPinned, transformer: sequential()); on(_onPageRefreshed, transformer: sequential()); on(_onPageLoadStarted, transformer: restartable()); - on(_init); + on(_init, transformer: sequential()); } final PriceStore priceStore; final AppStore appStore; Future _init(Init event, Emitter emit) async { - if (state is! ChartsInitial) { + + if(appStore.settingsStore.fiatApiMode == FiatApiMode.disabled) { + emit(const ChartsDisabled()); return; } + if (state is! ChartsInitial) { + emit(const ChartsInitial()); + } + final assets = await ChartsAsset.get(); if (assets.isEmpty) { diff --git a/lib/new-ui/viewmodels/charts/charts_state.dart b/lib/new-ui/viewmodels/charts/charts_state.dart index 18496288a..1a33c9d58 100644 --- a/lib/new-ui/viewmodels/charts/charts_state.dart +++ b/lib/new-ui/viewmodels/charts/charts_state.dart @@ -9,6 +9,10 @@ final class ChartsInitial extends ChartsState { const ChartsInitial(); } +final class ChartsDisabled extends ChartsState { + const ChartsDisabled(); +} + abstract final class ChartsStateWithData extends ChartsState { const ChartsStateWithData({ required this.pinnedCurrency, diff --git a/lib/new-ui/widgets/charts_page/asset_grid.dart b/lib/new-ui/widgets/charts_page/asset_grid.dart index 3c7500fa4..fec182b7d 100644 --- a/lib/new-ui/widgets/charts_page/asset_grid.dart +++ b/lib/new-ui/widgets/charts_page/asset_grid.dart @@ -17,10 +17,13 @@ import "package:flutter/services.dart"; import "package:flutter_bloc/flutter_bloc.dart"; class ChartsAssetGrid extends StatelessWidget { - const ChartsAssetGrid({super.key}); + const ChartsAssetGrid({required this.bloc, super.key}); + + final ChartsBloc bloc; @override Widget build(BuildContext context) => BlocBuilder( + bloc: bloc, builder: (context, state) { if (state is ChartsStateWithData) { final currencies = state.currencies; @@ -36,6 +39,7 @@ class ChartsAssetGrid extends StatelessWidget { itemBuilder: (context, index) { final curr = currencies[index]; return ChartsAssetCard( + bloc: bloc, currency: curr, price: state.priceFor(curr)?.toStringWithPrecision(fractionalDigits: 2) ?? "...", ticker: state.fiatTicker, @@ -53,7 +57,7 @@ class ChartsAssetGrid extends StatelessWidget { class ChartsAssetCard extends StatelessWidget { const ChartsAssetCard( - {super.key, + {required this.bloc, super.key, required this.currency, required this.price, required this.ticker, @@ -67,6 +71,7 @@ class ChartsAssetCard extends StatelessWidget { final PriceChangeData? changeData; final bool favorite; final bool isSingleCurrency; + final ChartsBloc bloc; String get displayPrice { try { @@ -88,7 +93,7 @@ class ChartsAssetCard extends StatelessWidget { label: S.of(context).favorite, iconPath: "assets/new-ui/favorite.svg", onSelected: () { - context.read().add(CurrencyPinned(currency: currency)); + bloc.add(CurrencyPinned(currency: currency)); Navigator.of(context).pop(); }, color: favorite ? Theme.of(context).colorScheme.error : null,), @@ -97,7 +102,7 @@ class ChartsAssetCard extends StatelessWidget { iconPath: "assets/new-ui/address_hide.svg", onSelected: () { if (!isSingleCurrency) { - context.read().add(CurrencyRemoved(currency: currency)); + bloc.add(CurrencyRemoved(currency: currency)); Navigator.of(context).pop(); } }, @@ -112,11 +117,12 @@ class ChartsAssetCard extends StatelessWidget { isScrollControlled: true, context: context, builder: (context) => ChartModal( + bloc: bloc, currency: currency, isFavorite: favorite, ),); if (res != null && res is bool && res) { - context.read().add(CurrencyPinned(currency: currency)); + bloc.add(CurrencyPinned(currency: currency)); } }, child: Container( diff --git a/lib/new-ui/widgets/charts_page/asset_grid_header.dart b/lib/new-ui/widgets/charts_page/asset_grid_header.dart index a757b9e8b..b8afb745e 100644 --- a/lib/new-ui/widgets/charts_page/asset_grid_header.dart +++ b/lib/new-ui/widgets/charts_page/asset_grid_header.dart @@ -12,13 +12,15 @@ import "package:flutter_bloc/flutter_bloc.dart"; class ChartsAssetGridHeader extends StatelessWidget { const ChartsAssetGridHeader({ - super.key, + required this.bloc, super.key, }); + final ChartsBloc bloc; + @override Widget build(BuildContext context) => BlocBuilder( + bloc: bloc, builder: (context, state) { - final bloc = context.read(); return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/lib/new-ui/widgets/charts_page/chart_header.dart b/lib/new-ui/widgets/charts_page/chart_header.dart index 6a21571e1..3b0758d68 100644 --- a/lib/new-ui/widgets/charts_page/chart_header.dart +++ b/lib/new-ui/widgets/charts_page/chart_header.dart @@ -15,7 +15,7 @@ import "package:intl/intl.dart"; class ChartHeader extends StatefulWidget { const ChartHeader({ - super.key, + required this.bloc, super.key, required this.currency, required this.chartHeight, required this.chartPadding, @@ -28,6 +28,7 @@ class ChartHeader extends StatefulWidget { final double chartPadding; final bool centered; final bool favorite; + final ChartsBloc bloc; @override State createState() => _ChartHeaderState(); @@ -39,6 +40,7 @@ class _ChartHeaderState extends State { @override Widget build(BuildContext context) => BlocBuilder( + bloc: widget.bloc, builder: (context, state) { if (state case final ChartsStateWithData s) { return Column( @@ -149,7 +151,7 @@ class _ChartHeaderState extends State { ChartRangeSelector( selectedRange: s.range, onRangeSelected: (range) => - context.read().add(RangeChanged(newRange: range)), + widget.bloc.add(RangeChanged(newRange: range)), ), ], ), diff --git a/lib/new-ui/widgets/charts_page/chart_modal.dart b/lib/new-ui/widgets/charts_page/chart_modal.dart index f8f46a581..006f0f6b2 100644 --- a/lib/new-ui/widgets/charts_page/chart_modal.dart +++ b/lib/new-ui/widgets/charts_page/chart_modal.dart @@ -19,15 +19,14 @@ import "package:flutter_bloc/flutter_bloc.dart"; import "package:modal_bottom_sheet/modal_bottom_sheet.dart"; class ChartModal extends StatelessWidget { - const ChartModal({required this.currency, required this.isFavorite, super.key}); + const ChartModal({required this.bloc, required this.currency, required this.isFavorite, super.key}); final CryptoCurrency currency; final bool isFavorite; + final ChartsBloc bloc; @override - Widget build(BuildContext context) => BlocProvider( - create: (context) => getIt.get()..add(Init()), - child: Container( + Widget build(BuildContext context) => Container( decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: const BorderRadius.vertical(top: Radius.circular(18)), @@ -43,6 +42,7 @@ class ChartModal extends StatelessWidget { padding: const EdgeInsets.only(top: 18, left: 18), ), ChartHeader( + bloc: bloc, currency: currency, chartHeight: 220, chartPadding: 32, @@ -135,9 +135,8 @@ class ChartModal extends StatelessWidget { ], ), ), - ), - ); - + ); + void openBuySellPage(BuildContext context, BuySellPageMode mode) { Navigator.of(context).pop(); final page = getIt.get( diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 6cec6c229..8daf7b34f 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -210,6 +210,8 @@ "change_wallet_alert_content": "Do you want to change current wallet to ${wallet_name}?", "change_wallet_alert_title": "Change current wallet", "charts": "Charts", + "charts_unavailable": "Charts unavailable", + "charts_unavailable_desc": "Please enable the Fiat API in Settings.", "check_receiver_forms": "Please, check receiver forms", "choose_a_payment_method": "Choose a payment method", "choose_a_provider": "Choose a provider",