Compare commits

...

3 Commits

Author SHA1 Message Date
jwinterm
86b4040c9b Linux: package release as self-contained AppImage
The previous Linux artifact was a zip of the Flutter bundle/ directory.
That's awkward to distribute — users have to unzip, find the binary,
chmod +x, and figure out the lib/ layout themselves. Replace with a
proper AppImage: single file, double-click to run, no install, no
Flutter knowledge required.

Build steps:
- Stage AppDir with the Flutter bundle under usr/bin/ (the binary's
  RPATH=\$ORIGIN/lib already finds plugin libs there).
- Add .desktop file (Hash Bags / Office;Finance;) and 256x256 hash
  icon scaled from the iOS marketing PNG.
- Download appimagetool and invoke with --appimage-extract-and-run
  so it works inside the build container without FUSE.

Artifact name: hash-wallet-linux-appimage-<sha>.
2026-06-03 20:11:43 -04:00
jwinterm
2abff1fe06 Android version-from-pubspec + proper iOS tinted icons
Android had the same hardcoded CAKEWALLET_BUILD_NUMBER=1 bug we just
fixed for iOS — bumping pubspec_description.yaml would not have moved
Play Store versionCode at all, and the second AAB upload would have
been rejected for duplicate versionCode. Mirror the iOS fix: parse
the build number from pubspec_description.yaml in scripts/android/app_env.sh.

Regenerate the 16 Tinted iOS icon slices as black bg + white hash mark.
The previous slices reused the green-bg light variant, which iOS 18+
cannot meaningfully tint (green-on-green collapses when the system
applies the home-screen accent color). Black background + white shape
gives iOS a clean luminance map to tint against.

Wownero monero! audit: cleared. Audit flagged two callsites in
fees_view_model.dart, but both wownero!.getWowneroTransactionPriority*
and monero!.getMoneroTransactionPriority* return the same
MoneroTransactionPriority singleton (cw_wownero.dart:158 +
cw_monero.dart:169), so the cross-call is inelegant but not buggy.

Bump 1.0.0+6 -> 1.0.0+7.
2026-06-03 09:31:24 -04:00
jwinterm
21f3a75aa5 Wownero: dispatch getCurrentAccount by wallet.type in AccountCustomizer
The "Wallet Accounts" reorder modal threw on open for Wownero wallets:
account_customizer.dart unconditionally called monero!.getCurrentAccount,
which casts the wallet to MoneroWallet internally. WowneroWallet is a
sibling type, not a subtype, so the cast blew up before the active-card
swap logic ran.

Dispatch on wallet.type and use the wownero! proxy for Wownero, matching
the pattern already in card_customizer_bloc.dart, addresses_page.dart,
and dashboard_view_model.dart. Skip the swap entirely for any other
wallet type rather than guessing.

Bump 1.0.0+5 -> 1.0.0+6.
2026-06-03 09:15:10 -04:00
20 changed files with 92 additions and 11 deletions

View File

@@ -168,18 +168,86 @@ jobs:
- name: Build Linux app - name: Build Linux app
run: flutter build linux --dart-define-from-file=env.json --release run: flutter build linux --dart-define-from-file=env.json --release
- name: Compress release bundle # ---- Package as AppImage --------------------------------------------
# Self-contained .AppImage is the user-facing Linux deliverable: single
# file, double-click to run, no install, works on any glibc Linux from
# the last few years. appimagetool is run with --appimage-extract-and-run
# so it works inside the container without FUSE.
- name: Stage AppDir
run: | run: |
pushd build/linux/x64/release set -e -x
zip -r hash_wallet_linux_${{ github.sha }}.zip bundle REL=build/linux/x64/release
popd APPDIR=$REL/Hash_Bags.AppDir
rm -rf "$APPDIR"
mkdir -p "$APPDIR/usr/bin" \
"$APPDIR/usr/share/applications" \
"$APPDIR/usr/share/icons/hicolor/256x256/apps"
# The whole Flutter Linux bundle (binary + data/ + lib/) lives
# under usr/bin/. The Flutter binary has RPATH=$ORIGIN/lib, so
# plugin/native libs in usr/bin/lib/ resolve naturally.
cp -r "$REL/bundle"/* "$APPDIR/usr/bin/"
# Icon: scale the iOS marketing icon to 256 if convert is around,
# else copy as-is (appimagetool only requires that AppDir root and
# the hicolor path contain a same-named PNG).
ICON_SRC=assets/images/ios_icons/hashwallet_ios_icons/Icon-App-1024x1024@1x.png
ICON_DEST="$APPDIR/usr/share/icons/hicolor/256x256/apps/hash_bags.png"
if command -v convert >/dev/null 2>&1; then
convert "$ICON_SRC" -resize 256x256 "$ICON_DEST"
else
cp "$ICON_SRC" "$ICON_DEST"
fi
cp "$ICON_DEST" "$APPDIR/hash_bags.png"
# .desktop file (at both canonical locations; appimagetool checks both)
cat > "$APPDIR/hash_bags.desktop" <<'DESKTOP'
[Desktop Entry]
Name=Hash Bags
Comment=Non-custodial multi-chain crypto wallet
Exec=hash_wallet
Icon=hash_bags
Type=Application
Categories=Office;Finance;
Terminal=false
DESKTOP
# Strip the leading whitespace from the heredoc
sed -i 's/^ //' "$APPDIR/hash_bags.desktop"
cp "$APPDIR/hash_bags.desktop" "$APPDIR/usr/share/applications/"
# AppRun: the entry point AppImage executes. Adds the bundled lib/
# dir to LD_LIBRARY_PATH and exec's the Flutter binary.
cat > "$APPDIR/AppRun" <<'APPRUN'
#!/bin/bash
HERE="$(dirname "$(readlink -f "${0}")")"
export LD_LIBRARY_PATH="${HERE}/usr/bin/lib:${LD_LIBRARY_PATH}"
exec "${HERE}/usr/bin/hash_wallet" "$@"
APPRUN
sed -i 's/^ //' "$APPDIR/AppRun"
chmod +x "$APPDIR/AppRun"
ls -la "$APPDIR"
- name: Build AppImage
run: |
set -e -x
REL=build/linux/x64/release
wget -q https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /tmp/appimagetool
chmod +x /tmp/appimagetool
# --appimage-extract-and-run avoids the FUSE requirement (no fusermount
# in the build container). ARCH= tells appimagetool which arch tag to
# embed in the filename.
ARCH=x86_64 /tmp/appimagetool --appimage-extract-and-run \
"$REL/Hash_Bags.AppDir" \
"$REL/Hash_Bags-x86_64.AppImage"
ls -la "$REL"/*.AppImage
# actions/upload-artifact@v4 uses an HTTP API that Gitea Actions does # actions/upload-artifact@v4 uses an HTTP API that Gitea Actions does
# not implement (only the v1/v3 wire format). Pinned to @v3 for Gitea # not implement (only the v1/v3 wire format). Pinned to @v3 for Gitea
# compatibility — also works on GitHub Actions. # compatibility — also works on GitHub Actions.
- name: Upload artifact - name: Upload AppImage artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: hash-wallet-linux-${{ github.sha }} name: hash-wallet-linux-appimage-${{ github.sha }}
path: build/linux/x64/release/hash_wallet_linux_*.zip path: build/linux/x64/release/Hash_Bags-x86_64.AppImage
retention-days: 14 retention-days: 14

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -2,6 +2,7 @@ import 'dart:ui';
import 'package:hash_wallet/di.dart'; import 'package:hash_wallet/di.dart';
import 'package:hash_wallet/generated/i18n.dart'; import 'package:hash_wallet/generated/i18n.dart';
import 'package:hash_wallet/monero/monero.dart'; import 'package:hash_wallet/monero/monero.dart';
import 'package:hash_wallet/wownero/wownero.dart';
import 'package:hash_wallet/new-ui/pages/card_customizer.dart'; import 'package:hash_wallet/new-ui/pages/card_customizer.dart';
import 'package:hash_wallet/new-ui/viewmodels/card_customizer/card_customizer_bloc.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/coins_page/cards/balance_card.dart';
@@ -21,6 +22,7 @@ import 'package:cw_core/card_design.dart';
import 'package:cw_core/generate_name.dart'; import 'package:cw_core/generate_name.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@@ -62,7 +64,13 @@ class _AccountCustomizerState extends State<AccountCustomizer> {
super.initState(); super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
loadCards(); loadCards();
final activeId = monero!.getCurrentAccount(widget.dashboardViewModel.wallet).id; final wallet = widget.dashboardViewModel.wallet;
final int? activeId = wallet.type == WalletType.monero
? monero?.getCurrentAccount(wallet).id
: wallet.type == WalletType.wownero
? wownero?.getCurrentAccount(wallet).id
: null;
if (activeId == null) return;
for (int i = 0; i < _items.length-1; i++) { for (int i = 0; i < _items.length-1; i++) {
if(_items[i].accountListItem.id == activeId) { if(_items[i].accountListItem.id == activeId) {
final lastIndex = _items.length - 1; final lastIndex = _items.length - 1;

View File

@@ -1,6 +1,6 @@
name: hash_wallet name: hash_wallet
description: Hash Bags — a noncustodial multi-currency wallet by Such Software LLC. description: Hash Bags — a noncustodial multi-currency wallet by Such Software LLC.
version: 1.0.0+5 version: 1.0.0+7
publish_to: none publish_to: none
environment: environment:

View File

@@ -20,9 +20,14 @@ MONERO_COM_BUNDLE_ID="com.monero.app"
MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_PACKAGE="com.monero.app"
MONERO_COM_SCHEME="monero.com" MONERO_COM_SCHEME="monero.com"
# Source CAKEWALLET version + build number from pubspec_description.yaml
# (single source of truth across iOS/Android). Without this, the hardcoded
# build number here would silently override pubspec via inject_app_details.sh
# and every Play Store upload would ship as versionCode 1.
_PUBSPEC_VERSION=$(awk -F': ' '/^version:/ {print $2; exit}' ../../pubspec_description.yaml)
CAKEWALLET_NAME="Hash Bags" CAKEWALLET_NAME="Hash Bags"
CAKEWALLET_VERSION="1.0.0" CAKEWALLET_VERSION="${_PUBSPEC_VERSION%+*}"
CAKEWALLET_BUILD_NUMBER=1 CAKEWALLET_BUILD_NUMBER="${_PUBSPEC_VERSION#*+}"
CAKEWALLET_BUNDLE_ID="com.suchsoftware.hashwallet" CAKEWALLET_BUNDLE_ID="com.suchsoftware.hashwallet"
CAKEWALLET_PACKAGE="com.suchsoftware.hashwallet" CAKEWALLET_PACKAGE="com.suchsoftware.hashwallet"
CAKEWALLET_SCHEME="hashbags" CAKEWALLET_SCHEME="hashbags"