diff --git a/design/mockups/per-target-launch-options/APPROVED b/design/mockups/per-target-launch-options/APPROVED index 31fa3e0..d50c75d 100644 --- a/design/mockups/per-target-launch-options/APPROVED +++ b/design/mockups/per-target-launch-options/APPROVED @@ -1,2 +1,3 @@ 2026-07-08 feat/launch-commands-editor approved 02-dark-pro.html 2026-07-08 fix/product-safety-review reused 02-dark-pro.html for non-visual drop safety changes +2026-07-09 fix/product-format-cleanup reused 02-dark-pro.html for non-visual dotnet format cleanup diff --git a/src/Dropwheel/Services/HotkeyService.cs b/src/Dropwheel/Services/HotkeyService.cs index 9ead736..f55826f 100644 --- a/src/Dropwheel/Services/HotkeyService.cs +++ b/src/Dropwheel/Services/HotkeyService.cs @@ -38,10 +38,10 @@ public static bool TryParse(string s, out uint mods, out uint vk) foreach (var part in s.Split('+', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)) switch (part.ToLowerInvariant()) { - case "alt": mods |= 0x1; break; - case "ctrl": mods |= 0x2; break; + case "alt": mods |= 0x1; break; + case "ctrl": mods |= 0x2; break; case "shift": mods |= 0x4; break; - case "win": mods |= 0x8; break; + case "win": mods |= 0x8; break; default: if (key != null) return false; // more than one non-modifier key try @@ -74,10 +74,32 @@ private static string NormalizeKeyName(string part) private static readonly Dictionary CyrillicToLatin = new() { - ['й'] = 'q', ['ц'] = 'w', ['у'] = 'e', ['к'] = 'r', ['е'] = 't', ['н'] = 'y', ['г'] = 'u', - ['ш'] = 'i', ['щ'] = 'o', ['з'] = 'p', ['ф'] = 'a', ['ы'] = 's', ['в'] = 'd', ['а'] = 'f', - ['п'] = 'g', ['р'] = 'h', ['о'] = 'j', ['л'] = 'k', ['д'] = 'l', ['я'] = 'z', ['ч'] = 'x', - ['с'] = 'c', ['м'] = 'v', ['и'] = 'b', ['т'] = 'n', ['ь'] = 'm', + ['й'] = 'q', + ['ц'] = 'w', + ['у'] = 'e', + ['к'] = 'r', + ['е'] = 't', + ['н'] = 'y', + ['г'] = 'u', + ['ш'] = 'i', + ['щ'] = 'o', + ['з'] = 'p', + ['ф'] = 'a', + ['ы'] = 's', + ['в'] = 'd', + ['а'] = 'f', + ['п'] = 'g', + ['р'] = 'h', + ['о'] = 'j', + ['л'] = 'k', + ['д'] = 'l', + ['я'] = 'z', + ['ч'] = 'x', + ['с'] = 'c', + ['м'] = 'v', + ['и'] = 'b', + ['т'] = 'n', + ['ь'] = 'm', }; private IntPtr Hook(IntPtr hwnd, int msg, IntPtr w, IntPtr l, ref bool handled) diff --git a/src/Dropwheel/UI/OverlayWindow.Back.cs b/src/Dropwheel/UI/OverlayWindow.Back.cs index 8242173..cede203 100644 --- a/src/Dropwheel/UI/OverlayWindow.Back.cs +++ b/src/Dropwheel/UI/OverlayWindow.Back.cs @@ -12,13 +12,17 @@ private FrameworkElement MakeBackBubble() var th = Themes.Current; var sq = new Border { - Width = 64, Height = 64, CornerRadius = new CornerRadius(17), + Width = 64, + Height = 64, + CornerRadius = new CornerRadius(17), Background = new SolidColorBrush(th.TileBg), BorderBrush = new SolidColorBrush(th.GroupBorder), BorderThickness = new Thickness(1.2), Child = new TextBlock { - Text = "←", FontSize = 24, Foreground = new SolidColorBrush(th.Label), + Text = "←", + FontSize = 24, + Foreground = new SolidColorBrush(th.Label), HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center } diff --git a/src/Dropwheel/UI/OverlayWindow.Bubble.Wire.cs b/src/Dropwheel/UI/OverlayWindow.Bubble.Wire.cs index d29a9d1..36ce1ff 100644 --- a/src/Dropwheel/UI/OverlayWindow.Bubble.Wire.cs +++ b/src/Dropwheel/UI/OverlayWindow.Bubble.Wire.cs @@ -13,7 +13,8 @@ private StackPanel WireBubble(TargetItem t, Border badge, FrameworkElement label var th = Themes.Current; var panel = new StackPanel { - Width = 76, Tag = t, + Width = 76, + Tag = t, AllowDrop = t.IsGroup || LaunchService.IsFolderTarget(t) || LaunchService.IsRunTarget(t), Opacity = t.Exists ? 1.0 : 0.4, Background = Brushes.Transparent diff --git a/src/Dropwheel/UI/OverlayWindow.Bubble.cs b/src/Dropwheel/UI/OverlayWindow.Bubble.cs index 26dd397..5e3c364 100644 --- a/src/Dropwheel/UI/OverlayWindow.Bubble.cs +++ b/src/Dropwheel/UI/OverlayWindow.Bubble.cs @@ -16,20 +16,26 @@ private FrameworkElement MakeBubble(TargetItem t) UIElement inner = t.IsGroup ? new TextBlock { - Text = t.Children!.Count.ToString(), FontSize = 20, - FontWeight = FontWeights.Bold, Foreground = new SolidColorBrush(th.Label), + Text = t.Children!.Count.ToString(), + FontSize = 20, + FontWeight = FontWeights.Bold, + Foreground = new SolidColorBrush(th.Label), HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center } : new Image { - Width = 32, Height = 32, Source = IconService.GetIcon(t.Path), + Width = 32, + Height = 32, + Source = IconService.GetIcon(t.Path), HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center }; var sq = new Border { - Width = 64, Height = 64, CornerRadius = new CornerRadius(17), + Width = 64, + Height = 64, + CornerRadius = new CornerRadius(17), Background = new SolidColorBrush(th.TileBg), BorderBrush = new SolidColorBrush( t.IsGroup ? th.GroupBorder : t.IsSorter ? th.SorterBorder : th.TileBorder), @@ -39,8 +45,10 @@ private FrameworkElement MakeBubble(TargetItem t) }; var badge = new Border { - Background = Brushes.MediumSpringGreen, CornerRadius = new CornerRadius(10), - Padding = new Thickness(5, 1, 5, 1), Visibility = Visibility.Collapsed, + Background = Brushes.MediumSpringGreen, + CornerRadius = new CornerRadius(10), + Padding = new Thickness(5, 1, 5, 1), + Visibility = Visibility.Collapsed, HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Top, Child = new TextBlock { Text = "⧉", FontWeight = FontWeights.Bold, FontSize = 12 } @@ -60,8 +68,11 @@ private static FrameworkElement MakeLabel(string text) var color = Luminance(th.Label) < 0.5 ? Color.FromRgb(0xEC, 0xF1, 0xF7) : th.Label; return new TextBlock { - Text = text, Foreground = new SolidColorBrush(color), FontSize = 11.5, - TextAlignment = TextAlignment.Center, MaxWidth = 88, + Text = text, + Foreground = new SolidColorBrush(color), + FontSize = 11.5, + TextAlignment = TextAlignment.Center, + MaxWidth = 88, TextTrimming = TextTrimming.CharacterEllipsis, Effect = new DropShadowEffect { Color = Colors.Black, BlurRadius = 3, ShadowDepth = 1, Opacity = 0.85 }, }; diff --git a/src/Dropwheel/UI/OverlayWindow.Cloud.cs b/src/Dropwheel/UI/OverlayWindow.Cloud.cs index ac74303..216bed3 100644 --- a/src/Dropwheel/UI/OverlayWindow.Cloud.cs +++ b/src/Dropwheel/UI/OverlayWindow.Cloud.cs @@ -50,7 +50,8 @@ private void BuildCloud() // MouseLeave and the close timer instantly). Clicking empty space closes. var backdrop = new System.Windows.Shapes.Ellipse { - Width = 452, Height = 452, + Width = 452, + Height = 452, Fill = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)), }; Canvas.SetLeft(backdrop, HalfSize - 226); @@ -69,11 +70,13 @@ private void BuildCloud() double a = -Math.PI / 2 + i * 2 * Math.PI / n; var spoke = new Line { - X1 = HalfSize, Y1 = HalfSize, + X1 = HalfSize, + Y1 = HalfSize, X2 = HalfSize + (RingR - 52) * Math.Cos(a), Y2 = HalfSize + (RingR - 52) * Math.Sin(a), Stroke = new SolidColorBrush(th.Spoke), - StrokeThickness = 2, IsHitTestVisible = false, + StrokeThickness = 2, + IsHitTestVisible = false, }; Cloud.Children.Add(spoke); _spokes[items[i]] = spoke; diff --git a/src/Dropwheel/UI/OverlayWindow.Dnd.cs b/src/Dropwheel/UI/OverlayWindow.Dnd.cs index f9df5b6..b00335c 100644 --- a/src/Dropwheel/UI/OverlayWindow.Dnd.cs +++ b/src/Dropwheel/UI/OverlayWindow.Dnd.cs @@ -12,7 +12,7 @@ public partial class OverlayWindow private static DropAction Resolve(TargetItem t, DragEventArgs e) { if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey)) return DropAction.Copy; - if (e.KeyStates.HasFlag(DragDropKeyStates.ShiftKey)) return DropAction.Move; + if (e.KeyStates.HasFlag(DragDropKeyStates.ShiftKey)) return DropAction.Move; if (t.Override != DropAction.Inherit) return t.Override; return TargetStore.Config.GlobalAction; } diff --git a/src/Dropwheel/UI/OverlayWindow.Hotkey.cs b/src/Dropwheel/UI/OverlayWindow.Hotkey.cs index 50a0ea0..e27e3f3 100644 --- a/src/Dropwheel/UI/OverlayWindow.Hotkey.cs +++ b/src/Dropwheel/UI/OverlayWindow.Hotkey.cs @@ -45,7 +45,7 @@ private void OnHotkey() { var dip = ct.TransformFromDevice.Transform(new Point(c.X, c.Y)); Left = dip.X - HalfSize; - Top = dip.Y - HalfSize; + Top = dip.Y - HalfSize; } UpdateOrbScreenPos(); OpenCloud(); diff --git a/src/Dropwheel/UI/OverlayWindow.Layout.cs b/src/Dropwheel/UI/OverlayWindow.Layout.cs index cbf932e..3b73fa7 100644 --- a/src/Dropwheel/UI/OverlayWindow.Layout.cs +++ b/src/Dropwheel/UI/OverlayWindow.Layout.cs @@ -19,7 +19,7 @@ private void PlaceWindow() double l = SystemParameters.VirtualScreenLeft, t = SystemParameters.VirtualScreenTop; double r = l + SystemParameters.VirtualScreenWidth, b = t + SystemParameters.VirtualScreenHeight; Left = Math.Clamp(cx - HalfSize, l - HalfSize + 24, r - HalfSize - 24); - Top = Math.Clamp(cy - HalfSize, t - HalfSize + 24, b - HalfSize - 24); + Top = Math.Clamp(cy - HalfSize, t - HalfSize + 24, b - HalfSize - 24); } private void OnOrbMouseDown(object sender, MouseButtonEventArgs e) diff --git a/src/Dropwheel/UI/OverlayWindow.Plus.cs b/src/Dropwheel/UI/OverlayWindow.Plus.cs index 30629a9..f974c6d 100644 --- a/src/Dropwheel/UI/OverlayWindow.Plus.cs +++ b/src/Dropwheel/UI/OverlayWindow.Plus.cs @@ -15,7 +15,8 @@ private FrameworkElement MakePlusTile() var th = Themes.Current; var rect = new Rectangle { - RadiusX = 17, RadiusY = 17, + RadiusX = 17, + RadiusY = 17, Stroke = new SolidColorBrush(th.TileBorder), StrokeDashArray = new DoubleCollection { 4, 3 }, StrokeThickness = 1.4, @@ -23,7 +24,9 @@ private FrameworkElement MakePlusTile() }; var plus = new TextBlock { - Text = "+", FontSize = 26, Foreground = new SolidColorBrush(th.Label), + Text = "+", + FontSize = 26, + Foreground = new SolidColorBrush(th.Label), HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center }; diff --git a/src/Dropwheel/UI/OverlayWindow.Proximity.cs b/src/Dropwheel/UI/OverlayWindow.Proximity.cs index 35cd25b..861477a 100644 --- a/src/Dropwheel/UI/OverlayWindow.Proximity.cs +++ b/src/Dropwheel/UI/OverlayWindow.Proximity.cs @@ -23,7 +23,7 @@ private void UpdateOrbScreenPos() var p = Orb.PointToScreen(new Point(23, 23)); // orb center, device px _orbSX = p.X; _orbSY = p.Y; double m = ct.TransformToDevice.M11; - _openR2 = 150 * m * 150 * m; // open radius + _openR2 = 150 * m * 150 * m; // open radius _closeR2 = 340 * m * 340 * m; // close radius } diff --git a/src/Dropwheel/UI/TargetEditorWindow.Rules.cs b/src/Dropwheel/UI/TargetEditorWindow.Rules.cs index 8155583..ad9310c 100644 --- a/src/Dropwheel/UI/TargetEditorWindow.Rules.cs +++ b/src/Dropwheel/UI/TargetEditorWindow.Rules.cs @@ -84,7 +84,9 @@ private FrameworkElement BuildMasterRow(SortRule rule, int index) }; var summary = new TextBlock { - Text = MasterSummary(rule), FontSize = 11, Foreground = Palettes.TextMuted, + Text = MasterSummary(rule), + FontSize = 11, + Foreground = Palettes.TextMuted, TextTrimming = TextTrimming.CharacterEllipsis, }; var body = new StackPanel { Margin = new Thickness(8, 4, 6, 4) }; @@ -93,7 +95,9 @@ private FrameworkElement BuildMasterRow(SortRule rule, int index) var border = new Border { - Child = body, CornerRadius = new CornerRadius(5), Margin = new Thickness(0, 0, 0, 3), + Child = body, + CornerRadius = new CornerRadius(5), + Margin = new Thickness(0, 0, 0, 3), Cursor = System.Windows.Input.Cursors.Hand, Background = sel ? SelectedBg : Brushes.Transparent, BorderBrush = sel ? SelectedBar : Brushes.Transparent, @@ -165,7 +169,9 @@ private void RebuildDetail() _tokenHint = new TextBlock { - FontSize = 11, Foreground = Palettes.TextMuted, TextWrapping = TextWrapping.Wrap, + FontSize = 11, + Foreground = Palettes.TextMuted, + TextWrapping = TextWrapping.Wrap, Margin = new Thickness(0, 0, 0, 10), }; DetailHost.Children.Add(_tokenHint); @@ -179,8 +185,10 @@ private void RebuildDetail() var addCond = new Button { - Content = "+ condition", Padding = new Thickness(6, 1, 6, 1), - HorizontalAlignment = HorizontalAlignment.Left, Margin = new Thickness(0, 4, 0, 0), + Content = "+ condition", + Padding = new Thickness(6, 1, 6, 1), + HorizontalAlignment = HorizontalAlignment.Left, + Margin = new Thickness(0, 4, 0, 0), }; addCond.Click += (_, _) => { @@ -192,8 +200,10 @@ private void RebuildDetail() var savePreset = new Button { - Content = "Save as preset…", Padding = new Thickness(6, 1, 6, 1), - HorizontalAlignment = HorizontalAlignment.Left, Margin = new Thickness(0, 8, 0, 0), + Content = "Save as preset…", + Padding = new Thickness(6, 1, 6, 1), + HorizontalAlignment = HorizontalAlignment.Left, + Margin = new Thickness(0, 8, 0, 0), }; savePreset.Click += (_, _) => OnSaveAsPreset(rule); DetailHost.Children.Add(savePreset); @@ -216,7 +226,9 @@ private FrameworkElement BuildConditionRow(SortRule rule, RuleCondition cond) cond.Op = ops[0]; var opWord = new TextBlock { - Text = OpWord(cond.Op), Foreground = Palettes.TextMuted, VerticalAlignment = VerticalAlignment.Center, + Text = OpWord(cond.Op), + Foreground = Palettes.TextMuted, + VerticalAlignment = VerticalAlignment.Center, Margin = new Thickness(8, 0, 4, 0), }; DockPanel.SetDock(opWord, Dock.Right); @@ -247,8 +259,11 @@ private FrameworkElement BuildConditionRow(SortRule rule, RuleCondition cond) var value = new TextBox { Text = cond.Value }; var hint = new TextBlock { - Text = WatermarkFor(cond.Field), Foreground = Palettes.TextMuted, IsHitTestVisible = false, - Margin = new Thickness(6, 0, 0, 0), VerticalAlignment = VerticalAlignment.Center, + Text = WatermarkFor(cond.Field), + Foreground = Palettes.TextMuted, + IsHitTestVisible = false, + Margin = new Thickness(6, 0, 0, 0), + VerticalAlignment = VerticalAlignment.Center, Visibility = string.IsNullOrEmpty(cond.Value) ? Visibility.Visible : Visibility.Collapsed, }; value.TextChanged += (_, _) => @@ -364,7 +379,9 @@ private void RefreshMatches() var here = files.Where(f => SortService.MatchedRuleIndex(_rules, f) == _selected).ToArray(); _matchesHost.Children.Add(new TextBlock { - Text = $"Routes here: {here.Length} of {files.Length}", FontSize = 11, Foreground = Palettes.TextMuted, + Text = $"Routes here: {here.Length} of {files.Length}", + FontSize = 11, + Foreground = Palettes.TextMuted, Margin = new Thickness(0, 0, 0, 2), }); bool showDest = _rules[_selected].Dest.Contains("${", StringComparison.Ordinal); @@ -374,7 +391,8 @@ private void RefreshMatches() Text = showDest ? $"{Path.GetFileName(f)} → {ResolvedDestLabel(_rules[_selected], Path.GetFileName(f))}" : Path.GetFileName(f), - FontSize = 11, TextTrimming = TextTrimming.CharacterEllipsis, + FontSize = 11, + TextTrimming = TextTrimming.CharacterEllipsis, }); // Size/age conditions are treated as zero in the preview: the test input is names without // real files on disk. Warn if any rule has such a condition — a file might have been silently @@ -499,8 +517,11 @@ private Button MoveButton(string glyph, bool enabled, Action onClick) { var b = new Button { - Content = glyph, Width = 24, Margin = new Thickness(2, 0, 0, 0), - Padding = new Thickness(0), IsEnabled = enabled, + Content = glyph, + Width = 24, + Margin = new Thickness(2, 0, 0, 0), + Padding = new Thickness(0), + IsEnabled = enabled, }; b.Click += (_, _) => onClick(); return b; @@ -548,7 +569,10 @@ private bool TryValidateRules(out string error) private static TextBlock Hint(string text) => new() { - Text = text, FontSize = 11, Foreground = Palettes.TextMuted, TextWrapping = TextWrapping.Wrap, + Text = text, + FontSize = 11, + Foreground = Palettes.TextMuted, + TextWrapping = TextWrapping.Wrap, Margin = new Thickness(0, 2, 0, 2), };