Skip to content

Commit ae7215f

Browse files
committed
Feature: Adjust status window design
1 parent ef42fa9 commit ae7215f

4 files changed

Lines changed: 54 additions & 87 deletions

File tree

Source/NETworkManager.Converters/TimeToStrokeDashOffsetConverter.cs

Lines changed: 0 additions & 37 deletions
This file was deleted.

Source/NETworkManager/NotificationWindow.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public NotificationWindow(PackIconMaterialKind iconKind, string iconColor, strin
8888
// message wraps to more lines the whole stack must re-anchor to the bottom edge.
8989
SizeChanged += (_, _) => NotificationManager.RepositionAll();
9090

91-
_timer.Interval = TimeSpan.FromMilliseconds(16);
91+
_timer.Interval = TimeSpan.FromMilliseconds(33);
9292
_timer.Tick += Timer_Tick;
9393
}
9494

Source/NETworkManager/StatusWindow.xaml

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
66
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
77
xmlns:localization="clr-namespace:NETworkManager.Localization.Resources;assembly=NETworkManager.Localization"
8-
xmlns:resources="clr-namespace:NETworkManager.Properties"
98
xmlns:networkManager="clr-namespace:NETworkManager"
109
xmlns:converters="clr-namespace:NETworkManager.Converters;assembly=NETworkManager.Converters"
1110
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
@@ -16,49 +15,16 @@
1615
Topmost="True"
1716
ShowInTaskbar="False"
1817
Width="950"
19-
Height="241"
18+
SizeToContent="Height"
2019
ResizeMode="NoResize"
2120
IsWindowDraggable="False"
2221
ShowMinButton="False"
2322
ShowMaxRestoreButton="False"
2423
ShowCloseButton="True"
25-
ShowTitleBar="True"
2624
Closing="MetroWindow_Closing">
2725
<mah:MetroWindow.Resources>
2826
<converters:BooleanToVisibilityCollapsedConverter x:Key="BooleanToVisibilityCollapsedConverter" />
29-
<converters:TimeToStrokeDashOffsetConverter x:Key="TimeToStrokeDashOffsetConverter" />
3027
</mah:MetroWindow.Resources>
31-
<mah:MetroWindow.LeftWindowCommands>
32-
<mah:WindowCommands ShowSeparators="False">
33-
<!-- Countdown progress ring -->
34-
<Grid Width="20" Height="20"
35-
Visibility="{Binding ShowTime, Converter={StaticResource BooleanToVisibilityCollapsedConverter}}"
36-
VerticalAlignment="Center"
37-
Margin="10,0,0,0">
38-
<!-- Track (background ring) -->
39-
<Ellipse StrokeThickness="2.5"
40-
Stroke="{DynamicResource MahApps.Brushes.Accent}"
41-
Opacity="0.2" />
42-
<!-- Foreground arc that shrinks as time counts down -->
43-
<Ellipse StrokeThickness="2.5"
44-
Stroke="{DynamicResource MahApps.Brushes.Accent}"
45-
StrokeDashCap="Round"
46-
StrokeDashArray="22 100"
47-
RenderTransformOrigin="0.5,0.5">
48-
<Ellipse.RenderTransform>
49-
<RotateTransform Angle="-90" />
50-
</Ellipse.RenderTransform>
51-
<Ellipse.StrokeDashOffset>
52-
<MultiBinding Converter="{StaticResource TimeToStrokeDashOffsetConverter}"
53-
ConverterParameter="22.0">
54-
<Binding Path="Time" />
55-
<Binding Path="TimeMax" />
56-
</MultiBinding>
57-
</Ellipse.StrokeDashOffset>
58-
</Ellipse>
59-
</Grid>
60-
</mah:WindowCommands>
61-
</mah:MetroWindow.LeftWindowCommands>
6228
<mah:MetroWindow.RightWindowCommands>
6329
<mah:WindowCommands ShowSeparators="False">
6430
<Button Command="{Binding Path=ShowMainWindowCommand}"
@@ -77,5 +43,23 @@
7743
</Button>
7844
</mah:WindowCommands>
7945
</mah:MetroWindow.RightWindowCommands>
80-
<ContentControl Margin="10,5,10,10" x:Name="ContentControlNetworkConnection" />
46+
<Grid>
47+
<Grid.RowDefinitions>
48+
<RowDefinition Height="*" />
49+
<RowDefinition Height="Auto" />
50+
</Grid.RowDefinitions>
51+
<ContentControl Grid.Column="0" Grid.Row="0"
52+
x:Name="ContentControlNetworkConnection"
53+
Margin="10" />
54+
<ProgressBar Grid.Column="0" Grid.Row="1"
55+
Height="3"
56+
MinHeight="3"
57+
Margin="0"
58+
Minimum="0"
59+
Maximum="{Binding TimeMax, Mode=OneWay}"
60+
Value="{Binding Time, Mode=OneWay}"
61+
Visibility="{Binding ShowTime, Converter={StaticResource BooleanToVisibilityCollapsedConverter}}"
62+
BorderThickness="0"
63+
Padding="0" />
64+
</Grid>
8165
</mah:MetroWindow>

Source/NETworkManager/StatusWindow.xaml.cs

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@ public StatusWindow(MainWindow mainWindow)
2525

2626
_mainWindow = mainWindow;
2727

28-
_dispatcherTimerClose.Interval = TimeSpan.FromMilliseconds(16);
28+
_dispatcherTimerClose.Interval = TimeSpan.FromMilliseconds(33);
2929
_dispatcherTimerClose.Tick += DispatcherTimerTime_Tick;
3030

3131
_networkConnectionView = new NetworkConnectionWidgetView();
3232
ContentControlNetworkConnection.Content = _networkConnectionView;
33+
34+
// With SizeToContent="Height" the height is only known after layout; re-anchor to the
35+
// bottom-right whenever it changes so the window does not drift to the top of the screen.
36+
SizeChanged += (_, _) => UpdatePosition();
3337
}
3438

3539
#endregion
@@ -84,7 +88,9 @@ public double Time
8488
get;
8589
set
8690
{
87-
if (value == field)
91+
// Same guard as NotificationWindow.TimeRemaining: ignore sub-0.001 changes so the
92+
// countdown updates at the same cadence in both windows.
93+
if (Math.Abs(value - field) < 0.001)
8894
return;
8995

9096
field = value;
@@ -128,15 +134,9 @@ private void Check()
128134
/// <param name="enableCloseTimer">Automatically close the window after a certain time.</param>
129135
public void ShowWindow(bool enableCloseTimer = false)
130136
{
131-
// Set window position on primary screen
132-
// ToDo: User setting...
133-
if (Screen.PrimaryScreen != null)
134-
{
135-
var scaleFactor = System.Windows.Media.VisualTreeHelper.GetDpi(this).DpiScaleX;
136-
137-
Left = Screen.PrimaryScreen.WorkingArea.Right / scaleFactor - Width - 10;
138-
Top = Screen.PrimaryScreen.WorkingArea.Bottom / scaleFactor - Height - 10;
139-
}
137+
// Position bottom-right on the primary screen. With SizeToContent="Height" the final
138+
// height is only known after layout, so this is refined again in SizeChanged.
139+
UpdatePosition();
140140

141141
// Show the window
142142
Show();
@@ -155,6 +155,23 @@ public void ShowWindow(bool enableCloseTimer = false)
155155
Activate();
156156
}
157157

158+
/// <summary>
159+
/// Anchors the window to the bottom-right corner of the primary screen. Uses
160+
/// <see cref="FrameworkElement.ActualHeight"/> (not Height, which is NaN while
161+
/// SizeToContent is active) so the window stays bottom-anchored as its height changes.
162+
/// </summary>
163+
private void UpdatePosition()
164+
{
165+
// ToDo: User setting...
166+
if (Screen.PrimaryScreen == null)
167+
return;
168+
169+
var scaleFactor = System.Windows.Media.VisualTreeHelper.GetDpi(this).DpiScaleX;
170+
171+
Left = Screen.PrimaryScreen.WorkingArea.Right / scaleFactor - Width - 10;
172+
Top = Screen.PrimaryScreen.WorkingArea.Bottom / scaleFactor - ActualHeight - 10;
173+
}
174+
158175
private void SetupCloseTimer()
159176
{
160177
TimeMax = SettingsManager.Current.Status_WindowCloseTime;
@@ -183,9 +200,12 @@ private void MetroWindow_Closing(object sender, CancelEventArgs e)
183200

184201
private async void DispatcherTimerTime_Tick(object sender, EventArgs e)
185202
{
186-
Time = Math.Max(0.0, TimeMax - _stopwatch.Elapsed.TotalSeconds);
203+
// Use a local for the close decision — the Time setter now ignores sub-0.001 changes, so
204+
// reading the property back could stay stuck at a tiny positive value and never hide.
205+
var remaining = Math.Max(0.0, TimeMax - _stopwatch.Elapsed.TotalSeconds);
206+
Time = remaining;
187207

188-
if (Time > 0)
208+
if (remaining > 0)
189209
return;
190210

191211
_dispatcherTimerClose.Stop();

0 commit comments

Comments
 (0)