Skip to content

Commit 896b8ce

Browse files
committed
refactor: consolidate controllers, themes, visualization & performance
Spectrum - Simplified spectrum analyzer architecture - Fixed namespace conflict by using FftSharp.Windows Controllers/UI - Replaced 10+ managers with AppController, ViewManager and UIManager - Removed redundant interfaces (controller/view/ui/rendering/cleanup) - Simplified IMainController (removed inheritance chain) - Updated XAML bindings to direct paths: - View.BarCount, View.RenderQuality, View.SelectedStyle - Audio.MinDbLevel, Audio.AmplificationFactor - UI.IsOverlayActive, UI.IsPopupOpen - Reduced controller code size (~800 LOC -> ~460 LOC) Themes/Settings/DI - Merged ThemeManager, IThemes and CommonResources - Switched to Microsoft.Extensions.DependencyInjection - Settings refactor: 13 files -> 3 (-600 LOC) - Fixed theme persistence and Space key binding; instant save on theme change - Consolidated Colors/Brushes; removed redundant interfaces - SmartLogger: lazy init + auto-configuration Windows/Layout - ControlPanelWindow: replaced Popup with Grid overlay; added StereoMode selector - SettingsWindow: reduced size; added SettingSlider; fixed key bindings - Removed XAML event handlers and code-behind subscriptions where possible Visualization/Performance - Consolidated visualization into core files: SpectrumRenderer, RendererCore, PerformanceCore, Placeholder, Interfaces - Simplified renderer hierarchy (4 levels -> 2) - Centralized spectrum processing and shared SKPaint/SKPath pooling - Unified performance metrics and FPS limiter in PerformanceCore - Added IRendererContext; simplified RendererFactory/cache; moved perf overlay renderer - Fixed DI registration for performance and transparency managers - Reduced overall code size (~30%) and added new renderers Overlay - Resolved transparency and performance issues - Removed BitmapCache from SKElement to fix FPS drops - Refactored overlay module structure - Optimized overlay rendering and fixed click-through Repo hygiene - Removed tracked test project and stray file; added test project to .gitignore
1 parent 25e7894 commit 896b8ce

File tree

210 files changed

+17040
-31362
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

210 files changed

+17040
-31362
lines changed

.editorconfig

Lines changed: 589 additions & 0 deletions
Large diffs are not rendered by default.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,3 +363,4 @@ MigrationBackup/
363363
FodyWeavers.xsd
364364
/SpectrumNet/EventHandlers.cs
365365
/SpectrumNet/MainWindow copy.xaml.cs
366+
SpectrumNetXUnit/

SpectrumNet/.editorconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[*.cs]
2+
3+
# CA1515: Consider making public types internal
4+
dotnet_diagnostic.CA1515.severity = silent

SpectrumNet/.gitignore

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,52 @@
1-
/SpectrumNetXUnit/
1+
# Test project
2+
/SpectrumNetXUnit/
3+
4+
# Build outputs
5+
bin/
6+
obj/
7+
out/
8+
9+
# Visual Studio
10+
.vs/
11+
*.user
12+
*.suo
13+
*.userosscache
14+
*.sln.docstates
15+
16+
# Rider / JetBrains
17+
.idea/
18+
*.sln.iml
19+
20+
# NuGet
21+
packages/
22+
*.nupkg
23+
project.lock.json
24+
project.fragment.lock.json
25+
26+
# Build results
27+
[Dd]ebug/
28+
[Rr]elease/
29+
x64/
30+
x86/
31+
[Ww][Ii][Nn]32/
32+
[Aa][Rr][Mm]/
33+
[Aa][Rr][Mm]64/
34+
bld/
35+
[Ll]og/
36+
[Ll]ogs/
37+
38+
# Temp files
39+
*.tmp
40+
*.temp
41+
*.log
42+
*.cache
43+
~$*
44+
45+
# OS files
46+
Thumbs.db
47+
ehthumbs.db
48+
.DS_Store
49+
50+
# Publish
51+
publish/
52+
PublishProfiles/

SpectrumNet/App.xaml

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,18 @@
1-
<Application x:Class="SpectrumNet.App"
1+
<Application x:Class="SpectrumNet.App"
22
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44
xmlns:local="clr-namespace:SpectrumNet"
55
xmlns:service="clr-namespace:SpectrumNet.SN.Themes"
66
xmlns:skia="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF"
7-
xmlns:sys="clr-namespace:System;assembly=mscorlib"
8-
StartupUri="MainWindow.xaml">
7+
xmlns:sys="clr-namespace:System;assembly=mscorlib">
98
<Application.Resources>
109
<ResourceDictionary>
1110
<ResourceDictionary.MergedDictionaries>
1211
<ResourceDictionary Source="SN.Themes/Resources/CommonConstants.xaml"/>
13-
1412
<ResourceDictionary Source="SN.Themes/Resources/BaseStyles.xaml"/>
15-
1613
<ResourceDictionary Source="SN.Themes/Resources/Animations.xaml"/>
17-
1814
<ResourceDictionary Source="SN.Themes/Resources/Converters.xaml"/>
19-
2015
<ResourceDictionary Source="SN.Themes/Resources/DarkTheme.xaml"/>
21-
2216
<ResourceDictionary Source="SN.Themes/Resources/TextStyles.xaml"/>
2317
<ResourceDictionary Source="SN.Themes/Resources/ButtonStyles.xaml"/>
2418
<ResourceDictionary Source="SN.Themes/Resources/ComboboxStyles.xaml"/>
@@ -29,7 +23,6 @@
2923
<ResourceDictionary Source="SN.Themes/Resources/GroupBoxStyles.xaml"/>
3024
<ResourceDictionary Source="SN.Themes/Resources/TabControlStyles.xaml"/>
3125
<ResourceDictionary Source="SN.Themes/Resources/SpecialStyles.xaml"/>
32-
3326
</ResourceDictionary.MergedDictionaries>
3427

3528
<Style TargetType="ScrollBar" BasedOn="{StaticResource ModernScrollBarStyle}"/>
@@ -46,7 +39,6 @@
4639
<Setter Property="SnapsToDevicePixels" Value="True"/>
4740
<Setter Property="UseLayoutRounding" Value="True"/>
4841
</Style>
49-
5042
</ResourceDictionary>
5143
</Application.Resources>
52-
</Application>
44+
</Application>

SpectrumNet/App.xaml.cs

Lines changed: 130 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,149 +1,184 @@
1-
#nullable enable
2-
31
namespace SpectrumNet;
42

53
public partial class App : Application
64
{
7-
private const string LogPrefix = nameof(App);
8-
private readonly ISmartLogger _logger = Instance;
9-
private const int SHUTDOWN_TIMEOUT_MS = 5000;
5+
private const int Timeout = 5000;
6+
7+
private IServiceProvider? _svc;
8+
private ISmartLogger? _log;
9+
private ISettingsService? _cfg;
10+
11+
public static IServiceProvider Services => ((App)Current)._svc!;
12+
13+
public static T Get<T>() where T : class =>
14+
Services.GetRequiredService<T>();
1015

1116
protected override void OnStartup(StartupEventArgs e)
1217
{
18+
base.OnStartup(e);
19+
1320
try
1421
{
15-
RenderOptions.ProcessRenderMode = RenderMode.Default;
16-
Initialize();
17-
SetupExceptionHandling();
18-
InitializeApplication();
19-
RegisterApplicationExitHandler();
22+
Configure();
23+
24+
_log = _svc!.GetRequiredService<ISmartLogger>();
25+
_cfg = _svc!.GetRequiredService<ISettingsService>();
26+
27+
SetupExc();
28+
CommonResources.InitialiseResources();
29+
30+
_cfg.Load();
31+
InitTheme();
32+
InitBrush();
33+
CreateMain();
2034
}
2135
catch (Exception ex)
2236
{
23-
LogCriticalStartupError(ex);
37+
_log?.Error(nameof(App), "Startup error", ex);
2438
Shutdown(-1);
2539
}
2640
}
2741

28-
private void SetupExceptionHandling()
42+
private void Configure()
2943
{
30-
AppDomain.CurrentDomain.UnhandledException += (_, args) =>
44+
var sc = new ServiceCollection();
45+
46+
sc.AddSingleton<ISmartLogger>(_ => Instance);
47+
sc.AddSingleton<ISettingsService>(_ => SettingsService.Instance);
48+
sc.AddSingleton<IThemes>(_ => Theme.Instance);
49+
sc.AddSingleton<ITransparencyManager>(_ => TransparencyManager.Instance);
50+
sc.AddSingleton<IBrushProvider>(_ => SpectrumBrushes.Instance);
51+
52+
sc.AddSingleton<IRendererFactory>(p =>
3153
{
32-
if (args.ExceptionObject is Exception ex)
33-
{
34-
_logger.Error(LogPrefix, "Unhandled exception in application", ex);
35-
}
36-
else
37-
{
38-
_logger.Fatal(LogPrefix, $"Unhandled non-Exception object in application: {args.ExceptionObject}");
39-
}
40-
};
54+
RendererFactory r = RendererFactory.Instance;
55+
r.Initialize(
56+
p.GetRequiredService<ISmartLogger>(),
57+
p.GetRequiredService<ITransparencyManager>(),
58+
RenderQuality.Medium);
59+
return r;
60+
});
61+
62+
sc.AddSingleton<IPerformanceMetricsManager>(_ =>
63+
{
64+
PerformanceMetricsManager m = PerformanceMetricsManager.Instance;
65+
m.Initialize();
66+
return m;
67+
});
68+
69+
sc.AddSingleton<MainWindow>();
70+
sc.AddSingleton(CreateCtrl);
71+
72+
sc.AddTransient(p =>
73+
new ControlPanelWindow(p.GetRequiredService<AppController>()));
74+
75+
sc.AddTransient<SettingsWindow>();
76+
77+
_svc = sc.BuildServiceProvider();
4178
}
4279

43-
private void InitializeApplication()
80+
private AppController CreateCtrl(IServiceProvider p)
4481
{
45-
base.OnStartup(null);
46-
CommonResources.InitialiseResources();
47-
SettingsWindow.Instance.LoadSettings();
48-
InitializeBrushProvider();
82+
MainWindow mw = p.GetRequiredService<MainWindow>();
83+
84+
return new AppController(
85+
mw,
86+
mw.SpectrumCanvas,
87+
p.GetRequiredService<ISettingsService>(),
88+
p.GetRequiredService<ISmartLogger>(),
89+
p.GetRequiredService<IRendererFactory>(),
90+
p.GetRequiredService<IBrushProvider>(),
91+
p.GetRequiredService<IThemes>(),
92+
p.GetRequiredService<ITransparencyManager>(),
93+
p.GetRequiredService<IPerformanceMetricsManager>());
4994
}
5095

51-
private void InitializeBrushProvider()
96+
private void CreateMain()
5297
{
53-
if (Resources["PaletteNameToBrushConverter"] is PaletteNameToBrushConverter conv)
54-
conv.BrushesProvider = SpectrumBrushes.Instance;
98+
MainWindow mw = _svc!.GetRequiredService<MainWindow>();
99+
AppController c = _svc!.GetRequiredService<AppController>();
100+
101+
mw.Initialize(c);
102+
mw.Show();
55103
}
56104

57-
private void RegisterApplicationExitHandler()
105+
private void InitTheme()
58106
{
59-
Current.Exit += (_, _) =>
60-
_logger.Log(LogLevel.Information,
61-
LogPrefix,
62-
"Application is shutting down normally",
63-
forceLog: true);
107+
if (_svc == null || _cfg == null) return;
108+
109+
IThemes t = _svc.GetRequiredService<IThemes>();
110+
111+
if (t.IsDarkTheme != _cfg.Current.General.IsDarkTheme)
112+
t.SetTheme(_cfg.Current.General.IsDarkTheme);
64113
}
65114

66-
private void LogCriticalStartupError(Exception ex) =>
67-
_logger.Error(LogPrefix, "Critical error during startup", ex);
115+
private void InitBrush()
116+
{
117+
if (_svc == null) return;
118+
119+
if (Resources["PaletteNameToBrushConverter"] is PaletteNameToBrushConverter c)
120+
c.BrushesProvider =
121+
_svc.GetRequiredService<IBrushProvider>() as SpectrumBrushes;
122+
}
123+
124+
private void SetupExc()
125+
{
126+
AppDomain.CurrentDomain.UnhandledException += (_, a) =>
127+
{
128+
if (a.ExceptionObject is Exception ex)
129+
_log?.Error(nameof(App), "Unhandled", ex);
130+
else
131+
_log?.Fatal(nameof(App), $"Unhandled: {a.ExceptionObject}");
132+
};
133+
}
68134

69135
protected override void OnExit(ExitEventArgs e)
70136
{
137+
DoShutdown();
71138
base.OnExit(e);
72-
PerformShutdownCleanup();
73139
}
74140

75-
private void PerformShutdownCleanup()
141+
private void DoShutdown()
76142
{
77143
try
78144
{
79-
var shutdownTask = Task.Run(CleanupResources);
145+
_cfg?.Apply(_cfg.Current);
80146

81-
if (!shutdownTask.Wait(SHUTDOWN_TIMEOUT_MS))
82-
{
83-
LogShutdownTimeout();
84-
}
147+
var t = Task.Run(DisposeAsync);
148+
149+
if (!t.Wait(Timeout))
150+
_log?.Log(
151+
LogLevel.Warning,
152+
nameof(App),
153+
"Timeout",
154+
forceLog: true);
85155
}
86156
catch (Exception ex)
87157
{
88-
LogShutdownError(ex);
158+
_log?.Log(
159+
LogLevel.Error,
160+
nameof(App),
161+
ex.Message,
162+
forceLog: true);
89163
}
90164
}
91165

92-
private void CleanupResources()
166+
private async Task DisposeAsync()
93167
{
94168
try
95169
{
96-
DisposeSpectrumBrushes();
97-
LogResourceCleanupCompleted();
170+
if (_svc is IAsyncDisposable ad)
171+
await ad.DisposeAsync().ConfigureAwait(false);
172+
else
173+
(_svc as IDisposable)?.Dispose();
98174
}
99175
catch (Exception ex)
100176
{
101-
LogResourceCleanupError(ex);
102-
}
103-
}
104-
105-
private void DisposeSpectrumBrushes()
106-
{
107-
if (SpectrumBrushes.Instance != null)
108-
{
109-
_logger.Log(LogLevel.Information,
110-
LogPrefix,
111-
"Disposing SpectrumBrushes instance",
177+
_log?.Log(
178+
LogLevel.Error,
179+
nameof(App),
180+
ex.Message,
112181
forceLog: true);
113-
114-
SpectrumBrushes.Instance.Dispose();
115182
}
116183
}
117-
118-
private void LogResourceCleanupCompleted()
119-
{
120-
_logger.Log(LogLevel.Information,
121-
LogPrefix,
122-
"Resource cleanup completed",
123-
forceLog: true);
124-
}
125-
126-
private void LogResourceCleanupError(Exception ex)
127-
{
128-
_logger.Log(LogLevel.Error,
129-
LogPrefix,
130-
$"Error during shutdown resource cleanup: {ex.Message}",
131-
forceLog: true);
132-
}
133-
134-
private void LogShutdownTimeout()
135-
{
136-
_logger.Log(LogLevel.Warning,
137-
LogPrefix,
138-
"Shutdown resources cleanup taking too long, continuing with exit",
139-
forceLog: true);
140-
}
141-
142-
private void LogShutdownError(Exception ex)
143-
{
144-
_logger.Log(LogLevel.Error,
145-
LogPrefix,
146-
$"Error during shutdown: {ex.Message}",
147-
forceLog: true);
148-
}
149-
}
184+
}

0 commit comments

Comments
 (0)