mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
Avoids any confusion / potential trademark friction with HashWallet
(Spanish hardware-wallet company). Hash Bags is a more distinctive
name, harder to collide with, and we can still rank for 'hash wallet'
search via App Store / Play Store subtitle ('Hash Bags - A Wallet
for your Coins').
What changed (all user-visible strings):
- Launcher labels: android/app.properties, scripts/android/app_env.sh,
scripts/ios/app_env.sh, linux window title (CMakeLists +
my_application.cc)
- In-app text: lib/generated/i18n.dart + ARB sources under res/values/
- Brand docs: README.md, CONTRIBUTING.md, PRIVACY.md,
assets/text/Terms_of_Use.txt, assets/text/Release_Notes.txt
- hash.boats website: index.html, og-image.svg + regen og-image.png,
site.webmanifest, styles.css comment, splash/confirm/pulse/mark/
lockup svg titles, report/index.html, server/server.js
- CI workflow display names ("Hash Bags Linux build", etc.)
What did NOT change (deliberate):
- Bundle ID / Package: com.suchsoftware.hashwallet (immutable app
identity on App Store + Play Store — changing == orphaning the app)
- Binary name: hash_wallet (Linux executable)
- Dart import paths: package:hash_wallet/...
- Git repo: hash-wallet (Such-Software/hash-wallet)
- URL scheme: hashwallet:// (internal deep links)
- support@such.software (no domain change yet)
- App Store / Play Store listing names (whatever was registered there
stays; we updated launcher label only)
- hash.boats domain (still the wallet site)
Also kept the '#ash Wallet' wordplay in the nav but updated to
'#ash Bags' so the # mark still serves as the H. Nav reads:
[# mark] #ash Bags
Website hero tagline now matches the App Store sub-title concept:
'A wallet for your coins. Open-source, non-custodial, multi-chain.
Privacy-leaning by default.'
108 files modified, ~674 string replacements.
136 lines
5.1 KiB
Dart
136 lines
5.1 KiB
Dart
import 'dart:io';
|
|
import 'package:cw_core/utils/print_verbose.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
String? _rootDirPath;
|
|
|
|
const String _tailsData = '/live/persistence/TailsData_unlocked/Persistent';
|
|
|
|
bool get isNonAmnesticTails {
|
|
try {
|
|
final os = File("/etc/os-release").readAsLinesSync();
|
|
for (var line in os) {
|
|
if (!line.startsWith("ID=")) continue;
|
|
if (!line.contains("tails")) continue;
|
|
return Directory(_tailsData).existsSync();
|
|
}
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool showNotice = true;
|
|
|
|
void setRootDirFromEnv() =>
|
|
// HASH_WALLET_DIR is the canonical override; CAKE_WALLET_DIR kept as a
|
|
// fallback so users migrating from a Cake install via env-var override
|
|
// don't lose their path.
|
|
_rootDirPath = Platform.environment['HASH_WALLET_DIR'] ?? Platform.environment['CAKE_WALLET_DIR'];
|
|
|
|
void copyDirectory(Directory source, Directory destination) {
|
|
source.listSync(recursive: false).forEach((var entity) {
|
|
if (entity is Directory) {
|
|
var newDirectory = Directory(p.join(destination.absolute.path, p.basename(entity.path)));
|
|
newDirectory.createSync(recursive: true);
|
|
copyDirectory(entity.absolute, newDirectory);
|
|
} else if (entity is File) {
|
|
destination.createSync(recursive: true);
|
|
entity.copySync(p.join(destination.path, p.basename(entity.path)));
|
|
}
|
|
});
|
|
}
|
|
|
|
Future<void> linuxSymlinkSharedPreferences() async {
|
|
if (!Platform.isLinux) return; // nuh-uh
|
|
final dataHome = Platform.environment["XDG_DATA_HOME"] ?? p.join(Platform.environment["HOME"] ?? "", ".local", "share");
|
|
// Names to migrate from on startup. Includes the legacy Cake paths so users
|
|
// forking from a previous Cake install get their data automatically
|
|
// symlinked into Hash Bags's new home (~/.local/share/hash_wallet).
|
|
var legacyNames = ['com.example.cake_wallet', 'cake_wallet'];
|
|
for (String name in legacyNames) {
|
|
final oldPath = p.join(dataHome, name);
|
|
final newPath = p.join((await getAppDir()).path, "_local_share");
|
|
final oldDir = Directory(oldPath);
|
|
final oldLink = Link(oldPath);
|
|
final newDir = Directory(newPath);
|
|
if (oldDir.existsSync()) {
|
|
if (oldLink.existsSync()) {
|
|
printV("not creating, link exists");
|
|
} else {
|
|
if (newDir.existsSync()) {
|
|
newDir.renameSync("${newPath}_${DateTime.now().millisecondsSinceEpoch~/1000}");
|
|
}
|
|
copyDirectory(oldDir, newDir);
|
|
oldDir.deleteSync(recursive: true);
|
|
}
|
|
}
|
|
if (!oldLink.existsSync()) {
|
|
oldLink.create(newPath, recursive: true);
|
|
}
|
|
if (!newDir.existsSync()) {
|
|
newDir.createSync(recursive: true);
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<Directory> getAppDir() async {
|
|
const String appName = 'hash_wallet';
|
|
Directory dir;
|
|
|
|
if (_rootDirPath != null && _rootDirPath!.isNotEmpty) {
|
|
dir = Directory.fromUri(Uri.file(_rootDirPath!));
|
|
dir.create(recursive: true);
|
|
} else {
|
|
if (Platform.isWindows) {
|
|
dir = await getApplicationSupportDirectory();
|
|
} else if (Platform.isLinux) {
|
|
String? appDirPath;
|
|
try {
|
|
dir = await getApplicationDocumentsDirectory();
|
|
appDirPath = '${dir.path}/$appName';
|
|
} catch (e) {
|
|
appDirPath = null;
|
|
}
|
|
// App will try to use last entry in here, so {distro,package}-specific paths can be
|
|
// be put as one of last items (tails - I'm looking at you), and other paths can be
|
|
// added in the order of preference
|
|
// Which currently is $HOME/.config/$appName - as this is the most standard directory
|
|
// for storing things that users in general back-up
|
|
var linuxAppPath = [
|
|
if (appDirPath != null) appDirPath, // old preferred
|
|
p.join('/home', Platform.environment['USER']??"null", appName), // old fallback
|
|
if (Platform.environment['HOME'] != null) p.join(Platform.environment['HOME']!, ".$appName"), // old fallback but using HOME
|
|
if (Platform.environment['HOME'] != null) p.join(Platform.environment['HOME']!, '.config', appName), // old fallback but using HOME
|
|
if (isNonAmnesticTails) p.join(_tailsData, ".$appName") // tails (if persistance is enabled)
|
|
];
|
|
|
|
String preferredPath = linuxAppPath.last;
|
|
|
|
preferredLoop:
|
|
for (String notSoPreferredPath in linuxAppPath) {
|
|
if (notSoPreferredPath == linuxAppPath.last) continue;
|
|
bool useThisOne = Directory(notSoPreferredPath).existsSync();
|
|
if (useThisOne) {
|
|
if (showNotice) {
|
|
showNotice = false;
|
|
printV("Not using $preferredPath because $notSoPreferredPath exists, falling back for backwards compatibility");
|
|
printV("Can't see your wallet? Check\n - ${linuxAppPath.join("\n - ")}\n and move directory that to $preferredPath");
|
|
printV("Or use CAKE_WALLET_DIR=/path/to/app/ ${Platform.executable}");
|
|
}
|
|
preferredPath = notSoPreferredPath;
|
|
break preferredLoop;
|
|
}
|
|
}
|
|
|
|
dir = Directory.fromUri(Uri.file(preferredPath));
|
|
await dir.create(recursive: true);
|
|
} else {
|
|
dir = await getApplicationDocumentsDirectory();
|
|
}
|
|
}
|
|
|
|
return dir;
|
|
}
|