modified layout (#2)

Reviewed-on: #2
Co-authored-by: Aleksandr Neychev <alexnejchev73@gmail.com>
This commit was merged in pull request #2.
This commit is contained in:
2026-08-12 14:25:05 +00:00
committed by alex
parent 55ac8e6556
commit 68b3d544d2
14 changed files with 376 additions and 415 deletions
@@ -15,17 +15,15 @@ namespace CursorLang.Settings.ViewModels;
/// The updates section of the settings window.
/// </summary>
/// <remarks>
/// A check made on opening the window passes its failures in silence: the machine does
/// not always have a live network, and there is no point complaining about it to a user
/// who came to change the popup colour. A check started by the button does report a
/// failure — it is awaited and watched.
/// The section always says where things stand: a check flies off the moment the window
/// appears, and its outcome — including an unreachable network — stays written in the
/// status line. Nothing here is silent, and nothing disappears: a user who opened the
/// window is told about updates whether they came looking for them or not.
/// </remarks>
public sealed partial class UpdateViewModel : ObservableObject, IDisposable
{
private readonly IUpdateService _updates;
private readonly ILocalizationService _localization;
private readonly AppSettings _settings;
private readonly UpdateOptions _options;
private CancellationTokenSource? _work;
private ReleaseInfo? _release;
@@ -35,7 +33,6 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
[NotifyPropertyChangedFor(nameof(StatusText))]
[NotifyPropertyChangedFor(nameof(IsBusy))]
[NotifyPropertyChangedFor(nameof(CanCheck))]
[NotifyPropertyChangedFor(nameof(HasStatus))]
[NotifyPropertyChangedFor(nameof(IsProgressUnknown))]
[NotifyPropertyChangedFor(nameof(IsDownloadOffered))]
[NotifyPropertyChangedFor(nameof(IsInstallOffered))]
@@ -48,16 +45,10 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
[NotifyPropertyChangedFor(nameof(IsProgressUnknown))]
private double _progress;
public UpdateViewModel(
IUpdateService updates,
ILocalizationService localization,
AppSettings settings,
UpdateOptions options)
public UpdateViewModel(IUpdateService updates, ILocalizationService localization)
{
_updates = updates;
_localization = localization;
_settings = settings;
_options = options;
_localization.PropertyChanged += OnLocalizationChanged;
}
@@ -67,29 +58,11 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
public string CurrentVersion => _updates.CurrentVersion.ToString();
/// <summary>Check for new versions at startup.</summary>
public bool CheckAutomatically
{
get => _settings.CheckForUpdates;
set
{
if (value == _settings.CheckForUpdates)
{
return;
}
_settings.CheckForUpdates = value;
OnPropertyChanged();
}
}
/// <summary>A request or a download is in flight — the buttons freeze for that time.</summary>
public bool IsBusy => Status is UpdateStatus.Checking or UpdateStatus.Downloading;
public bool CanCheck => !IsBusy;
public bool HasStatus => Status != UpdateStatus.Idle;
/// <summary>
/// The package size is unknown, and the bar shows only the fact of the download.
/// Its start looks the same until the first report arrives.
@@ -107,6 +80,10 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
/// <summary>The release page: the release notes live there too.</summary>
public Uri? ReleaseUrl => _release?.PageUrl;
/// <summary>
/// What the section says. There is a line for every state, the one before the
/// first check included: the status is never an empty spot in the window.
/// </summary>
public string StatusText => Status switch
{
UpdateStatus.Checking => _localization["UpdateChecking"],
@@ -115,33 +92,24 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
UpdateStatus.Downloading => _localization["UpdateDownloading"],
UpdateStatus.Ready => _localization["UpdateReady"],
UpdateStatus.Failed => _localization["UpdateFailed"],
_ => string.Empty,
_ => _localization["UpdateNotChecked"],
};
/// <summary>
/// Checks for updates when the user has not forbidden it and enough time has
/// passed since the previous check. Called once when the window opens.
/// Asks about new versions. Called once, when the window has just appeared.
/// </summary>
/// <remarks>
/// It used to be called when the application started, which back then meant when
/// the machine was switched on. The background half is a separate process now and
/// does not go to the network at all — nothing in it could show the answer — so the
/// question is asked when there is a window to answer into.
///
/// And it is asked every time that window appears: opening it is a deliberate act
/// of the user, rare enough that a request costs nothing, and the answer is what
/// the section exists for. A remembered answer from yesterday is worth less than
/// today's, so nothing is remembered.
/// </remarks>
public async Task StartAsync()
{
if (!IsSupported || !_settings.CheckForUpdates)
{
return;
}
if (_settings.LastUpdateCheck is { } last && DateTimeOffset.UtcNow - last < _options.CheckInterval)
{
return;
}
await RunCheckAsync(quiet: true);
}
public Task StartAsync() => CheckAsync();
public void Dispose()
{
@@ -153,7 +121,36 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
}
[RelayCommand]
private Task CheckAsync() => RunCheckAsync(quiet: false);
private async Task CheckAsync()
{
if (!IsSupported)
{
return;
}
CancellationToken token = StartWork();
Status = UpdateStatus.Checking;
try
{
_release = await _updates.CheckAsync(token);
_packagePath = null;
Status = _release is null ? UpdateStatus.UpToDate : UpdateStatus.Available;
}
catch (OperationCanceledException) when (token.IsCancellationRequested)
{
// The check was cancelled by the next piece of work: it has already set its own state
return;
}
catch (Exception e) when (IsExpected(e))
{
Status = UpdateStatus.Failed;
}
OnPropertyChanged(nameof(ReleaseUrl));
OnPropertyChanged(nameof(IsReleaseLinkShown));
}
[RelayCommand]
private async Task DownloadAsync()
@@ -216,38 +213,6 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
or NotSupportedException or InvalidOperationException or Win32Exception
or OperationCanceledException;
private async Task RunCheckAsync(bool quiet)
{
if (!IsSupported)
{
return;
}
CancellationToken token = StartWork();
Status = UpdateStatus.Checking;
try
{
_release = await _updates.CheckAsync(token);
_packagePath = null;
_settings.LastUpdateCheck = DateTimeOffset.UtcNow;
Status = _release is null ? UpdateStatus.UpToDate : UpdateStatus.Available;
}
catch (OperationCanceledException) when (token.IsCancellationRequested)
{
// The check was cancelled by the next piece of work: it has already set its own state
return;
}
catch (Exception e) when (IsExpected(e))
{
Status = quiet ? UpdateStatus.Idle : UpdateStatus.Failed;
}
OnPropertyChanged(nameof(ReleaseUrl));
OnPropertyChanged(nameof(IsReleaseLinkShown));
}
/// <summary>
/// Starts a new piece of work, cancelling the previous one: the user may have
/// pressed "Check" in the middle of a download.
+195 -195
View File
@@ -51,7 +51,10 @@
<!-- The settings are laid out in two columns: this way the window fits on the
screen entirely and does without scrolling. Scrolling is kept for the case of
a large system font, with which the content is taller than the monitor after all -->
a large system font, with which the content is taller than the monitor after all.
The left column holds what the popup does; the right one holds the single
section describing how and where the popup looks -->
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="16">
<Grid>
<Grid.ColumnDefinitions>
@@ -91,7 +94,7 @@
</Grid>
</GroupBox>
<GroupBox Header="{Binding Localization[SectionPlacement]}">
<GroupBox Header="{Binding Localization[SectionBehavior]}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="164" />
@@ -105,6 +108,177 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Style="{StaticResource FieldLabel}"
Text="{Binding Localization[DurationLabel]}" />
<Slider Grid.Column="1" Minimum="200" Maximum="5000" TickFrequency="100"
Value="{Binding Settings.DurationMilliseconds}" />
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Style="{StaticResource FieldValue}"
Text="{Binding Settings.DurationMilliseconds, StringFormat={}{0:F0}}" />
<TextBlock Margin="4,0,0,0"
Foreground="{DynamicResource Theme.SecondaryForeground}"
Text="{Binding Localization[MillisecondsSuffix]}" />
</StackPanel>
<TextBlock Grid.Row="1" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[CapsLockLabel]}" />
<CheckBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
IsChecked="{Binding Settings.UseCapsLockHotkey}"
Content="{Binding Localization[CapsLockHotkeyCheck]}" />
<TextBlock Grid.Row="2" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[CapsLockHoldLabel]}" />
<Slider Grid.Row="2" Grid.Column="1" Margin="0,12,0,0"
Minimum="150" Maximum="1500" TickFrequency="50"
Value="{Binding Settings.CapsLockHoldMilliseconds}"
IsEnabled="{Binding Settings.UseCapsLockHotkey}" />
<StackPanel Grid.Row="2" Grid.Column="2" Margin="0,12,0,0"
Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Style="{StaticResource FieldValue}"
Text="{Binding Settings.CapsLockHoldMilliseconds, StringFormat={}{0:F0}}" />
<TextBlock Margin="4,0,0,0"
Foreground="{DynamicResource Theme.SecondaryForeground}"
Text="{Binding Localization[MillisecondsSuffix]}" />
</StackPanel>
<TextBlock Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,6,0,0" TextWrapping="Wrap"
Foreground="{DynamicResource Theme.SecondaryForeground}">
<Run Text="{Binding Localization[CapsLockHoldHint], Mode=OneWay}" />
<InlineUIContainer BaselineAlignment="Baseline">
<!-- The elevation caveat lives in the tooltip to keep the section compact -->
<TextBlock Text="{Binding Localization[MoreInfoLink]}"
Foreground="{DynamicResource Theme.Accent}"
TextDecorations="Underline"
Cursor="Help"
ToolTipService.InitialShowDelay="200"
ToolTipService.ShowDuration="60000"
Visibility="{Binding Settings.UseCapsLockHotkey, Converter={StaticResource BooleanToVisibility}}">
<TextBlock.ToolTip>
<ToolTip>
<TextBlock TextWrapping="Wrap"
Text="{Binding Localization[CapsLockElevationHint]}" />
</ToolTip>
</TextBlock.ToolTip>
</TextBlock>
</InlineUIContainer>
</TextBlock>
<TextBlock Grid.Row="4" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Visibility="{Binding IsStartupAvailable, Converter={StaticResource BooleanToVisibility}}"
Text="{Binding Localization[StartupLabel]}" />
<CheckBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
Visibility="{Binding IsStartupAvailable, Converter={StaticResource BooleanToVisibility}}"
IsEnabled="{Binding CanChangeStartup}"
IsChecked="{Binding RunAtStartup}"
Content="{Binding Localization[StartupCheck]}" />
<TextBlock Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,6,0,0" TextWrapping="Wrap"
Foreground="{DynamicResource Theme.SecondaryForeground}"
Visibility="{Binding IsStartupLocked, Converter={StaticResource BooleanToVisibility}}"
Text="{Binding Localization[StartupLockedHint]}" />
</Grid>
</GroupBox>
<!-- The section is absent for an app from the Store: the Store updates it itself -->
<GroupBox Header="{Binding Localization[SectionUpdates]}"
Visibility="{Binding Updates.IsSupported, Converter={StaticResource BooleanToVisibility}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="164" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Style="{StaticResource FieldLabel}"
Text="{Binding Localization[CurrentVersionLabel]}" />
<TextBlock Grid.Column="1" VerticalAlignment="Center"
Text="{Binding Updates.CurrentVersion}" />
<Button Grid.Column="2" Padding="12,4"
Command="{Binding Updates.CheckCommand}"
IsEnabled="{Binding Updates.CanCheck}"
Content="{Binding Localization[CheckUpdatesButton]}" />
<!-- The status is always on show: the check flies off with the
window, and where things stand is the answer the user came for -->
<TextBlock Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,12,0,0" TextWrapping="Wrap"
Text="{Binding Updates.StatusText}" />
<!-- The downloaded fraction is not always known: not every hosting reports the file size -->
<ProgressBar Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,8,0,0" Height="4" Maximum="1"
Value="{Binding Updates.Progress, Mode=OneWay}"
IsIndeterminate="{Binding Updates.IsProgressUnknown}"
Visibility="{Binding Updates.IsProgressShown, Converter={StaticResource BooleanToVisibility}}" />
<StackPanel Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,12,0,0" Orientation="Horizontal">
<Button Padding="12,4"
Command="{Binding Updates.DownloadCommand}"
Visibility="{Binding Updates.IsDownloadOffered, Converter={StaticResource BooleanToVisibility}}"
Content="{Binding Localization[DownloadUpdateButton]}" />
<Button Padding="12,4"
Command="{Binding Updates.InstallCommand}"
Visibility="{Binding Updates.IsInstallOffered, Converter={StaticResource BooleanToVisibility}}"
Content="{Binding Localization[InstallUpdateButton]}" />
<TextBlock Margin="12,0,0,0" VerticalAlignment="Center"
Visibility="{Binding Updates.IsReleaseLinkShown, Converter={StaticResource BooleanToVisibility}}">
<Hyperlink NavigateUri="{Binding Updates.ReleaseUrl}"
RequestNavigate="OnReleaseLinkNavigate">
<Run Text="{Binding Localization[ReleasePageLink], Mode=OneWay}" />
</Hyperlink>
</TextBlock>
</StackPanel>
<TextBlock Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,6,0,0" TextWrapping="Wrap"
Foreground="{DynamicResource Theme.SecondaryForeground}"
Visibility="{Binding Updates.IsInstallOffered, Converter={StaticResource BooleanToVisibility}}"
Text="{Binding Localization[UpdateInstallHint]}" />
</Grid>
</GroupBox>
</StackPanel>
<StackPanel Grid.Column="1" Margin="16,0,0,0">
<!-- Where the popup appears and how it looks are one question for the
user, so both live in a single section: the rule is picked at the
top and its result is seen in the preview at the bottom -->
<GroupBox Header="{Binding Localization[SectionPopup]}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="164" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
@@ -220,160 +394,56 @@
Visibility="{Binding Settings.PlacementMode,
Converter={StaticResource EnumToVisibility},
ConverterParameter=FixedPoint}" />
</Grid>
</GroupBox>
<GroupBox Header="{Binding Localization[SectionBehavior]}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="164" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- A hairline between the two halves of the section: the
placement above, the look of the popup below -->
<Border Grid.Row="7" Grid.ColumnSpan="3"
Margin="0,16,0,0" Height="1"
Background="{DynamicResource Theme.ControlBorder}" />
<TextBlock Style="{StaticResource FieldLabel}"
Text="{Binding Localization[DurationLabel]}" />
<Slider Grid.Column="1" Minimum="200" Maximum="5000" TickFrequency="100"
Value="{Binding Settings.DurationMilliseconds}" />
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Style="{StaticResource FieldValue}"
Text="{Binding Settings.DurationMilliseconds, StringFormat={}{0:F0}}" />
<TextBlock Margin="4,0,0,0"
Foreground="{DynamicResource Theme.SecondaryForeground}"
Text="{Binding Localization[MillisecondsSuffix]}" />
</StackPanel>
<TextBlock Grid.Row="1" Margin="0,12,12,0"
<TextBlock Grid.Row="8" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[CapsLockLabel]}" />
<CheckBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
IsChecked="{Binding Settings.UseCapsLockHotkey}"
Content="{Binding Localization[CapsLockHotkeyCheck]}" />
<TextBlock Grid.Row="2" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[CapsLockHoldLabel]}" />
<Slider Grid.Row="2" Grid.Column="1" Margin="0,12,0,0"
Minimum="150" Maximum="1500" TickFrequency="50"
Value="{Binding Settings.CapsLockHoldMilliseconds}"
IsEnabled="{Binding Settings.UseCapsLockHotkey}" />
<StackPanel Grid.Row="2" Grid.Column="2" Margin="0,12,0,0"
Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Style="{StaticResource FieldValue}"
Text="{Binding Settings.CapsLockHoldMilliseconds, StringFormat={}{0:F0}}" />
<TextBlock Margin="4,0,0,0"
Foreground="{DynamicResource Theme.SecondaryForeground}"
Text="{Binding Localization[MillisecondsSuffix]}" />
</StackPanel>
<TextBlock Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,6,0,0" TextWrapping="Wrap"
Foreground="{DynamicResource Theme.SecondaryForeground}">
<Run Text="{Binding Localization[CapsLockHoldHint], Mode=OneWay}" />
<InlineUIContainer BaselineAlignment="Baseline">
<!-- The elevation caveat lives in the tooltip to keep the section compact -->
<TextBlock Text="{Binding Localization[MoreInfoLink]}"
Foreground="{DynamicResource Theme.Accent}"
TextDecorations="Underline"
Cursor="Help"
ToolTipService.InitialShowDelay="200"
ToolTipService.ShowDuration="60000"
Visibility="{Binding Settings.UseCapsLockHotkey, Converter={StaticResource BooleanToVisibility}}">
<TextBlock.ToolTip>
<ToolTip>
<TextBlock TextWrapping="Wrap"
Text="{Binding Localization[CapsLockElevationHint]}" />
</ToolTip>
</TextBlock.ToolTip>
</TextBlock>
</InlineUIContainer>
</TextBlock>
<TextBlock Grid.Row="4" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Visibility="{Binding IsStartupAvailable, Converter={StaticResource BooleanToVisibility}}"
Text="{Binding Localization[StartupLabel]}" />
<CheckBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
Visibility="{Binding IsStartupAvailable, Converter={StaticResource BooleanToVisibility}}"
IsEnabled="{Binding CanChangeStartup}"
IsChecked="{Binding RunAtStartup}"
Content="{Binding Localization[StartupCheck]}" />
<TextBlock Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,6,0,0" TextWrapping="Wrap"
Foreground="{DynamicResource Theme.SecondaryForeground}"
Visibility="{Binding IsStartupLocked, Converter={StaticResource BooleanToVisibility}}"
Text="{Binding Localization[StartupLockedHint]}" />
</Grid>
</GroupBox>
</StackPanel>
<StackPanel Grid.Column="1" Margin="16,0,0,0">
<GroupBox Header="{Binding Localization[SectionAppearance]}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="164" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Style="{StaticResource FieldLabel}"
Text="{Binding Localization[FontSizeLabel]}" />
<Slider Grid.Column="1" Minimum="10" Maximum="72" TickFrequency="1"
<Slider Grid.Row="8" Grid.Column="1" Margin="0,12,0,0"
Minimum="10" Maximum="72" TickFrequency="1"
Value="{Binding Settings.FontSize}" />
<TextBlock Grid.Column="2" Style="{StaticResource FieldValue}"
<TextBlock Grid.Row="8" Grid.Column="2" Margin="12,12,0,0"
Style="{StaticResource FieldValue}"
Text="{Binding Settings.FontSize, StringFormat={}{0:F0}}" />
<TextBlock Grid.Row="1" Margin="0,12,12,0"
<TextBlock Grid.Row="9" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[OpacityLabel]}" />
<Slider Grid.Row="1" Grid.Column="1" Margin="0,12,0,0"
<Slider Grid.Row="9" Grid.Column="1" Margin="0,12,0,0"
Minimum="0.1" Maximum="1" TickFrequency="0.05"
Value="{Binding Settings.Opacity}" />
<TextBlock Grid.Row="1" Grid.Column="2" Margin="12,12,0,0"
<TextBlock Grid.Row="9" Grid.Column="2" Margin="12,12,0,0"
Style="{StaticResource FieldValue}"
Text="{Binding Settings.Opacity, StringFormat={}{0:P0}}" />
<TextBlock Grid.Row="2" Margin="0,12,12,0"
<TextBlock Grid.Row="10" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[BackgroundColorLabel]}" />
<ComboBox Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
<ComboBox Grid.Row="10" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
ItemsSource="{Binding BackgroundPalette}"
ItemTemplate="{StaticResource ColorSwatchTemplate}"
SelectedItem="{Binding Settings.BackgroundColor}" />
<TextBlock Grid.Row="3" Margin="0,12,12,0"
<TextBlock Grid.Row="11" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[TextColorLabel]}" />
<ComboBox Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
<ComboBox Grid.Row="11" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
ItemsSource="{Binding TextPalette}"
ItemTemplate="{StaticResource ColorSwatchTemplate}"
SelectedItem="{Binding Settings.ForegroundColor}" />
<TextBlock Grid.Row="4" Margin="0,12,12,0"
<TextBlock Grid.Row="12" Margin="0,12,12,0"
Style="{StaticResource FieldLabel}"
Text="{Binding Localization[PreviewLabel]}" />
<!-- The height of the area is sized for the largest font
available: the sample text is fully visible at any
position of the slider -->
<Border Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2"
<Border Grid.Row="12" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,12,0,0" Padding="16"
Height="152" ClipToBounds="True"
Background="{DynamicResource Theme.SurfaceStrong}" CornerRadius="4"
@@ -392,76 +462,6 @@
</Grid>
</GroupBox>
<!-- The section is absent for an app from the Store: the Store updates it itself -->
<GroupBox Header="{Binding Localization[SectionUpdates]}"
Visibility="{Binding Updates.IsSupported, Converter={StaticResource BooleanToVisibility}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="164" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Style="{StaticResource FieldLabel}"
Text="{Binding Localization[CurrentVersionLabel]}" />
<TextBlock Grid.Column="1" VerticalAlignment="Center"
Text="{Binding Updates.CurrentVersion}" />
<Button Grid.Column="2" Padding="12,4"
Command="{Binding Updates.CheckCommand}"
IsEnabled="{Binding Updates.CanCheck}"
Content="{Binding Localization[CheckUpdatesButton]}" />
<CheckBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,12,0,0"
IsChecked="{Binding Updates.CheckAutomatically}"
Content="{Binding Localization[UpdateAutoCheck]}" />
<TextBlock Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,12,0,0" TextWrapping="Wrap"
Visibility="{Binding Updates.HasStatus, Converter={StaticResource BooleanToVisibility}}"
Text="{Binding Updates.StatusText}" />
<!-- The downloaded fraction is not always known: not every hosting reports the file size -->
<ProgressBar Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,8,0,0" Height="4" Maximum="1"
Value="{Binding Updates.Progress, Mode=OneWay}"
IsIndeterminate="{Binding Updates.IsProgressUnknown}"
Visibility="{Binding Updates.IsProgressShown, Converter={StaticResource BooleanToVisibility}}" />
<StackPanel Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,12,0,0" Orientation="Horizontal">
<Button Padding="12,4"
Command="{Binding Updates.DownloadCommand}"
Visibility="{Binding Updates.IsDownloadOffered, Converter={StaticResource BooleanToVisibility}}"
Content="{Binding Localization[DownloadUpdateButton]}" />
<Button Padding="12,4"
Command="{Binding Updates.InstallCommand}"
Visibility="{Binding Updates.IsInstallOffered, Converter={StaticResource BooleanToVisibility}}"
Content="{Binding Localization[InstallUpdateButton]}" />
<TextBlock Margin="12,0,0,0" VerticalAlignment="Center"
Visibility="{Binding Updates.IsReleaseLinkShown, Converter={StaticResource BooleanToVisibility}}">
<Hyperlink NavigateUri="{Binding Updates.ReleaseUrl}"
RequestNavigate="OnReleaseLinkNavigate">
<Run Text="{Binding Localization[ReleasePageLink], Mode=OneWay}" />
</Hyperlink>
</TextBlock>
</StackPanel>
<TextBlock Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2"
Margin="0,6,0,0" TextWrapping="Wrap"
Foreground="{DynamicResource Theme.SecondaryForeground}"
Visibility="{Binding Updates.IsInstallOffered, Converter={StaticResource BooleanToVisibility}}"
Text="{Binding Localization[UpdateInstallHint]}" />
</Grid>
</GroupBox>
</StackPanel>
</Grid>
</ScrollViewer>