11using System ;
22using System . Collections . Generic ;
3- using System . Diagnostics ;
43using System . IO ;
54using System . Net . Http ;
6- using System . Reflection ;
75using System . Text ;
86using System . Text . Json ;
9- using System . Threading ;
107using System . Threading . Tasks ;
118
129using Avalonia ;
1310using Avalonia . Controls ;
1411using Avalonia . Controls . ApplicationLifetimes ;
1512using Avalonia . Data . Core . Plugins ;
16- using Avalonia . Input . Platform ;
1713using Avalonia . Markup . Xaml ;
1814using Avalonia . Media ;
1915using 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 {
0 commit comments