Files
PalladiumWallet/src/App/Views/MainView.axaml.cs
T
davide 34b4313a36 feat(app): check GitHub releases on startup and prompt for updates
Compares the running assembly version against the latest GitHub release
tag on every app launch (desktop and Android) and shows an in-app
overlay with the new version tag when one is available. Best-effort:
network/parse failures are silent, matching the app's existing
non-blocking startup checks.
2026-07-02 21:33:18 +02:00

173 lines
6.7 KiB
C#

using System;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using Avalonia.VisualTree;
using PalladiumWallet.App.ViewModels;
namespace PalladiumWallet.App.Views;
/// <summary>
/// App root view, shared between desktop (hosted in <see cref="MainWindow"/>)
/// and mobile (single-view root). All overlays are in-app so no separate windows
/// are needed. Top-level APIs (file picker, clipboard) are reached via
/// <see cref="TopLevel.GetTopLevel"/> because a UserControl does not expose them.
/// </summary>
public partial class MainView : UserControl
{
public MainView()
{
InitializeComponent();
}
private void OnHistoryRowDoubleTapped(object? sender, TappedEventArgs e)
{
if (sender is not ListBox lb || DataContext is not MainWindowViewModel vm) return;
if (lb.SelectedItem is not HistoryRow row) return;
// In-app overlay: appears immediately with a spinner; data arrives from
// the server in the background. No top-level window (slow to open/close).
_ = vm.ShowTransactionDetailsAsync(row.Txid);
}
private void OnTxDetailsOverlayBackdropTapped(object? sender, TappedEventArgs e)
{
if (!ReferenceEquals(e.Source, sender)) return;
if (DataContext is MainWindowViewModel vm)
vm.CloseTransactionDetailsCommand.Execute(null);
}
private void OnAddressListTapped(object? sender, TappedEventArgs e)
{
if (DataContext is not MainWindowViewModel vm || vm.SelectedAddressRow is not { } row)
return;
vm.ShowAddressInfo(row);
}
private void OnAddressListPointerPressed(object? sender, PointerPressedEventArgs e)
{
if (!e.GetCurrentPoint(null).Properties.IsRightButtonPressed) return;
if (sender is not ListBox lb || DataContext is not MainWindowViewModel vm) return;
var item = (e.Source as Visual)?.FindAncestorOfType<ListBoxItem>();
if (item is not { DataContext: AddressRow row }) return;
lb.SelectedItem = row;
vm.ShowAddressInfo(row);
}
// Close the address-detail overlay: click on the dark backdrop
// (backdrop only, not the card itself) or press Esc.
private void OnAddressOverlayBackdropTapped(object? sender, TappedEventArgs e)
{
if (!ReferenceEquals(e.Source, sender)) return;
if (DataContext is MainWindowViewModel vm)
vm.AddressInfo = null;
}
private void OnServerOverlayBackdropTapped(object? sender, TappedEventArgs e)
{
if (!ReferenceEquals(e.Source, sender)) return;
if (DataContext is MainWindowViewModel vm)
vm.IsServerSettingsOpen = false;
}
private async void OnChooseDataFolderClick(object? sender, RoutedEventArgs e)
{
if (DataContext is not MainWindowViewModel vm) return;
if (TopLevel.GetTopLevel(this)?.StorageProvider is not { } storage) return;
var folders = await storage.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
Title = "Cartella dati Palladium Wallet",
AllowMultiple = false,
});
if (folders.FirstOrDefault()?.TryGetLocalPath() is { } path)
vm.ApplyDataLocation(path);
}
private async void OnCopyReceiveAddressClick(object? sender, RoutedEventArgs e)
{
if (DataContext is not MainWindowViewModel vm || string.IsNullOrEmpty(vm.ReceiveAddress))
return;
if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard)
{
await clipboard.SetTextAsync(vm.ReceiveAddress);
vm.NotifyAddressCopied();
}
}
private void OnConnectionStatusTapped(object? sender, TappedEventArgs e)
{
if (DataContext is MainWindowViewModel vm)
vm.IsServerSettingsOpen = true;
}
private void OnWalletInfoOverlayBackdropTapped(object? sender, TappedEventArgs e)
{
if (!ReferenceEquals(e.Source, sender)) return;
if (DataContext is MainWindowViewModel vm)
vm.CloseWalletInfoCommand.Execute(null);
}
private void OnSettingsOverlayBackdropTapped(object? sender, TappedEventArgs e)
{
if (!ReferenceEquals(e.Source, sender)) return;
if (DataContext is MainWindowViewModel vm)
vm.IsSettingsOpen = false;
}
private void OnHelpOverlayBackdropTapped(object? sender, TappedEventArgs e)
{
if (!ReferenceEquals(e.Source, sender)) return;
if (DataContext is MainWindowViewModel vm)
vm.IsHelpOpen = false;
}
private void OnUpdateAvailableOverlayBackdropTapped(object? sender, TappedEventArgs e)
{
if (!ReferenceEquals(e.Source, sender)) return;
if (DataContext is MainWindowViewModel vm)
vm.IsUpdateAvailableOpen = false;
}
private async void OnOpenBugReportClick(object? sender, RoutedEventArgs e)
{
const string issueUrl = "https://github.com/davide3011/PalladiumWallet/issues/new?template=bug_report.yml";
var launcher = TopLevel.GetTopLevel(this)?.Launcher;
if (launcher is not null)
await launcher.LaunchUriAsync(new Uri(issueUrl));
}
private async void OnOpenReleasePageClick(object? sender, RoutedEventArgs e)
{
if (DataContext is not MainWindowViewModel vm || string.IsNullOrEmpty(vm.UpdateReleaseUrl)) return;
var launcher = TopLevel.GetTopLevel(this)?.Launcher;
if (launcher is not null)
await launcher.LaunchUriAsync(new Uri(vm.UpdateReleaseUrl));
vm.IsUpdateAvailableOpen = false;
}
// Esc (desktop) or Back (Android) closes the topmost open overlay.
protected override void OnKeyDown(KeyEventArgs e)
{
if ((e.Key == Key.Escape || e.Key == Key.Back) && DataContext is MainWindowViewModel vm)
{
if (vm.IsTxDetailsOpen) { vm.CloseTransactionDetailsCommand.Execute(null); e.Handled = true; return; }
if (vm.IsPrivKeyPromptOpen) { vm.CancelPrivKeyPromptCommand.Execute(null); e.Handled = true; return; }
if (vm.AddressInfo is not null) { vm.CloseAddressInfoCommand.Execute(null); e.Handled = true; return; }
if (vm.IsServerSettingsOpen) { vm.IsServerSettingsOpen = false; e.Handled = true; return; }
if (vm.IsWalletInfoOpen) { vm.CloseWalletInfoCommand.Execute(null); e.Handled = true; return; }
if (vm.IsSettingsOpen) { vm.IsSettingsOpen = false; e.Handled = true; return; }
if (vm.IsHelpOpen) { vm.IsHelpOpen = false; e.Handled = true; return; }
if (vm.IsUpdateAvailableOpen) { vm.IsUpdateAvailableOpen = false; e.Handled = true; return; }
}
base.OnKeyDown(e);
}
}