Files
jwinterm 04203654f1 Rename Flutter project + binary: cake_wallet -> hash_wallet
The big one. Touches 760+ files. Locks in the user's decision to break
import-line compatibility with upstream cake-tech/cake_wallet in exchange
for a binary named hash_wallet on every platform.

Changes:
- pubspec_description.yaml: project name cake_wallet -> hash_wallet
- 762 Dart files: every 'package:cake_wallet/...' import rewritten to
  'package:hash_wallet/...' (lib/, cw_*/lib/, tool/, test/, integration_test/)
- linux/CMakeLists.txt: BINARY_NAME cake_wallet -> hash_wallet
- windows/CMakeLists.txt: project + BINARY_NAME (CakeWallet -> HashWallet)
- windows/runner/Runner.rc: company / file / product strings to Hash Wallet
  + Such Software LLC copyright
- macos/Runner.xcodeproj/project_base.pbxproj: cake_wallet_new.app refs
  -> hash_wallet.app (macOS output bundle name)
- com.suchsoftware.HashWallet.yml (Flatpak): all binary path refs
  cake_wallet -> hash_wallet (e.g. /app/hash_wallet/hash_wallet)
- linux/com.suchsoftware.HashWallet.desktop: Exec=hash_wallet
- scripts/android/copy_monero_deps.sh: CW_DIR target path
- configure_hash_wallet.sh: error message typo (old filename)

INTENTIONALLY UNCHANGED:
- cw_* subpackage names (cw_core, cw_bitcoin, cw_wownero, etc.) — they
  remain as the historical 'cake wallet' naming; renaming them would
  cascade through every sub-package's internal structure
- Method channel name 'com.cake_wallet/native_utils' in iOS/macOS/Android
  AppDelegates and MainActivity — it's a string identifier that has to
  match the Dart side exactly. Renaming requires both-sides change; it's
  internal-only and not user-visible.
- ghcr.io/cake-tech/cake_wallet:debian13-... docker image references in
  build scripts — that's Cake Labs' published image we use as the build
  environment, not ours.

User data directory now follows the new binary name:
  ~/.local/share/hash_wallet/  (was ~/.local/share/cake_wallet/)
  ~/.config/hash_wallet/       (was ~/.config/cake_wallet/)
Existing users on the old name will need migration if any exist.
2026-05-16 11:33:25 -04:00

238 lines
12 KiB
Dart

import 'dart:async';
import 'dart:math';
import 'package:hash_wallet/generated/i18n.dart';
import 'package:hash_wallet/new-ui/viewmodels/card_customizer/card_customizer_bloc.dart';
import 'package:hash_wallet/new-ui/widgets/coins_page/cards/balance_card.dart';
import 'package:hash_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class CardCustomizer extends StatefulWidget {
const CardCustomizer({super.key, required this.cryptoTitle, required this.cryptoName});
final String cryptoTitle;
final String cryptoName;
@override
State<CardCustomizer> createState() => _CardCustomizerState();
}
class _CardCustomizerState extends State<CardCustomizer> {
final accountNameController = TextEditingController();
bool editEnabled = false;
late final CardCustomizerBloc bloc;
@override
void initState() {
super.initState();
bloc = context.read<CardCustomizerBloc>();
if (bloc.state is! CardCustomizerNotLoaded) {
editEnabled = bloc.state.accountName.isNotEmpty;
accountNameController.text = bloc.state.accountName;
} else {
late final StreamSubscription sub;
sub = bloc.stream.listen((state) {
if (state is! CardCustomizerNotLoaded) {
setState(() {
editEnabled = state.accountName.isNotEmpty;
});
sub.cancel();
}
});
}
}
@override
Widget build(BuildContext context) {
return BlocListener<CardCustomizerBloc, CardCustomizerState>(
listenWhen: (previous, current) =>
previous.accountName != current.accountName,
listener: (context, state) {
if(accountNameController.text != state.accountName) {
accountNameController.text = state.accountName;
}
},
child: BlocBuilder<CardCustomizerBloc, CardCustomizerState>(
builder: (context, state) {
if (state is CardCustomizerNotLoaded) return SizedBox.shrink();
return PopScope(
child: SingleChildScrollView(
child: SafeArea(
child: Column(
spacing: 25.0,
mainAxisSize: MainAxisSize.min,
children: [
ModalTopBar(
title: editEnabled ? S.of(context).edit_account : S.of(context).edit_card,
leadingIcon: Icon(Icons.close),
// trailingIcon: editEnabled ? Icon(Icons.delete_forever) : null,
onLeadingPressed: () => Navigator.of(context).maybePop(),
// onTrailingPressed: () {},
),
if (editEnabled)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0),
child: Column(
spacing: 8.0,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(S.of(context).account_name),
TextField(
maxLength: 32,
decoration: InputDecoration(counterText: ""),
onChanged: (value) {
context.read<CardCustomizerBloc>().add(AccountNameChanged(value));
},
controller: accountNameController,
)
],
),
),
BalanceCard(
width: min(MediaQuery.of(context).size.width * 0.87, 768),
selected: true,
designSwitchDuration: Duration(milliseconds: 300),
accountName:
editEnabled ? state.accountName:"" ,
balance: "0.00",
assetName: state.displaySats ? "sats" : widget.cryptoName,
capitalizeAssetName: !state.displaySats,
design: state.selectedDesign,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
spacing: 8.0,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(S.of(context).card_style),
Container(
height: 63,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: state.availableDesigns.length,
separatorBuilder: (context, index) {
return SizedBox(width: 8.0);
},
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
context
.read<CardCustomizerBloc>()
.add(CardDesignSelected(index));
},
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
decoration: ShapeDecoration(
shape: RoundedSuperellipseBorder(
side: BorderSide(color: ((index == state.selectedDesignIndex )? Theme.of(context).colorScheme.onSurface : Colors.transparent), width: 1),
borderRadius: BorderRadiusGeometry.circular(12),
),
),
child: AnimatedScale(
duration: Duration(milliseconds: 200),
scale: index == state.selectedDesignIndex ? 0.94 : 1,
child: BalanceCard(
width: 96,
borderRadius: 10,
selected: false,
designSwitchDuration: Duration(milliseconds: 300),
design: state.availableDesigns[index],
gradient: state.selectedDesign.gradient,
),
),
),
);
}),
),
],
)),
SizedBox(height: 8),
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
spacing: 8.0,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(S.of(context).color),
Container(
width: double.infinity,
child: Wrap(
direction: Axis.horizontal,
spacing: 4, // space between items in a row
runSpacing: 8,
children:
List.generate(state.availableColors.length, (index) {
return Material(
borderRadius: BorderRadius.circular(999999999),
child: InkWell(
borderRadius: BorderRadius.circular(999999999),
onTap: () {
context
.read<CardCustomizerBloc>()
.add(ColorSelected(index));
},
child: Stack(
children: [
AnimatedOpacity(
duration: Duration(milliseconds: 200),
opacity: index == state.selectedColorIndex ? 1 : 0,
child: Container(
width:32,height:32,decoration: BoxDecoration(borderRadius: BorderRadius.circular(99999999),border: Border.all(color:Theme.of(context)
.colorScheme
.onSurface))
),
),
AnimatedScale(
duration: Duration(milliseconds: 200),
scale: index == state.selectedColorIndex ? 0.8 : 1,
child: Container(
width: 32,
height: 32,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(99999999),
gradient: state.availableColors[index]),
),
),
],
),
),
);
}),
)),
],
),
),
)
],
),
)),
],
),
),
),
);
},
),
);
}
}