Files
hash-wallet/lib/new-ui/widgets/charts_page/chart_header.dart
T
jwinterm dd449f2594 Merge upstream Cake Wallet v6.5.0
Catches up from the May 12 fork point (v6.1.2+23) through v6.5.0: 535
upstream commits, including the Monero silent-open fix, Monero on Trezor,
Ledger/Trezor BLE fixes, the new seed and history screens, quick Bitcoin
sync, git-pinned dependencies (pubspec_overrides.yaml), frozen Hive
adapters (*.part.dart), monero_c v0.18.4.6-RC2 and Flutter 3.41.9.

Merged with both sides normalized first (import rename, 100-column
format), which took the conflict count from 614 paths to 322. The
procedure is now scripts/upstream_sync.sh.

Kept from Hash Bags:
- WalletType enum order and Hive IDs. SQLite stores WalletType.index and
  our order differs from upstream's; taking theirs would reread saved
  wallets as other chains. Our frozen adapter keeps the shipped IDs.
- The 1.0.2 legacy PIN and wallet-password decode and self-heal.
- Removed chains (Solana, Tron, Zano, Zcash, Decred, Haven) and the new
  Robinhood chain stay out; Cake Pay and non-Trocador swaps stay out.
- Default nodes (node.wownero.org, sethforprivacy, Blockstream, bysh.me),
  converted to upstream's isDefault node-list key; Wownero is back in the
  node reset list.
- Privacy: address resolvers limited to domain-anchored sources again;
  prices.neroswap.com for fiat; upstream's charts tab, which reads
  prices.cakewallet.com, sits behind FeatureFlag.isChartsEnabled = false.
- Lightning stays behind FeatureFlag.isLightningEnabled, including
  upstream's new post-seed Lightning username step.
- Our icon pipeline, branding and bundle identifiers.

Twelve new upstream widget tests are skipped: test and code are unchanged
from v6.5.0 apart from renames (not rerun on a pristine upstream checkout;
upstream's top_bar_test does not compile against its own TopBar).
flutter analyze lib: 0 errors; flutter test: 345 passed, 12 skipped;
flutter build bundle compiles. Built with Flutter 3.41.9.
2026-10-24 23:49:29 -04:00

165 lines
7.3 KiB
Dart

import "package:hash_wallet/new-ui/viewmodels/charts/charts_bloc.dart";
import "package:hash_wallet/new-ui/widgets/charts_page/change_display.dart";
import "package:hash_wallet/new-ui/widgets/charts_page/chart_view.dart";
import "package:hash_wallet/new-ui/widgets/charts_page/coin_header.dart";
import "package:hash_wallet/new-ui/widgets/charts_page/price_header.dart";
import "package:hash_wallet/new-ui/widgets/charts_page/range_selector.dart";
import "package:hash_wallet/src/widgets/hash_image_widget.dart";
import "package:cw_core/amount/money_double.dart";
import "package:cw_core/crypto_currency.dart";
import "package:flutter/cupertino.dart";
import "package:flutter/material.dart";
import "package:flutter/services.dart";
import "package:flutter_bloc/flutter_bloc.dart";
import "package:intl/intl.dart";
class ChartHeader extends StatefulWidget {
const ChartHeader({
required this.bloc, super.key,
required this.currency,
required this.chartHeight,
required this.chartPadding,
required this.centered,
required this.favorite,
});
final CryptoCurrency currency;
final double chartHeight;
final double chartPadding;
final bool centered;
final bool favorite;
final ChartsBloc bloc;
@override
State<ChartHeader> createState() => _ChartHeaderState();
}
class _ChartHeaderState extends State<ChartHeader> {
String? _viewedPrice;
String? _viewedTime;
@override
Widget build(BuildContext context) => BlocBuilder<ChartsBloc, ChartsState>(
bloc: widget.bloc,
builder: (context, state) {
if (state case final ChartsStateWithData s) {
return Column(
crossAxisAlignment:
widget.centered ? CrossAxisAlignment.center : CrossAxisAlignment.start,
spacing: 10,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: Column(
crossAxisAlignment:
widget.centered ? CrossAxisAlignment.center : CrossAxisAlignment.start,
spacing: 10,
children: [
if (!widget.favorite)
HashImageWidget(
imageUrl: widget.currency.iconPath ?? "",
width: 60,
height: 60,
),
ChartViewCoinHeader(currency: widget.currency, isFavorite: widget.favorite),
ChartViewPriceHeader(
price: _viewedPrice ?? s.priceFor(widget.currency)?.toStringWithPrecision(fractionalDigits: 2) ?? "...",
ticker: s.fiatTicker,
highlight: _viewedPrice != null,
),
Column(
crossAxisAlignment:
widget.centered ? CrossAxisAlignment.center : CrossAxisAlignment.start,
children: [
Container(
// has to be constant-size, otherwise will jump around when loading
height: 36,
alignment: widget.centered ? Alignment.center : Alignment.centerLeft,
child: (s is ChartsLoaded)
? (_viewedPrice != null && _viewedTime != null)
? Text(
_viewedTime!,
style: TextStyle(
fontFamily: "IBM Plex Mono",
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.onSurfaceVariant,
fontSize: 16,
),
)
: ChangeDisplay(
changeData: s.changeDataFor(widget.currency),
ticker: s.fiatTicker,
)
: const SizedBox.shrink(),
),
if (s is ChartsLoaded)
Padding(
padding: EdgeInsets.symmetric(vertical: widget.chartPadding),
child: PriceChart(
height: widget.chartHeight,
prices: s.dataFor(widget.currency),
direction: s.changeDataFor(widget.currency).direction,
touchCallback: (event, response) {
if (!event.isInterestedForInteractions) {
setState(() {
_viewedPrice = null;
_viewedTime = null;
});
return;
}
final newPrice =
response?.lineBarSpots?.firstOrNull?.y.toStringAsFixed(2);
final newTime = DateFormat("M/d/y HH:mm").format(
DateTime.fromMillisecondsSinceEpoch(
response?.lineBarSpots?.firstOrNull?.x.toInt() ?? 0,
),
);
if (_viewedPrice != newPrice) {
HapticFeedback.selectionClick();
setState(() {
_viewedPrice = newPrice;
});
}
if (_viewedTime != newTime) {
setState(() {
_viewedTime = newTime;
});
}
},
),
)
else
SizedBox(
height: widget.chartHeight + widget.chartPadding * 2,
child: const Center(child: CupertinoActivityIndicator()),
),
],
),
],
),
),
Container(
width: double.infinity,
height: 1,
color: Theme.of(context).colorScheme.onSurfaceVariant.withAlpha(128),
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ChartRangeSelector(
selectedRange: s.range,
onRangeSelected: (range) =>
widget.bloc.add(RangeChanged(newRange: range)),
),
],
),
],
);
}
return const CupertinoActivityIndicator();
},
);
}