feat(app): label watch-only send flow and export unsigned PSBT

Send already refused to enable Confirm for watch-only accounts (Signed
false), but the App had no way to get the resulting PSBT out to sign
elsewhere — only the CLI printed it. Adds a base64 PSBT box + copy button
in the Send summary card, and a visible warning banner explaining the
wallet cannot sign, on both desktop and mobile layouts.
This commit is contained in:
2026-07-19 12:39:17 +02:00
parent f0fb5bfcc6
commit 9b00002e39
5 changed files with 65 additions and 2 deletions
+37 -2
View File
@@ -445,7 +445,7 @@
<!-- ── DESKTOP: Recipient | Amount side-by-side ── -->
<Grid IsVisible="{Binding IsDesktop}"
RowDefinitions="Auto,Auto,Auto" RowSpacing="14">
RowDefinitions="Auto,Auto,Auto,Auto" RowSpacing="14">
<Grid Grid.Row="0" ColumnDefinitions="*,*" ColumnSpacing="14">
<!-- Recipient card -->
@@ -516,11 +516,29 @@
<SelectableTextBlock Text="{Binding SendPreview}"
TextWrapping="Wrap" FontSize="13" Classes="mono"
Foreground="{DynamicResource TextSecondaryBrush}"/>
<StackPanel Spacing="6"
IsVisible="{Binding PendingPsbtBase64, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
<TextBlock Text="{Binding Loc[send.psbt.label]}" Classes="label"/>
<Grid ColumnDefinitions="*,Auto">
<TextBox Grid.Column="0" Text="{Binding PendingPsbtBase64}" IsReadOnly="True"
FontFamily="monospace" FontSize="11" TextWrapping="Wrap"
AcceptsReturn="True" Height="90"/>
<Button Grid.Column="1" Margin="8,0,0,0"
Content="{Binding Loc[send.psbt.copy]}"
Click="OnCopyPsbtClick"/>
</Grid>
</StackPanel>
</StackPanel>
</Border>
<!-- Watch-only notice -->
<TextBlock Grid.Row="2" Text="{Binding Loc[send.watchonly.hint]}"
IsVisible="{Binding IsWatchOnlyAccount}"
TextWrapping="Wrap" FontSize="12"
Foreground="{DynamicResource WarningBrush}"/>
<!-- Action buttons -->
<Grid Grid.Row="2" ColumnDefinitions="*,*" ColumnSpacing="14">
<Grid Grid.Row="3" ColumnDefinitions="*,*" ColumnSpacing="14">
<Button Grid.Column="0" Content="{Binding Loc[send.prepare]}"
Command="{Binding PrepareSendCommand}"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
@@ -620,9 +638,26 @@
<SelectableTextBlock Text="{Binding SendPreview}"
TextWrapping="Wrap" FontSize="13" Classes="mono"
Foreground="{DynamicResource TextSecondaryBrush}"/>
<StackPanel Spacing="6"
IsVisible="{Binding PendingPsbtBase64, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
<TextBlock Text="{Binding Loc[send.psbt.label]}" Classes="label"/>
<TextBox Text="{Binding PendingPsbtBase64}" IsReadOnly="True"
FontFamily="monospace" FontSize="11" TextWrapping="Wrap"
AcceptsReturn="True" Height="90"/>
<Button Content="{Binding Loc[send.psbt.copy]}"
Click="OnCopyPsbtClick"
MinHeight="44"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
</StackPanel>
</StackPanel>
</Border>
<!-- Watch-only notice -->
<TextBlock Text="{Binding Loc[send.watchonly.hint]}"
IsVisible="{Binding IsWatchOnlyAccount}"
TextWrapping="Wrap" FontSize="12"
Foreground="{DynamicResource WarningBrush}"/>
<!-- Action buttons: primary (Confirm) prominent, secondary below -->
<Button Content="{Binding Loc[send.confirm]}" Classes="accent"
Command="{Binding ConfirmSendCommand}"