mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
make charts respect fiat api mode (#3678)
* make charts respect fiat api mode * remove unused blocprovider * https -> http * https -> http
This commit is contained in:
+1
-1
@@ -571,7 +571,7 @@ Future<void> setup({
|
||||
(displayMode == BitcoinAmountDisplayMode.satoshiForLightning && lightningMode)));
|
||||
});
|
||||
|
||||
getIt.registerLazySingleton<PriceStore>(() => PriceStore());
|
||||
getIt.registerLazySingleton<PriceStore>(() => PriceStore(settingsStore: getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactory<ChartsBloc>(
|
||||
() => ChartsBloc(appStore: getIt.get<AppStore>(), priceStore: getIt.get<PriceStore>()));
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<ChartsBloc, ChartsState>(
|
||||
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<ChartsBloc, ChartsState>(
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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<ChartsEvent, ChartsState> {
|
||||
on<CurrencyPinned>(_onCurrencyPinned, transformer: sequential());
|
||||
on<PageRefreshed>(_onPageRefreshed, transformer: sequential());
|
||||
on<PageLoadStarted>(_onPageLoadStarted, transformer: restartable());
|
||||
on<Init>(_init);
|
||||
on<Init>(_init, transformer: sequential());
|
||||
}
|
||||
|
||||
final PriceStore priceStore;
|
||||
final AppStore appStore;
|
||||
|
||||
Future<void> _init(Init event, Emitter<ChartsState> 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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<ChartsBloc, ChartsState>(
|
||||
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<ChartsBloc>().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<ChartsBloc>().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<ChartsBloc>().add(CurrencyPinned(currency: currency));
|
||||
bloc.add(CurrencyPinned(currency: currency));
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
|
||||
@@ -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<ChartsBloc, ChartsState>(
|
||||
bloc: bloc,
|
||||
builder: (context, state) {
|
||||
final bloc = context.read<ChartsBloc>();
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
|
||||
@@ -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<ChartHeader> createState() => _ChartHeaderState();
|
||||
@@ -39,6 +40,7 @@ class _ChartHeaderState extends State<ChartHeader> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => BlocBuilder<ChartsBloc, ChartsState>(
|
||||
bloc: widget.bloc,
|
||||
builder: (context, state) {
|
||||
if (state case final ChartsStateWithData s) {
|
||||
return Column(
|
||||
@@ -149,7 +151,7 @@ class _ChartHeaderState extends State<ChartHeader> {
|
||||
ChartRangeSelector(
|
||||
selectedRange: s.range,
|
||||
onRangeSelected: (range) =>
|
||||
context.read<ChartsBloc>().add(RangeChanged(newRange: range)),
|
||||
widget.bloc.add(RangeChanged(newRange: range)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -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<ChartsBloc>()..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<NewBuySellAmountPage>(
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user