Skip to content

Commit 9dd1914

Browse files
committed
refactor: move some codes from App to Views.ControlExtensions
Signed-off-by: leo <longshuang@msn.cn>
1 parent 68831b2 commit 9dd1914

Some content is hidden

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

43 files changed

+637
-640
lines changed

src/App.Commands.cs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
using System;
22
using System.Windows.Input;
3-
4-
using Avalonia.Controls;
53
using Avalonia.Controls.ApplicationLifetimes;
64

75
namespace SourceGit
@@ -45,16 +43,6 @@ public static bool IsCheckForUpdateCommandVisible
4543
public static readonly Command OpenAboutCommand = new Command(async _ => await ShowDialog(new Views.About()));
4644
public static readonly Command CheckForUpdateCommand = new Command(_ => (Current as App)?.Check4Update(true));
4745
public static readonly Command QuitCommand = new Command(_ => Quit(0));
48-
public static readonly Command CopyTextBlockCommand = new Command(async p =>
49-
{
50-
if (p is not TextBlock textBlock)
51-
return;
52-
53-
if (textBlock.Inlines is { Count: > 0 } inlines)
54-
await CopyTextAsync(inlines.Text);
55-
else if (!string.IsNullOrEmpty(textBlock.Text))
56-
await CopyTextAsync(textBlock.Text);
57-
});
5846

5947
public static readonly Command HideAppCommand = new Command(_ =>
6048
{

src/App.axaml.cs

Lines changed: 39 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Diagnostics;
43
using System.IO;
54
using System.Net.Http;
6-
using System.Reflection;
75
using System.Text;
86
using System.Text.Json;
9-
using System.Threading;
107
using System.Threading.Tasks;
118

129
using Avalonia;
1310
using Avalonia.Controls;
1411
using Avalonia.Controls.ApplicationLifetimes;
1512
using Avalonia.Data.Core.Plugins;
16-
using Avalonia.Input.Platform;
1713
using Avalonia.Markup.Xaml;
1814
using Avalonia.Media;
1915
using Avalonia.Media.Fonts;
@@ -32,7 +28,7 @@ public static void Main(string[] args)
3228

3329
AppDomain.CurrentDomain.UnhandledException += (_, e) =>
3430
{
35-
LogException(e.ExceptionObject as Exception);
31+
Native.OS.LogException(e.ExceptionObject as Exception);
3632
};
3733

3834
TaskScheduler.UnobservedTaskException += (_, e) =>
@@ -51,7 +47,7 @@ public static void Main(string[] args)
5147
}
5248
catch (Exception ex)
5349
{
54-
LogException(ex);
50+
Native.OS.LogException(ex);
5551
}
5652
}
5753

@@ -76,52 +72,9 @@ public static AppBuilder BuildAvaloniaApp()
7672
Native.OS.SetupApp(builder);
7773
return builder;
7874
}
79-
80-
public static void LogException(Exception ex)
81-
{
82-
if (ex == null)
83-
return;
84-
85-
var crashDir = Path.Combine(Native.OS.DataDir, "crashes");
86-
if (!Directory.Exists(crashDir))
87-
Directory.CreateDirectory(crashDir);
88-
89-
var time = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
90-
var file = Path.Combine(crashDir, $"{time}.log");
91-
using var writer = new StreamWriter(file);
92-
writer.WriteLine($"Crash::: {ex.GetType().FullName}: {ex.Message}");
93-
writer.WriteLine();
94-
writer.WriteLine("----------------------------");
95-
writer.WriteLine($"Version: {Assembly.GetExecutingAssembly().GetName().Version}");
96-
writer.WriteLine($"OS: {Environment.OSVersion}");
97-
writer.WriteLine($"Framework: {AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName}");
98-
writer.WriteLine($"Source: {ex.Source}");
99-
writer.WriteLine($"Thread Name: {Thread.CurrentThread.Name ?? "Unnamed"}");
100-
writer.WriteLine($"App Start Time: {Process.GetCurrentProcess().StartTime}");
101-
writer.WriteLine($"Exception Time: {DateTime.Now}");
102-
writer.WriteLine($"Memory Usage: {Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024} MB");
103-
writer.WriteLine("----------------------------");
104-
writer.WriteLine();
105-
writer.WriteLine(ex);
106-
writer.Flush();
107-
}
10875
#endregion
10976

11077
#region Utility Functions
111-
public static Control CreateViewForViewModel(object data)
112-
{
113-
var dataTypeName = data.GetType().FullName;
114-
if (string.IsNullOrEmpty(dataTypeName) || !dataTypeName.Contains(".ViewModels.", StringComparison.Ordinal))
115-
return null;
116-
117-
var viewTypeName = dataTypeName.Replace(".ViewModels.", ".Views.");
118-
var viewType = Type.GetType(viewTypeName);
119-
if (viewType != null)
120-
return Activator.CreateInstance(viewType) as Control;
121-
122-
return null;
123-
}
124-
12578
public static Task ShowDialog(object data, Window owner = null)
12679
{
12780
if (owner == null)
@@ -135,7 +88,7 @@ public static Task ShowDialog(object data, Window owner = null)
13588
if (data is Views.ChromelessWindow window)
13689
return window.ShowDialog(owner);
13790

138-
window = CreateViewForViewModel(data) as Views.ChromelessWindow;
91+
window = Views.ControlExtensions.CreateFromViewModels(data) as Views.ChromelessWindow;
13992
if (window != null)
14093
{
14194
window.DataContext = data;
@@ -149,7 +102,7 @@ public static void ShowWindow(object data)
149102
{
150103
if (data is not Views.ChromelessWindow window)
151104
{
152-
window = CreateViewForViewModel(data) as Views.ChromelessWindow;
105+
window = Views.ControlExtensions.CreateFromViewModels(data) as Views.ChromelessWindow;
153106
if (window == null)
154107
return;
155108

@@ -330,19 +283,6 @@ public static void SetFonts(string defaultFont, string monospaceFont)
330283
}
331284
}
332285

333-
public static async Task CopyTextAsync(string data)
334-
{
335-
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow.Clipboard: { } clipboard })
336-
await clipboard.SetTextAsync(data ?? "");
337-
}
338-
339-
public static async Task<string> GetClipboardTextAsync()
340-
{
341-
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow.Clipboard: { } clipboard })
342-
return await clipboard.TryGetTextAsync();
343-
return null;
344-
}
345-
346286
public static string Text(string key, params object[] args)
347287
{
348288
var fmt = Current?.FindResource($"Text.{key}") as string;
@@ -355,19 +295,6 @@ public static string Text(string key, params object[] args)
355295
return string.Format(fmt, args);
356296
}
357297

358-
public static Avalonia.Controls.Shapes.Path CreateMenuIcon(string key)
359-
{
360-
var icon = new Avalonia.Controls.Shapes.Path();
361-
icon.Width = 12;
362-
icon.Height = 12;
363-
icon.Stretch = Stretch.Uniform;
364-
365-
if (Current?.FindResource(key) is StreamGeometry geo)
366-
icon.Data = geo;
367-
368-
return icon;
369-
}
370-
371298
public static ViewModels.Launcher GetLauncher()
372299
{
373300
return Current is App app ? app._launcher : null;
@@ -427,32 +354,12 @@ public override void OnFrameworkInitializationCompleted()
427354
if (TryLaunchAsAskpass(desktop))
428355
return;
429356

430-
_ipcChannel = new Models.IpcChannel();
431-
if (!_ipcChannel.IsFirstInstance)
432-
{
433-
var arg = desktop.Args is { Length: > 0 } ? desktop.Args[0].Trim() : string.Empty;
434-
if (!string.IsNullOrEmpty(arg))
435-
{
436-
if (arg.StartsWith('"') && arg.EndsWith('"'))
437-
arg = arg.Substring(1, arg.Length - 2).Trim();
438-
439-
if (arg.Length > 0 && !Path.IsPathFullyQualified(arg))
440-
arg = Path.GetFullPath(arg);
441-
}
442-
443-
_ipcChannel.SendToFirstInstance(arg);
444-
Environment.Exit(0);
445-
}
446-
else
447-
{
448-
_ipcChannel.MessageReceived += TryOpenRepository;
449-
desktop.Exit += (_, _) => _ipcChannel.Dispose();
450-
TryLaunchAsNormal(desktop);
451-
}
357+
TryLaunchAsNormal(desktop);
452358
}
453359
}
454360
#endregion
455361

362+
#region Launch Ways
456363
private static bool TryLaunchAsRebaseTodoEditor(string[] args, out int exitCode)
457364
{
458365
exitCode = -1;
@@ -613,6 +520,24 @@ private bool TryLaunchAsAskpass(IClassicDesktopStyleApplicationLifetime desktop)
613520

614521
private void TryLaunchAsNormal(IClassicDesktopStyleApplicationLifetime desktop)
615522
{
523+
_ipcChannel = new Models.IpcChannel();
524+
if (!_ipcChannel.IsFirstInstance)
525+
{
526+
var arg = desktop.Args is { Length: > 0 } ? desktop.Args[0].Trim() : string.Empty;
527+
if (!string.IsNullOrEmpty(arg))
528+
{
529+
if (arg.StartsWith('"') && arg.EndsWith('"'))
530+
arg = arg.Substring(1, arg.Length - 2).Trim();
531+
532+
if (arg.Length > 0 && !Path.IsPathFullyQualified(arg))
533+
arg = Path.GetFullPath(arg);
534+
}
535+
536+
_ipcChannel.SendToFirstInstance(arg);
537+
Environment.Exit(0);
538+
return;
539+
}
540+
616541
Native.OS.SetupExternalTools();
617542
Models.AvatarManager.Instance.Start();
618543

@@ -627,40 +552,26 @@ private void TryLaunchAsNormal(IClassicDesktopStyleApplicationLifetime desktop)
627552
desktop.MainWindow = new Views.Launcher() { DataContext = _launcher };
628553
desktop.ShutdownMode = ShutdownMode.OnMainWindowClose;
629554

630-
#if !DISABLE_UPDATE_DETECTION
631-
if (pref.ShouldCheck4UpdateOnStartup())
632-
Check4Update();
633-
#endif
634-
}
635-
636-
private void TryOpenRepository(string repo)
637-
{
638-
if (!string.IsNullOrEmpty(repo) && Directory.Exists(repo))
555+
_ipcChannel.MessageReceived += repo =>
639556
{
640-
var test = new Commands.QueryRepositoryRootPath(repo).GetResult();
641-
if (test.IsSuccess && !string.IsNullOrEmpty(test.StdOut))
557+
Dispatcher.UIThread.Invoke(() =>
642558
{
643-
Dispatcher.UIThread.Invoke(() =>
644-
{
645-
var node = ViewModels.Preferences.Instance.FindOrAddNodeByRepositoryPath(test.StdOut.Trim(), null, false);
646-
ViewModels.Welcome.Instance.Refresh();
647-
_launcher?.OpenRepositoryInTab(node, null);
648-
649-
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: Views.Launcher wnd })
650-
wnd.BringToTop();
651-
});
559+
_launcher.TryOpenRepositoryFromPath(repo);
560+
if (desktop.MainWindow is Views.Launcher main)
561+
main.BringToTop();
562+
});
563+
};
652564

653-
return;
654-
}
655-
}
565+
desktop.Exit += (_, _) => _ipcChannel.Dispose();
656566

657-
Dispatcher.UIThread.Invoke(() =>
658-
{
659-
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: Views.Launcher launcher })
660-
launcher.BringToTop();
661-
});
567+
#if !DISABLE_UPDATE_DETECTION
568+
if (pref.ShouldCheck4UpdateOnStartup())
569+
Check4Update();
570+
#endif
662571
}
572+
#endregion
663573

574+
#region Check for Updates
664575
private void Check4Update(bool manually = false)
665576
{
666577
Task.Run(async () =>
@@ -716,6 +627,7 @@ private void ShowSelfUpdateResult(object data)
716627
// Ignore exceptions.
717628
}
718629
}
630+
#endregion
719631

720632
private string FixFontFamilyName(string input)
721633
{

src/Native/OS.cs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
using System.Collections.Generic;
33
using System.Diagnostics;
44
using System.IO;
5+
using System.Reflection;
56
using System.Text;
67
using System.Text.RegularExpressions;
7-
8+
using System.Threading;
89
using Avalonia;
910
using Avalonia.Controls;
1011

@@ -153,6 +154,35 @@ public static void SetupForWindow(Window window)
153154
_backend.SetupWindow(window);
154155
}
155156

157+
public static void LogException(Exception ex)
158+
{
159+
if (ex == null)
160+
return;
161+
162+
var crashDir = Path.Combine(DataDir, "crashes");
163+
if (!Directory.Exists(crashDir))
164+
Directory.CreateDirectory(crashDir);
165+
166+
var time = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
167+
var file = Path.Combine(crashDir, $"{time}.log");
168+
using var writer = new StreamWriter(file);
169+
writer.WriteLine($"Crash::: {ex.GetType().FullName}: {ex.Message}");
170+
writer.WriteLine();
171+
writer.WriteLine("----------------------------");
172+
writer.WriteLine($"Version: {Assembly.GetExecutingAssembly().GetName().Version}");
173+
writer.WriteLine($"OS: {Environment.OSVersion}");
174+
writer.WriteLine($"Framework: {AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName}");
175+
writer.WriteLine($"Source: {ex.Source}");
176+
writer.WriteLine($"Thread Name: {Thread.CurrentThread.Name ?? "Unnamed"}");
177+
writer.WriteLine($"App Start Time: {Process.GetCurrentProcess().StartTime}");
178+
writer.WriteLine($"Exception Time: {DateTime.Now}");
179+
writer.WriteLine($"Memory Usage: {Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024} MB");
180+
writer.WriteLine("----------------------------");
181+
writer.WriteLine();
182+
writer.WriteLine(ex);
183+
writer.Flush();
184+
}
185+
156186
public static string FindGitExecutable()
157187
{
158188
return _backend.FindGitExecutable();

src/Resources/Styles.axaml

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -540,36 +540,6 @@
540540
<Setter Property="Foreground" Value="{DynamicResource Brush.InlineCodeFG}"/>
541541
</Style>
542542

543-
<Style Selector="SelectableTextBlock">
544-
<Setter Property="HorizontalAlignment" Value="Left"/>
545-
<Setter Property="VerticalAlignment" Value="Center"/>
546-
<Setter Property="Foreground" Value="{DynamicResource Brush.FG1}"/>
547-
</Style>
548-
<Style Selector="SelectableTextBlock[IsEnabled=True]">
549-
<Setter Property="ContextFlyout">
550-
<Setter.Value>
551-
<MenuFlyout Placement="Bottom">
552-
<MenuItem Header="{DynamicResource Text.Copy}"
553-
Command="{Binding $parent[SelectableTextBlock].Copy}"
554-
IsEnabled="{Binding $parent[SelectableTextBlock].CanCopy}"
555-
InputGesture="{x:Static TextBox.CopyGesture}">
556-
<MenuItem.Icon>
557-
<Path Width="11" Height="11" Data="{StaticResource Icons.Copy}" VerticalAlignment="Center"/>
558-
</MenuItem.Icon>
559-
</MenuItem>
560-
561-
<MenuItem Header="{DynamicResource Text.CopyAllText}"
562-
Command="{x:Static s:App.CopyTextBlockCommand}"
563-
CommandParameter="{Binding $parent[SelectableTextBlock]}">
564-
<MenuItem.Icon>
565-
<Path Width="11" Height="11" Data="{StaticResource Icons.Copy}" VerticalAlignment="Center"/>
566-
</MenuItem.Icon>
567-
</MenuItem>
568-
</MenuFlyout>
569-
</Setter.Value>
570-
</Setter>
571-
</Style>
572-
573543
<Style Selector="TextBox">
574544
<Setter Property="CornerRadius" Value="0"/>
575545
<Setter Property="Padding" Value="4,0"/>

0 commit comments

Comments
 (0)