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

121 lines
3.6 KiB
Dart

import 'dart:io';
import 'package:hash_wallet/core/backup_service_v3.dart';
import 'package:hash_wallet/core/execution_state.dart';
import 'package:hash_wallet/core/secure_storage.dart';
import 'package:hash_wallet/entities/default_settings_migration.dart' show generateBackupPassword;
import 'package:hash_wallet/entities/secret_store_key.dart';
import 'package:hash_wallet/view_model/edit_backup_password_view_model.dart';
import 'package:cw_core/root_dir.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:mobx/mobx.dart';
import 'package:intl/intl.dart';
import 'package:hash_wallet/wallet_type_utils.dart';
part 'backup_view_model.g.dart';
class BackupExportFile {
BackupExportFile(this.file, {required this.name});
final String name;
final File file;
}
class BackupViewModel = BackupViewModelBase with _$BackupViewModel;
abstract class BackupViewModelBase with Store {
BackupViewModelBase(this.secureStorage, this.backupService, this.editBackupPasswordViewModel)
: isBackupPasswordVisible = false,
backupPassword = '',
state = InitialExecutionState() {
init();
reaction((_) => editBackupPasswordViewModel.backupPassword, (value) {
if(value != backupPassword) {
backupPassword = value;
}
});
reaction((_)=>backupPassword, (value){
if(value != editBackupPasswordViewModel.backupPassword) {
editBackupPasswordViewModel.backupPassword = value;
}
});
}
final SecureStorage secureStorage;
final BackupServiceV3 backupService;
final EditBackupPasswordViewModel editBackupPasswordViewModel;
@observable
ExecutionState state;
@observable
bool isBackupPasswordVisible;
@observable
String backupPassword;
@action
Future<void> init() async {
final key = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
backupPassword = (await secureStorage.read(key: key)) ?? '';
if (backupPassword.isEmpty) {
generateBackupPassword(secureStorage);
}
}
@action
Future<BackupExportFile?> exportBackup() async {
try {
state = IsExecutingState();
final backupFile = await backupService.exportBackupFile(backupPassword);
state = ExecutedSuccessfullyState();
final now = DateTime.now();
final formatter = DateFormat('yyyy-MM-dd_Hm');
final snakeAppName = approximatedAppName.replaceAll(' ', '_').toLowerCase();
final fileName = '${snakeAppName}_backup_${formatter.format(now)}.zip';
return BackupExportFile(backupFile, name: fileName);
} catch (e) {
printV(e.toString());
state = FailureState(e.toString());
return null;
}
}
Future<String> saveBackupFileLocally(BackupExportFile backup) async {
final appDir = await getAppDir();
final path = '${appDir.path}/${backup.name}';
if (File(path).existsSync()) {
File(path).deleteSync();
}
await backup.file.copy(path);
return path;
}
Future<void> removeBackupFileLocally(BackupExportFile backup) async {
final appDir = await getAppDir();
final path = '${appDir.path}/${backup.name}';
if (File(path).existsSync()) {
File(path).deleteSync();
}
}
@action
void showMasterPassword() => isBackupPasswordVisible = true;
@action
Future<void> saveToDownload(String name, File file) async {
if (!Platform.isAndroid) {
return;
}
const downloadDirPath = '/storage/emulated/0/Download'; // For Android
final filePath = '$downloadDirPath/${name}';
final downloadFile = File(filePath);
if (downloadFile.existsSync()) {
downloadFile.deleteSync();
}
await file.copy(filePath);
}
}