2 Commits

Author SHA1 Message Date
davide c5290a1796 feat(ui): persist last server and split connection status text
- AppConfig stores LastServerHost/Port/UseSsl; restored on next launch
  so the wallet reconnects to the last-used server instead of defaulting
  to the first bootstrap entry
- Added ConnectionStatusShort for the status bar (short label only);
  ConnectionStatus retains the full "Connesso a ip:porta" shown in the
  server settings overlay
2026-06-18 19:34:41 +02:00
davide 227ec62d53 feat(ui): simplify server panel — remove TLS/Discover, show full address in status
- Removed TLS checkbox (SSL still used internally, just not exposed in UI)
- Removed "Discover servers" button (discovery now runs automatically on panel open)
- ConnectionStatus now includes host:port when connected ("Connesso a ip:porta")
- Replaced status ellipse+text with a single TextBlock
2026-06-18 19:29:33 +02:00
3 changed files with 48 additions and 39 deletions
+35 -6
View File
@@ -31,10 +31,13 @@ public partial class MainWindowViewModel
private bool isServerSettingsOpen; private bool isServerSettingsOpen;
[RelayCommand] [RelayCommand]
private void OpenServerSettings() private async Task OpenServerSettings()
{ {
IsSettingsOpen = false; IsSettingsOpen = false;
RefreshServers();
IsServerSettingsOpen = true; IsServerSettingsOpen = true;
if (_client is { IsConnected: true })
await DiscoverServers();
} }
[RelayCommand] [RelayCommand]
@@ -43,6 +46,9 @@ public partial class MainWindowViewModel
[ObservableProperty] [ObservableProperty]
private string connectionStatus = Loc.Tr("conn.none"); private string connectionStatus = Loc.Tr("conn.none");
[ObservableProperty]
private string connectionStatusShort = Loc.Tr("conn.none");
[ObservableProperty] [ObservableProperty]
private bool isConnected; private bool isConnected;
@@ -100,11 +106,24 @@ public partial class MainWindowViewModel
KnownServers.Clear(); KnownServers.Clear();
foreach (var server in Registry.All) foreach (var server in Registry.All)
KnownServers.Add(server); KnownServers.Add(server);
SelectedKnownServer = KnownServers.FirstOrDefault();
if (SelectedKnownServer is null) if (_config.LastServerHost is { Length: > 0 } savedHost && _config.LastServerPort is { } savedPort)
{ {
ServerHost = "127.0.0.1"; _syncingServerFields = true;
ServerPort = (UseSsl ? Profile.DefaultSslPort : Profile.DefaultTcpPort).ToString(); UseSsl = _config.LastServerUseSsl;
ServerHost = savedHost;
ServerPort = savedPort.ToString();
SelectedKnownServer = KnownServers.FirstOrDefault(s => s.Host == savedHost);
_syncingServerFields = false;
}
else
{
SelectedKnownServer = KnownServers.FirstOrDefault();
if (SelectedKnownServer is null)
{
ServerHost = "127.0.0.1";
ServerPort = (UseSsl ? Profile.DefaultSslPort : Profile.DefaultTcpPort).ToString();
}
} }
} }
@@ -176,6 +195,7 @@ public partial class MainWindowViewModel
foreach (var (h, p) in candidates) foreach (var (h, p) in candidates)
{ {
ConnectionStatus = $"{Loc.Tr("conn.connectingto")} {h}:{p}…"; ConnectionStatus = $"{Loc.Tr("conn.connectingto")} {h}:{p}…";
ConnectionStatusShort = Loc.Tr("conn.connectingto") + "…";
try try
{ {
var pins = new CertificatePinStore(AppPaths.CertificatePinsPath(Net)); var pins = new CertificatePinStore(AppPaths.CertificatePinsPath(Net));
@@ -185,10 +205,12 @@ public partial class MainWindowViewModel
{ {
IsConnected = false; IsConnected = false;
ConnectionStatus = Loc.Tr("conn.none"); ConnectionStatus = Loc.Tr("conn.none");
ConnectionStatusShort = Loc.Tr("conn.none");
}); });
IsConnected = true; IsConnected = true;
_autoReconnect = true; _autoReconnect = true;
ConnectionStatus = Loc.Tr("conn.connectedto"); ConnectionStatus = $"{Loc.Tr("conn.connectedto")} {h}:{p}";
ConnectionStatusShort = Loc.Tr("conn.connectedto");
// Update the UI to reflect the server actually connected. // Update the UI to reflect the server actually connected.
_syncingServerFields = true; _syncingServerFields = true;
ServerHost = h; ServerHost = h;
@@ -196,6 +218,11 @@ public partial class MainWindowViewModel
SelectedKnownServer = KnownServers.FirstOrDefault(s => s.Host == h) SelectedKnownServer = KnownServers.FirstOrDefault(s => s.Host == h)
?? SelectedKnownServer; ?? SelectedKnownServer;
_syncingServerFields = false; _syncingServerFields = false;
// Persist the last-used server so it is restored on next launch.
_config.LastServerHost = h;
_config.LastServerPort = p;
_config.LastServerUseSsl = UseSsl;
_config.Save();
lastError = null; lastError = null;
break; break;
} }
@@ -261,12 +288,14 @@ public partial class MainWindowViewModel
{ {
IsConnected = false; IsConnected = false;
ConnectionStatus = Loc.Tr("conn.none"); ConnectionStatus = Loc.Tr("conn.none");
ConnectionStatusShort = Loc.Tr("conn.none");
StatusMessage = ex.Message; StatusMessage = ex.Message;
} }
catch (Exception ex) catch (Exception ex)
{ {
IsConnected = _client?.IsConnected == true; IsConnected = _client?.IsConnected == true;
ConnectionStatus = IsConnected ? ConnectionStatus : Loc.Tr("conn.none"); ConnectionStatus = IsConnected ? ConnectionStatus : Loc.Tr("conn.none");
ConnectionStatusShort = IsConnected ? Loc.Tr("conn.connectedto") : Loc.Tr("conn.none");
StatusMessage = $"Errore: {ex.Message}"; StatusMessage = $"Errore: {ex.Message}";
if (_account is not null) if (_account is not null)
{ {
+8 -33
View File
@@ -895,7 +895,7 @@
IsVisible="{Binding IsConnected}"/> IsVisible="{Binding IsConnected}"/>
<Ellipse Width="10" Height="10" Fill="{DynamicResource DangerBrush}" VerticalAlignment="Center" <Ellipse Width="10" Height="10" Fill="{DynamicResource DangerBrush}" VerticalAlignment="Center"
IsVisible="{Binding !IsConnected}"/> IsVisible="{Binding !IsConnected}"/>
<TextBlock Text="{Binding ConnectionStatus}" FontSize="12" <TextBlock Text="{Binding ConnectionStatusShort}" FontSize="12"
Foreground="{DynamicResource SystemAccentColor}" Foreground="{DynamicResource SystemAccentColor}"
VerticalAlignment="Center"/> VerticalAlignment="Center"/>
</StackPanel> </StackPanel>
@@ -1164,21 +1164,17 @@
<TextBlock Text="{Binding Loc[server.title]}" <TextBlock Text="{Binding Loc[server.title]}"
FontSize="18" FontWeight="Bold"/> FontSize="18" FontWeight="Bold"/>
<!-- Host + port — Desktop: 3 columns --> <!-- Host + port — Desktop: 2 columns -->
<Grid ColumnDefinitions="*,Auto,Auto" RowDefinitions="Auto,Auto" <Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto"
IsVisible="{Binding IsDesktop}"> IsVisible="{Binding IsDesktop}">
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Loc[server.host]}" <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Loc[server.host]}"
FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/> FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Loc[server.port]}" <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Loc[server.port]}"
FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}" Margin="10,0,0,0" Width="90"/> FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}" Margin="10,0,0,0" Width="90"/>
<TextBlock Grid.Row="0" Grid.Column="2" Text="TLS"
FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}" Margin="10,0,0,0"/>
<TextBox Grid.Row="1" Grid.Column="0" Text="{Binding ServerHost}" <TextBox Grid.Row="1" Grid.Column="0" Text="{Binding ServerHost}"
FontFamily="monospace" Margin="0,2,0,0"/> FontFamily="monospace" Margin="0,2,0,0"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding ServerPort}" <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding ServerPort}"
FontFamily="monospace" Width="90" Margin="10,2,0,0"/> FontFamily="monospace" Width="90" Margin="10,2,0,0"/>
<CheckBox Grid.Row="1" Grid.Column="2" IsChecked="{Binding UseSsl}"
Margin="10,2,0,0" VerticalAlignment="Center"/>
</Grid> </Grid>
<!-- Host + port — Mobile: vertical, larger font --> <!-- Host + port — Mobile: vertical, larger font -->
<StackPanel Spacing="10" IsVisible="{Binding IsMobile}"> <StackPanel Spacing="10" IsVisible="{Binding IsMobile}">
@@ -1186,27 +1182,16 @@
<TextBlock Text="{Binding Loc[server.host]}" FontSize="13" Foreground="{DynamicResource TextSecondaryBrush}"/> <TextBlock Text="{Binding Loc[server.host]}" FontSize="13" Foreground="{DynamicResource TextSecondaryBrush}"/>
<TextBox Text="{Binding ServerHost}" FontFamily="monospace" FontSize="15"/> <TextBox Text="{Binding ServerHost}" FontFamily="monospace" FontSize="15"/>
</StackPanel> </StackPanel>
<Grid ColumnDefinitions="*,Auto"> <StackPanel Spacing="4">
<StackPanel Grid.Column="0" Spacing="4"> <TextBlock Text="{Binding Loc[server.port]}" FontSize="13" Foreground="{DynamicResource TextSecondaryBrush}"/>
<TextBlock Text="{Binding Loc[server.port]}" FontSize="13" Foreground="{DynamicResource TextSecondaryBrush}"/> <TextBox Text="{Binding ServerPort}" FontFamily="monospace" FontSize="15"/>
<TextBox Text="{Binding ServerPort}" FontFamily="monospace" FontSize="15"/> </StackPanel>
</StackPanel>
<StackPanel Grid.Column="1" Spacing="4" Margin="20,0,0,0"
VerticalAlignment="Center">
<TextBlock Text="TLS" FontSize="13" Foreground="{DynamicResource TextSecondaryBrush}"
HorizontalAlignment="Center"/>
<CheckBox IsChecked="{Binding UseSsl}"
HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
</StackPanel> </StackPanel>
<!-- Actions — Desktop: in a row --> <!-- Actions — Desktop: in a row -->
<StackPanel Orientation="Horizontal" Spacing="8" IsVisible="{Binding IsDesktop}"> <StackPanel Orientation="Horizontal" Spacing="8" IsVisible="{Binding IsDesktop}">
<Button Content="{Binding Loc[wallet.connect]}" Classes="accent" <Button Content="{Binding Loc[wallet.connect]}" Classes="accent"
Command="{Binding ConnectAndSyncCommand}" IsEnabled="{Binding !IsSyncing}"/> Command="{Binding ConnectAndSyncCommand}" IsEnabled="{Binding !IsSyncing}"/>
<Button Content="{Binding Loc[wallet.discover]}"
Command="{Binding DiscoverServersCommand}"/>
<Button Content="{Binding Loc[wallet.resetcert]}" <Button Content="{Binding Loc[wallet.resetcert]}"
Command="{Binding ResetCertificatesCommand}"/> Command="{Binding ResetCertificatesCommand}"/>
</StackPanel> </StackPanel>
@@ -1215,23 +1200,13 @@
<Button Content="{Binding Loc[wallet.connect]}" Classes="accent" <Button Content="{Binding Loc[wallet.connect]}" Classes="accent"
Command="{Binding ConnectAndSyncCommand}" IsEnabled="{Binding !IsSyncing}" Command="{Binding ConnectAndSyncCommand}" IsEnabled="{Binding !IsSyncing}"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/> HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
<Button Content="{Binding Loc[wallet.discover]}"
Command="{Binding DiscoverServersCommand}"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
<Button Content="{Binding Loc[wallet.resetcert]}" <Button Content="{Binding Loc[wallet.resetcert]}"
Command="{Binding ResetCertificatesCommand}" Command="{Binding ResetCertificatesCommand}"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/> HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
</StackPanel> </StackPanel>
<!-- Connection status --> <!-- Connection status -->
<StackPanel Orientation="Horizontal" Spacing="6"> <TextBlock Text="{Binding ConnectionStatus}" Foreground="{DynamicResource TextSecondaryBrush}"/>
<Ellipse Width="10" Height="10" Fill="{DynamicResource SuccessBrush}" VerticalAlignment="Center"
IsVisible="{Binding IsConnected}"/>
<Ellipse Width="10" Height="10" Fill="{DynamicResource DangerBrush}" VerticalAlignment="Center"
IsVisible="{Binding !IsConnected}"/>
<TextBlock Text="{Binding ConnectionStatus}" Foreground="{DynamicResource TextSecondaryBrush}"
VerticalAlignment="Center"/>
</StackPanel>
<!-- Known servers: click to populate host/port --> <!-- Known servers: click to populate host/port -->
<TextBlock Text="{Binding Loc[server.known]}" FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/> <TextBlock Text="{Binding Loc[server.known]}" FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/>
+5
View File
@@ -15,6 +15,11 @@ public sealed class AppConfig
/// <summary>Display unit for amounts (see <see cref="Wallet.CoinAmount.Units"/>).</summary> /// <summary>Display unit for amounts (see <see cref="Wallet.CoinAmount.Units"/>).</summary>
public string Unit { get; set; } = "PLM"; public string Unit { get; set; } = "PLM";
/// <summary>Last successfully connected server, persisted across sessions.</summary>
public string? LastServerHost { get; set; }
public int? LastServerPort { get; set; }
public bool LastServerUseSsl { get; set; } = true;
private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true }; private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true };
public static AppConfig Load(string? path = null) public static AppConfig Load(string? path = null)