11using Avalonia ;
22using Avalonia . Controls . ApplicationLifetimes ;
3- using Avalonia . Data . Core . Plugins ;
43using Avalonia . Markup . Xaml ;
5- using Froststrap . AvaloniaUI . ViewModels ;
4+ using Avalonia . Threading ;
5+ using Microsoft . Win32 ;
6+ using System . Reflection ;
7+ using System . Security . Cryptography ;
8+ using System . Text ;
69using Froststrap . AvaloniaUI . Views ;
10+ using Froststrap . AvaloniaUI . ViewModels ;
11+ using Froststrap . Integrations ;
12+
13+ namespace Froststrap ;
714
8- namespace Froststrap . AvaloniaUI ;
15+
16+ /*
17+ * shits currently broken right now
18+ * - WPF-only Base Types
19+ * - WPF UI Libraries
20+ * - Global Exception Handling (we gonna have fun fixing that one)
21+ * - Fonts (Avalonia uses asset based font loading)
22+ * - Rendering & GPU Control
23+ * - Message Boxes (MessageBox.Avalonia comes in clutch)
24+ * - Taskbar Integration (Does anyone even realize we have this????)
25+ * - Window Enumeration & Lifetime
26+ * - WPF Resource System (Probably easy to fix)
27+ * - WPF Startup & Exit Hooks (Also probably easy to fix)
28+ * - Dispatcher-Based Threading (Use: Dispatcher.UIThread)
29+ * - Windows-Only UX APIs. Backdrop, Transparency etc. (Probably just make these Windows exclusive)
30+ *
31+ * This is just ONE file, alebit a fairly big and important one.
32+ */
933
1034public partial class App : Application
1135{
36+ #if QA_BUILD
37+ public const string ProjectName = "Froststrap-QA" ;
38+ #else
39+ public const string ProjectName = "Froststrap" ;
40+ #endif
41+
42+ public const string ProjectOwner = "RealMeddsam" ;
43+ public const string ProjectRepository = "RealMeddsam/Froststrap" ;
44+ public const string ProjectDownloadLink = "https://github.com/RealMeddsam/Froststrap/releases" ;
45+ public const string ProjectHelpLink = "https://github.com/bloxstraplabs/bloxstrap/wiki" ; // Most likely need to make our own wiki after we finish rewrite
46+ public const string ProjectSupportLink = "https://github.com/RealMeddsam/Froststrap/issues/new" ;
47+ public const string ProjectRemoteDataLink = "https://raw.githubusercontent.com/RealMeddsam/config/refs/heads/main/Data.json" ;
48+
49+ // Windows only for now
50+ public const string RobloxPlayerAppName = "RobloxPlayerBeta.exe" ;
51+ public const string RobloxStudioAppName = "RobloxStudioBeta.exe" ;
52+
53+ // one day ill add studio support
54+ // edit: are you sure about that?
55+ public const string RobloxAnselAppName = "eurotrucks2.exe" ;
56+
57+ // Not yet sure whats the point of this but ok
58+ public const string UninstallKey = $@ "Software\Microsoft\Windows\CurrentVersion\Uninstall\{ ProjectName } ";
59+ public const string ApisKey = $ "Software\\ { ProjectName } ";
60+
61+
62+ public static LaunchSettings LaunchSettings { get ; private set ; } = null ! ;
63+ public static readonly MD5 MD5Provider = MD5 . Create ( ) ;
64+ public static readonly Logger Logger = new ( ) ;
65+
66+ public static Bootstrapper ? Bootstrapper { get ; set ; } = null ! ;
67+ public FroststrapRichPresence RichPresence { get ; private set ; } = null ! ;
68+ public static MemoryCleaner MemoryCleaner { get ; private set ; } = null ! ; // doubt this is necessary on Linux
69+
70+ public static bool IsActionBuild => ! String . IsNullOrEmpty ( BuildMetadata . CommitRef ) ;
71+ public static bool IsProductionBuild => IsActionBuild && BuildMetadata . CommitRef . StartsWith ( "tag" , StringComparison . Ordinal ) ;
72+ public static bool IsPlayerInstalled => App . PlayerState . IsSaved && ! String . IsNullOrEmpty ( App . PlayerState . Prop . VersionGuid ) ;
73+ public static bool IsStudioInstalled => App . StudioState . IsSaved && ! String . IsNullOrEmpty ( App . StudioState . Prop . VersionGuid ) ;
74+
75+
76+ // Disambiguate Settings so we use the persistable Settings (Bloxstrap.Models.Persistable.Settings),
77+ // not the auto-generated Properties.Settings which doesn't contain the clicker fields.
78+ public static readonly JsonManager < Settings > Settings = new ( ) ;
79+ public static readonly JsonManager < State > State = new ( ) ;
80+ public static readonly LazyJsonManager < DistributionState > PlayerState = new ( nameof ( PlayerState ) ) ;
81+ public static readonly LazyJsonManager < DistributionState > StudioState = new ( nameof ( StudioState ) ) ;
82+ public static readonly RemoteDataManager RemoteData = new ( ) ;
83+ public static readonly FastFlagManager FastFlags = new ( ) ;
84+ public static readonly GBSEditor GlobalSettings = new ( ) ;
85+ public static readonly CookiesManager Cookies = new ( ) ;
86+ public static readonly HttpClient HttpClient = new ( new HttpClientLoggingHandler ( new HttpClientHandler { AutomaticDecompression = DecompressionMethods . All } ) ) ;
87+
88+ public static BuildMetadataAttribute BuildMetadata =
89+ Assembly . GetExecutingAssembly ( ) . GetCustomAttribute < BuildMetadataAttribute > ( ) ! ;
90+
91+ public static string Version =
92+ Assembly . GetExecutingAssembly ( ) . GetName ( ) . Version ! . ToString ( ) ;
93+
94+ private static bool _showingExceptionDialog ;
95+
1296 public override void Initialize ( )
1397 {
1498 AvaloniaXamlLoader . Load ( this ) ;
99+
100+ // Global exception handlers (Avalonia replacement)
101+ AppDomain . CurrentDomain . UnhandledException += OnUnhandledException ;
102+ TaskScheduler . UnobservedTaskException += OnUnobservedTaskException ;
15103 }
16104
17105 public override void OnFrameworkInitializationCompleted ( )
18106 {
19107 if ( ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop )
20108 {
21- // Avoid duplicate validations from both Avalonia and the CommunityToolkit.
22- // More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
23- DisableAvaloniaDataAnnotationValidation ( ) ;
109+ LaunchSettings = new LaunchSettings ( Environment . GetCommandLineArgs ( ) ) ;
110+
111+ Logger . WriteLine ( "App::Startup" , $ "Starting { ProjectName } v{ Version } ") ;
112+
24113 desktop . MainWindow = new MainWindow
25114 {
26- DataContext = new MainWindowViewModel ( ) ,
115+ DataContext = new MainWindowViewModel ( )
27116 } ;
28117 }
29118
30119 base . OnFrameworkInitializationCompleted ( ) ;
31120 }
32121
33- private void DisableAvaloniaDataAnnotationValidation ( )
122+ private void OnUnhandledException ( object ? sender , UnhandledExceptionEventArgs e )
34123 {
35- // Get an array of plugins to remove
36- var dataValidationPluginsToRemove =
37- BindingPlugins . DataValidators . OfType < DataAnnotationsValidationPlugin > ( ) . ToArray ( ) ;
124+ if ( e . ExceptionObject is Exception ex )
125+ FinalizeExceptionHandling ( ex ) ;
126+ }
38127
39- // remove each entry found
40- foreach ( var plugin in dataValidationPluginsToRemove )
128+ private void OnUnobservedTaskException ( object ? sender , UnobservedTaskExceptionEventArgs e )
129+ {
130+ e . SetObserved ( ) ;
131+ FinalizeExceptionHandling ( e . Exception ) ;
132+ }
133+
134+ public static void FinalizeExceptionHandling ( Exception ex )
135+ {
136+ if ( _showingExceptionDialog )
137+ return ;
138+
139+ _showingExceptionDialog = true ;
140+
141+ Logger . WriteException ( "App::Fatal" , ex ) ;
142+
143+ Dispatcher . UIThread . Post ( ( ) =>
144+ {
145+ // TODO: replace with MessageBox.Avalonia dialog
146+ // Frontend.ShowExceptionDialog(ex);
147+
148+ Environment . Exit ( ( int ) ErrorCode . ERROR_INSTALL_FAILURE ) ;
149+ } ) ;
150+ }
151+
152+ public static void Terminate ( ErrorCode exitCode = ErrorCode . ERROR_SUCCESS )
153+ {
154+ Logger . WriteLine ( "App::Terminate" , exitCode . ToString ( ) ) ;
155+ Environment . Exit ( ( int ) exitCode ) ;
156+ }
157+
158+ public static void SoftTerminate ( ErrorCode exitCode = ErrorCode . ERROR_SUCCESS )
159+ {
160+ if ( Current ? . ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop )
161+ {
162+ desktop . Shutdown ( ( int ) exitCode ) ;
163+ }
164+ else
41165 {
42- BindingPlugins . DataValidators . Remove ( plugin ) ;
166+ Environment . Exit ( ( int ) exitCode ) ;
43167 }
44168 }
45- }
169+ }
0 commit comments