Skip to content

Commit 4411c51

Browse files
committed
Check for updates
1 parent b27ebaf commit 4411c51

File tree

5 files changed

+186
-90
lines changed

5 files changed

+186
-90
lines changed

LCSC.App/App.xaml.cs

Lines changed: 74 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using LCSC.Discord.Extensions;
77
using LCSC.Discord.Services;
88
using LCTWorks.Telemetry;
9+
using LCTWorks.WinUI;
910
using LCTWorks.WinUI.Helpers;
1011
using Microsoft.Extensions.Configuration;
1112
using Microsoft.Extensions.DependencyInjection;
@@ -16,91 +17,92 @@
1617
using System.Threading.Tasks;
1718
using Windows.ApplicationModel;
1819

19-
namespace LCSC.App
20+
namespace LCSC.App;
21+
22+
public partial class App : Application, IAppExtended
2023
{
21-
public partial class App : Application
24+
private readonly ITelemetryService? _telemetryService;
25+
26+
public App()
2227
{
23-
private readonly ITelemetryService? _telemetryService;
28+
var configuration = ReadConfigurations();
29+
Services = ConfigureServices(configuration);
30+
BuildHelper.IsDebugBuild = AppHelper.IsDebug();
31+
this.InitializeComponent();
32+
33+
_telemetryService = Services.GetService<ITelemetryService>();
34+
UnhandledException += App_UnhandledException;
35+
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
36+
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
37+
}
2438

25-
public App()
26-
{
27-
var configuration = ReadConfigurations();
28-
Services = ConfigureServices(configuration);
29-
BuildHelper.IsDebugBuild = AppHelper.IsDebug();
30-
this.InitializeComponent();
31-
32-
_telemetryService = Services.GetService<ITelemetryService>();
33-
UnhandledException += App_UnhandledException;
34-
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
35-
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
36-
}
39+
public new static App Current => (App)Application.Current;
3740

38-
public new static App Current => (App)Application.Current;
41+
public static Window MainWindow { get; } = new MainWindow();
3942

40-
public static Window MainWindow { get; } = new MainWindow();
43+
Window IAppExtended.MainWindow => MainWindow;
4144

42-
public IServiceProvider Services { get; }
45+
public IServiceProvider Services { get; }
4346

44-
protected override void OnLaunched(LaunchActivatedEventArgs args)
45-
{
46-
MainWindow.Activate();
47-
}
47+
protected override void OnLaunched(LaunchActivatedEventArgs args)
48+
{
49+
MainWindow.Activate();
50+
}
51+
52+
private static ServiceProvider ConfigureServices(IConfiguration configuration)
53+
=> new ServiceCollection()
54+
//Services
55+
.AddSingleton(new CacheService(ApplicationData.GetDefault().LocalCachePath))
56+
.AddSingleton(sp => new LadderService(sp.GetRequiredService<CacheService>(), configuration["BattleNetSettings:clientId"], configuration["BattleNetSettings:clientSecret"]))
57+
.AddSingleton(sp => new CommunityDataService(sp.GetRequiredService<LadderService>(), sp.GetRequiredService<CacheService>(), configuration["AirBaseSettings:token"], configuration["AirBaseSettings:baseId"], Package.Current.InstalledLocation.Path))
4858

49-
private static ServiceProvider ConfigureServices(IConfiguration configuration)
50-
=> new ServiceCollection()
51-
//Services
52-
.AddSingleton(new CacheService(ApplicationData.GetDefault().LocalCachePath))
53-
.AddSingleton(sp => new LadderService(sp.GetRequiredService<CacheService>(), configuration["BattleNetSettings:clientId"], configuration["BattleNetSettings:clientSecret"]))
54-
.AddSingleton(sp => new CommunityDataService(sp.GetRequiredService<LadderService>(), sp.GetRequiredService<CacheService>(), configuration["AirBaseSettings:token"], configuration["AirBaseSettings:baseId"], Package.Current.InstalledLocation.Path))
55-
56-
//Discord bot
57-
.AddLogging(config =>
58-
{
59-
config.AddConsole();
60-
config.AddProvider(new ConsoleLoggerProvider());
61-
})
62-
.AddSingleton<DiscordBotService>()
63-
.ConfigureDiscordClient(configuration["DiscordSettings:token"])
64-
65-
//ViewModels
66-
.AddSingleton<MainViewModel>()
67-
.AddTransient<DiscordBotViewModel>()
68-
.AddTransient<MembersViewModel>()
69-
.AddTransient<TournamentsViewModel>()
70-
71-
//Telemetry
72-
.AddSentry(configuration["TelemetryKey:key"] ?? string.Empty, AppHelper.GetEnvironment(), BuildHelper.IsDebugBuild, RuntimePackageHelper.GetTelemetryContextData())
73-
.AddSerilog(AppStorageHelper.GetLocalFolder("Log").Path, BuildHelper.IsDebugBuild ? Serilog.Events.LogEventLevel.Debug : Serilog.Events.LogEventLevel.Information, BuildHelper.IsDebugBuild, includeConsole: true)
74-
75-
//Build:
76-
.BuildServiceProvider(true);
77-
78-
private static IConfiguration ReadConfigurations()
59+
//Discord bot
60+
.AddLogging(config =>
7961
{
80-
return new ConfigurationBuilder()
81-
.SetBasePath(Package.Current.InstalledLocation.Path)
82-
.AddJsonFile("assets\\Config\\appsettings.json", false)
83-
.Build();
84-
}
62+
config.AddConsole();
63+
config.AddProvider(new ConsoleLoggerProvider());
64+
})
65+
.AddSingleton<DiscordBotService>()
66+
.ConfigureDiscordClient(configuration["DiscordSettings:token"])
67+
68+
//ViewModels
69+
.AddSingleton<MainViewModel>()
70+
.AddTransient<DiscordBotViewModel>()
71+
.AddTransient<MembersViewModel>()
72+
.AddTransient<TournamentsViewModel>()
73+
74+
//Telemetry
75+
.AddSentry(configuration["TelemetryKey:key"] ?? string.Empty, AppHelper.GetEnvironment(), BuildHelper.IsDebugBuild, RuntimePackageHelper.GetTelemetryContextData())
76+
.AddSerilog(AppStorageHelper.GetLocalFolder("Log").Path, BuildHelper.IsDebugBuild ? Serilog.Events.LogEventLevel.Debug : Serilog.Events.LogEventLevel.Information, BuildHelper.IsDebugBuild, includeConsole: true)
77+
78+
//Build:
79+
.BuildServiceProvider(true);
80+
81+
private static IConfiguration ReadConfigurations()
82+
{
83+
return new ConfigurationBuilder()
84+
.SetBasePath(Package.Current.InstalledLocation.Path)
85+
.AddJsonFile("assets\\Config\\appsettings.json", false)
86+
.Build();
87+
}
8588

86-
private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
87-
=> _telemetryService?.ReportUnhandledException(e.Exception);
89+
private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
90+
=> _telemetryService?.ReportUnhandledException(e.Exception);
8891

89-
private void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs e)
90-
=> _telemetryService?.ReportUnhandledException(e.ExceptionObject as Exception ?? new Exception("Unknown exception"));
92+
private void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs e)
93+
=> _telemetryService?.ReportUnhandledException(e.ExceptionObject as Exception ?? new Exception("Unknown exception"));
9194

92-
private void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs? e)
95+
private void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs? e)
96+
{
97+
if (e?.Exception == null)
98+
{
99+
return;
100+
}
101+
var flattenedExceptions = e.Exception.Flatten().InnerExceptions;
102+
foreach (var exception in flattenedExceptions)
93103
{
94-
if (e?.Exception == null)
95-
{
96-
return;
97-
}
98-
var flattenedExceptions = e.Exception.Flatten().InnerExceptions;
99-
foreach (var exception in flattenedExceptions)
100-
{
101-
_telemetryService?.LogAndTrackError(GetType(), exception);
102-
}
103-
e.SetObserved();
104+
_telemetryService?.LogAndTrackError(GetType(), exception);
104105
}
106+
e.SetObserved();
105107
}
106108
}

LCSC.App/MainWindow.xaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44
xmlns:appBehaviors="using:LCSC.App.Behaviors"
55
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6-
xmlns:interactions="using:Microsoft.Xaml.Interactions.Core"
7-
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
86
xmlns:local="using:LCSC.App"
97
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
108
xmlns:views="using:LCSC.App.Views"
119
xmlns:winex="using:WinUIEx"
1210
Title="LCSC"
1311
MinWidth="800"
1412
MinHeight="600"
13+
Activated="{x:Bind ViewModel.Activated, Mode=OneWay}"
1514
mc:Ignorable="d">
1615

1716
<Grid Background="{StaticResource AppColor2}">
@@ -49,6 +48,6 @@
4948
Margin="24,8"
5049
HorizontalAlignment="Right"
5150
Opacity=".6"
52-
Text="{x:Bind ViewModel.AppVersion}" />
51+
Text="{x:Bind ViewModel.AppVersionNotification, Mode=OneWay}" />
5352
</Grid>
5453
</winex:WindowEx>

LCSC.App/MainWindow.xaml.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using LCSC.App.ViewModels;
22
using Microsoft.Extensions.DependencyInjection;
3-
using Microsoft.UI.Xaml;
43
using WinUIEx;
54

65
namespace LCSC.App
Lines changed: 101 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
using CommunityToolkit.Mvvm.ComponentModel;
2-
using LCSC.App.Models.Messages;
32
using CommunityToolkit.Mvvm.Messaging;
3+
using CommunityToolkit.WinUI.Helpers;
4+
using LCSC.App.Models.Messages;
45
using LCTWorks.WinUI.Helpers;
6+
using Microsoft.UI.Xaml;
7+
using System;
8+
using System.Threading.Tasks;
9+
using Windows.Services.Store;
510

611
namespace LCSC.App.ViewModels;
712

813
public partial class MainViewModel : ObservableRecipient
914
{
15+
private bool _activated;
16+
1017
public MainViewModel()
1118
{
1219
Messenger.Register<MainViewModel, LoadingChangedMessage>(this, (recipient, message) =>
@@ -15,14 +22,103 @@ public MainViewModel()
1522
});
1623
}
1724

18-
public string AppVersion => RuntimePackageHelper.IsDebug() ? "Debug" : RuntimePackageHelper.GetPackageVersion();
25+
[ObservableProperty]
26+
public partial string? AppVersionNotification { get; set; }
1927

20-
public bool IsBotViewEnabled => true;
28+
public bool IsBotViewEnabled { get; } = true;
2129

2230
[ObservableProperty]
2331
public partial bool IsEnabled { get; set; } = true;
2432

25-
public bool IsMembersViewEnabled => true;
33+
public bool IsMembersViewEnabled { get; } = true;
34+
35+
public bool IsTournamentsViewEnabled { get; } = true;
36+
37+
public static StoreContext? GetStoreContext()
38+
{
39+
try
40+
{
41+
var w = App.MainWindow;
42+
var exApp = Application.Current.AsAppExtended();
43+
if (exApp == null || exApp.MainWindow == null)
44+
{
45+
return null;
46+
}
47+
//This here, throws a Win32 Unknown exception. No idea why.
48+
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(exApp.MainWindow);
49+
var storeContext = StoreContext.GetDefault();
50+
WinRT.Interop.InitializeWithWindow.Initialize(storeContext, hWnd);
51+
return storeContext;
52+
}
53+
catch (Exception)
54+
{
55+
return default;
56+
}
57+
}
58+
59+
public void Activated(object _, WindowActivatedEventArgs __)
60+
{
61+
if (_activated)
62+
{
63+
return;
64+
}
65+
CheckForUpdatesAsync();
66+
}
67+
68+
private async void CheckForUpdatesAsync()
69+
{
70+
_activated = true;
71+
var context = GetStoreContext();
72+
if (context == null)
73+
{
74+
await UpdateVersionNotificationAsync("No store context found");
75+
AppVersionNotification = RuntimePackageHelper.IsDebug() ? "Debug" : RuntimePackageHelper.GetPackageVersion();
76+
return;
77+
}
78+
await UpdateVersionNotificationAsync("Store context found");
79+
80+
//Is update available?
81+
var updates = await context.GetAppAndOptionalStorePackageUpdatesAsync();
82+
if (updates.Count > 0)
83+
{
84+
var first = updates[0];
85+
var version = first.Package.Id.Version.ToVersionString();
86+
await UpdateVersionNotificationAsync($"Update found: {version}");
87+
await UpdateVersionNotificationAsync($"Trying to download update...", 200);
88+
89+
var progress = new Progress<StorePackageUpdateStatus>(status =>
90+
{
91+
var progressPercent = status.PackageDownloadProgress * 100;
92+
AppVersionNotification = status.PackageUpdateState switch
93+
{
94+
StorePackageUpdateState.Pending => $"Pending: {progressPercent:F0}%",
95+
StorePackageUpdateState.Downloading => $"Downloading: {progressPercent:F0}%",
96+
StorePackageUpdateState.Deploying => $"Installing: {progressPercent:F0}%",
97+
StorePackageUpdateState.Completed => "Update completed!",
98+
StorePackageUpdateState.Canceled => "Update canceled",
99+
StorePackageUpdateState.ErrorLowBattery => "Error: Low battery",
100+
StorePackageUpdateState.ErrorWiFiRecommended => "Error: WiFi recommended",
101+
StorePackageUpdateState.ErrorWiFiRequired => "Error: WiFi required",
102+
_ => $"Updating... {progressPercent:F0}%"
103+
};
104+
});
26105

27-
public bool IsTournamentsViewEnabled => true;
106+
var result = await context.RequestDownloadAndInstallStorePackageUpdatesAsync(updates)
107+
.AsTask(progress);
108+
109+
if (result.OverallState == StorePackageUpdateState.Completed)
110+
{
111+
await UpdateVersionNotificationAsync("Update installed successfully!");
112+
}
113+
}
114+
115+
//End:
116+
AppVersionNotification = RuntimePackageHelper.IsDebug() ? "Debug" : RuntimePackageHelper.GetPackageVersion();
117+
}
118+
119+
private async Task UpdateVersionNotificationAsync(string? notificationText, int delayInMs = 2000)
120+
{
121+
AppVersionNotification = notificationText;
122+
await Task.Delay(delayInMs);
123+
}
28124
}

LCSC.Models/MemberModel.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,17 @@ public string MMR
8484
{
8585
get
8686
{
87-
if (Profiles != null)
87+
if (Profiles == null)
8888
{
89-
return Profiles
90-
.Where(p => p.LadderRegions != null && p.LadderRegions.Count > 0)
91-
.SelectMany(p => p.LadderRegions!)
92-
.Select(x => x.CurrentMMR)
93-
.Max()
94-
.ToString()
95-
?? string.Empty;
89+
return string.Empty;
9690
}
97-
return string.Empty;
91+
92+
var maxRegion = Profiles
93+
.Where(p => p.LadderRegions != null && p.LadderRegions.Count > 0)
94+
.SelectMany(p => p.LadderRegions!)
95+
.MaxBy(x => x.CurrentMMR);
96+
97+
return maxRegion?.CurrentMMR.ToString() ?? string.Empty;
9898
}
9999
}
100100
}

0 commit comments

Comments
 (0)