From 77b922cc6e477a1352899dafd62317f4768e2c91 Mon Sep 17 00:00:00 2001 From: Jebzou <22751386+Jebzou@users.noreply.github.com> Date: Sun, 24 Nov 2024 14:15:56 +0100 Subject: [PATCH] Bonodere integration (#514) --- .../ApiReqRanking/Models/ApiList.cs | 2 +- ElectronicObserver/App.xaml.cs | 12 ++ .../Data/Bonodere/BonodereError.cs | 12 ++ .../Data/Bonodere/BonodereHttpClient.cs | 160 ++++++++++++++++++ .../Data/Bonodere/BonodereLoginRequest.cs | 15 ++ .../Data/Bonodere/BonodereLoginResponse.cs | 12 ++ .../Bonodere/BonodereSubmissionRequest.cs | 11 ++ .../BonodereSubmissionResources.en.resx | 129 ++++++++++++++ .../Bonodere/BonodereSubmissionResources.resx | 129 ++++++++++++++ .../Bonodere/BonodereSubmissionService.cs | 103 +++++++++++ .../BonodereSubmissionTranslationViewModel.cs | 10 ++ .../Data/Bonodere/BonodereUser.cs | 12 ++ .../Data/Bonodere/BonodereUserDataResponse.cs | 9 + .../Data/Bonodere/BonodereUserInfo.cs | 9 + ElectronicObserver/Data/ConstantsRes.en.resx | 108 ++++++------ .../Data/SenkaLeaderboardRefreshKind.cs | 7 + .../TsunDbSubmissionManager.cs | 2 +- ElectronicObserver/FormMainWpf.xaml | 11 ++ ElectronicObserver/Observer/APIObserver.cs | 15 +- .../{getlist.cs => mxltvkpyuklh.cs} | 19 ++- .../Dialog/ConfigurationResources.en.resx | 36 +++- .../Window/Dialog/ConfigurationResources.resx | 27 ++- .../Window/HeadquartersResources.en.resx | 9 +- .../Services/TimeChangeService.cs | 20 ++- .../Utility/ConfigDataSubmission.cs | 6 + ElectronicObserver/Utility/Configuration.cs | 11 +- .../Utility/SoftwareInformation.cs | 1 - .../Utility/Storage/DataStorage.cs | 4 - .../ViewModels/FormMainViewModel.cs | 11 +- .../FormMainTranslationViewModel.cs | 1 + .../Control/Paging/PagingControlViewModel.cs | 28 ++- .../Window/Dialog/DialogLocalAPILoader2.cs | 83 +++++---- .../Window/Dialog/DialogTsunDb.Designer.cs | 112 ------------ .../Window/Dialog/DialogTsunDb.cs | 35 ---- ...nfigurationBehaviorTranslationViewModel.cs | 3 - .../ConfigurationBehaviorUserControl.xaml | 8 +- .../ConfigurationBehaviorViewModel.cs | 22 --- ...ationDataSubmissionTranslationViewModel.cs | 11 +- ...onfigurationDataSubmissionUserControl.xaml | 100 +++++++++++ ...igurationDataSubmissionUserControl.xaml.cs | 10 +- .../ConfigurationDataSubmissionViewModel.cs | 91 +++++++++- .../ApiFile/ApiFileExplorerUserControl.xaml | 1 + .../ApiFile/ApiFileExplorerViewModel.cs | 10 ++ .../Wpf/SenkaLeaderboard/SenkaEntryModel.cs | 24 +++ .../SenkaLeaderboardManager.cs | 85 ++++++++++ .../SenkaLeaderboardResources.en.resx | 138 +++++++++++++++ .../SenkaLeaderboardResources.resx | 138 +++++++++++++++ .../SenkaLeaderboardTranslationViewModel.cs | 16 ++ .../SenkaLeaderboardView.xaml | 82 +++++++++ .../SenkaLeaderboardView.xaml.cs | 20 +++ .../SenkaLeaderboardViewModel.cs | 151 +++++++++++++++++ .../SenkaLeaderboardViewModelProxy.cs | 8 + .../Window/Wpf/ViewTemplateSelector.cs | 3 + .../Window/Wpf/ViewTemplates.xaml | 5 + 54 files changed, 1769 insertions(+), 328 deletions(-) create mode 100644 ElectronicObserver/Data/Bonodere/BonodereError.cs create mode 100644 ElectronicObserver/Data/Bonodere/BonodereHttpClient.cs create mode 100644 ElectronicObserver/Data/Bonodere/BonodereLoginRequest.cs create mode 100644 ElectronicObserver/Data/Bonodere/BonodereLoginResponse.cs create mode 100644 ElectronicObserver/Data/Bonodere/BonodereSubmissionRequest.cs create mode 100644 ElectronicObserver/Data/Bonodere/BonodereSubmissionResources.en.resx create mode 100644 ElectronicObserver/Data/Bonodere/BonodereSubmissionResources.resx create mode 100644 ElectronicObserver/Data/Bonodere/BonodereSubmissionService.cs create mode 100644 ElectronicObserver/Data/Bonodere/BonodereSubmissionTranslationViewModel.cs create mode 100644 ElectronicObserver/Data/Bonodere/BonodereUser.cs create mode 100644 ElectronicObserver/Data/Bonodere/BonodereUserDataResponse.cs create mode 100644 ElectronicObserver/Data/Bonodere/BonodereUserInfo.cs create mode 100644 ElectronicObserver/Data/SenkaLeaderboardRefreshKind.cs rename ElectronicObserver/Observer/kcsapi/api_req_ranking/{getlist.cs => mxltvkpyuklh.cs} (58%) delete mode 100644 ElectronicObserver/Window/Dialog/DialogTsunDb.Designer.cs delete mode 100644 ElectronicObserver/Window/Dialog/DialogTsunDb.cs create mode 100644 ElectronicObserver/Window/Wpf/SenkaLeaderboard/SenkaEntryModel.cs create mode 100644 ElectronicObserver/Window/Wpf/SenkaLeaderboard/SenkaLeaderboardManager.cs create mode 100644 ElectronicObserver/Window/Wpf/SenkaLeaderboard/SenkaLeaderboardResources.en.resx create mode 100644 ElectronicObserver/Window/Wpf/SenkaLeaderboard/SenkaLeaderboardResources.resx create mode 100644 ElectronicObserver/Window/Wpf/SenkaLeaderboard/SenkaLeaderboardTranslationViewModel.cs create mode 100644 ElectronicObserver/Window/Wpf/SenkaLeaderboard/SenkaLeaderboardView.xaml create mode 100644 ElectronicObserver/Window/Wpf/SenkaLeaderboard/SenkaLeaderboardView.xaml.cs create mode 100644 ElectronicObserver/Window/Wpf/SenkaLeaderboard/SenkaLeaderboardViewModel.cs create mode 100644 ElectronicObserver/Window/Wpf/SenkaLeaderboard/SenkaLeaderboardViewModelProxy.cs diff --git a/ElectronicObserver.KancolleApi.Types/ApiReqRanking/Models/ApiList.cs b/ElectronicObserver.KancolleApi.Types/ApiReqRanking/Models/ApiList.cs index 0a521db4f..415971922 100644 --- a/ElectronicObserver.KancolleApi.Types/ApiReqRanking/Models/ApiList.cs +++ b/ElectronicObserver.KancolleApi.Types/ApiReqRanking/Models/ApiList.cs @@ -21,5 +21,5 @@ public class ApiList public int ApiItslcqtmrxtf { get; set; } [JsonPropertyName("api_wuhnhojjxmke")] - public long ApiWuhnhojjxmke { get; set; } + public decimal ApiWuhnhojjxmke { get; set; } } diff --git a/ElectronicObserver/App.xaml.cs b/ElectronicObserver/App.xaml.cs index ef1e608ff..2f08b4b69 100644 --- a/ElectronicObserver/App.xaml.cs +++ b/ElectronicObserver/App.xaml.cs @@ -13,6 +13,7 @@ using CommunityToolkit.Mvvm.DependencyInjection; using ElectronicObserver.Common; using ElectronicObserver.Data; +using ElectronicObserver.Data.Bonodere; using ElectronicObserver.Database; using ElectronicObserver.Database.DataMigration; using ElectronicObserver.Dialogs; @@ -72,6 +73,7 @@ using ElectronicObserver.Window.Wpf; using ElectronicObserver.Window.Wpf.EquipmentUpgradePlanViewer; using ElectronicObserver.Window.Wpf.ExpeditionCheck; +using ElectronicObserver.Window.Wpf.SenkaLeaderboard; using ElectronicObserver.Window.Wpf.ShipTrainingPlanner; using ElectronicObserverTypes.Data; using Jot; @@ -308,6 +310,8 @@ private void ConfigureServices() .AddSingleton() .AddSingleton() .AddSingleton() + .AddSingleton() + .AddSingleton() // tools .AddSingleton() .AddSingleton() @@ -326,6 +330,8 @@ private void ConfigureServices() .AddSingleton() .AddSingleton() .AddSingleton() + .AddSingleton() + .AddSingleton() // issue reporter .AddSingleton() .AddSingleton() @@ -471,6 +477,12 @@ private static Tracker JotTracker() .Property(w => w.ViewModel.DataGridViewModel.ColumnProperties) .Property(w => w.ViewModel.DataGridViewModel.SortDescriptions); + tracker + .Configure() + .Property(w => w.CurrentCutoffData.DataGridViewModel.ColumnProperties) + .Property(w => w.CurrentCutoffData.DataGridViewModel.SortDescriptions) + .Property(w => w.CurrentCutoffData.PagingViewModel.ItemsPerPage); + return tracker; } } diff --git a/ElectronicObserver/Data/Bonodere/BonodereError.cs b/ElectronicObserver/Data/Bonodere/BonodereError.cs new file mode 100644 index 000000000..78afb3f62 --- /dev/null +++ b/ElectronicObserver/Data/Bonodere/BonodereError.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace ElectronicObserver.Data.Bonodere; + +public class BonodereError +{ + [JsonPropertyName("message")] + public string Message { get; set; } = ""; + + [JsonPropertyName("code")] + public int Code { get; set; } +} diff --git a/ElectronicObserver/Data/Bonodere/BonodereHttpClient.cs b/ElectronicObserver/Data/Bonodere/BonodereHttpClient.cs new file mode 100644 index 000000000..f9eb8382b --- /dev/null +++ b/ElectronicObserver/Data/Bonodere/BonodereHttpClient.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Http.Json; +using System.Runtime.InteropServices; +using System.Security; +using System.Threading.Tasks; +using ElectronicObserver.Utility; +using ElectronicObserver.Window.Wpf.SenkaLeaderboard; + +namespace ElectronicObserver.Data.Bonodere; + +public class BonodereHttpClient(BonodereSubmissionTranslationViewModel translations) +{ + private HttpClient? CurrentClient { get; set; } + + public bool IsReady => CurrentClient is not null; + + private BonodereSubmissionTranslationViewModel Translations { get; } = translations; + + private static HttpClient MakeHttpClient() => new() + { + BaseAddress = new("https://bonodere.famluro.es/api/"), + DefaultRequestHeaders = + { + UserAgent = + { +#if DEBUG + new ProductInfoHeaderValue($"ElectronicObserverEN-DEBUG", SoftwareInformation.VersionEnglish), +#else + new ProductInfoHeaderValue($"ElectronicObserverEN", SoftwareInformation.VersionEnglish), +#endif + }, + }, + }; + + public async Task Login(string login, SecureString password) + { + CurrentClient = MakeHttpClient(); + + HttpResponseMessage response = await CurrentClient.PostAsJsonAsync("auth/login", new BonodereLoginRequest + { + Key = login, + Password = SecureStringToString(password), + Duration = 1500000000, + }); + + response.EnsureSuccessStatusCode(); + + BonodereLoginResponse? responseParsed = await response.Content.ReadFromJsonAsync(); + + if (responseParsed is null) + { + CurrentClient.Dispose(); + CurrentClient = null; + return null; + } + + CurrentClient = MakeHttpClient(); + CurrentClient.DefaultRequestHeaders.Add("x-access-token", responseParsed.Token); + + return responseParsed; + } + + public async Task LoginFromToken(string token, string userId) + { + CurrentClient?.Dispose(); + CurrentClient = null; + + CurrentClient = MakeHttpClient(); + CurrentClient.DefaultRequestHeaders.Add("x-access-token", token); + + HttpResponseMessage response = await CurrentClient.GetAsync($"user/data/{userId}"); + + if (!response.IsSuccessStatusCode) + { + await HandleErrorResponse(response); + return null; + } + + BonodereUserDataResponse? responseParsed = await response.Content.ReadFromJsonAsync(); + + if (responseParsed is null) + { + CurrentClient.Dispose(); + CurrentClient = null; + return null; + } + + return responseParsed; + } + + public async Task Logout() + { + if (CurrentClient is null) return; + + HttpResponseMessage response = await CurrentClient.PostAsJsonAsync("auth/logout", new object()); + + if (!response.IsSuccessStatusCode) + { + await HandleErrorResponse(response); + } + + CurrentClient.Dispose(); + CurrentClient = null; + } + + public async Task SubmitData(List data) + { + if (CurrentClient is null) return; + + HttpResponseMessage response = await CurrentClient.PostAsJsonAsync("senka/submit", new BonodereSubmissionRequest() + { + Data = data, + }); + + if (!response.IsSuccessStatusCode) + { + await HandleErrorResponse(response); + } + else + { + Logger.Add(2, Translations.Success); + } + } + + private async Task HandleErrorResponse(HttpResponseMessage response) + { + BonodereError? errorData = await response.Content.ReadFromJsonAsync(); + + if (errorData is not null && !string.IsNullOrEmpty(errorData.Message)) + { + Logger.Add(2, errorData switch + { + { Code: >0 } => $"{Translations.Error} : {errorData.Message} ({errorData.Code})", + _ => $"{Translations.Error} : {errorData.Message}", + }); + } + else + { + response.EnsureSuccessStatusCode(); + } + } + + private string SecureStringToString(SecureString value) + { + IntPtr valuePtr = IntPtr.Zero; + + try + { + valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value); + return Marshal.PtrToStringUni(valuePtr) ?? ""; + } + finally + { + Marshal.ZeroFreeGlobalAllocUnicode(valuePtr); + } + } +} diff --git a/ElectronicObserver/Data/Bonodere/BonodereLoginRequest.cs b/ElectronicObserver/Data/Bonodere/BonodereLoginRequest.cs new file mode 100644 index 000000000..de45024a1 --- /dev/null +++ b/ElectronicObserver/Data/Bonodere/BonodereLoginRequest.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace ElectronicObserver.Data.Bonodere; + +public class BonodereLoginRequest +{ + [JsonPropertyName("key")] + public required string Key { get; set; } + + [JsonPropertyName("password")] + public required string Password { get; set; } + + [JsonPropertyName("duration")] + public required int Duration { get; set; } +} diff --git a/ElectronicObserver/Data/Bonodere/BonodereLoginResponse.cs b/ElectronicObserver/Data/Bonodere/BonodereLoginResponse.cs new file mode 100644 index 000000000..dd5dac35b --- /dev/null +++ b/ElectronicObserver/Data/Bonodere/BonodereLoginResponse.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace ElectronicObserver.Data.Bonodere; + +public class BonodereLoginResponse +{ + [JsonPropertyName("token")] + public required string Token { get; set; } + + [JsonPropertyName("user")] + public required BonodereUser User { get; set; } +} diff --git a/ElectronicObserver/Data/Bonodere/BonodereSubmissionRequest.cs b/ElectronicObserver/Data/Bonodere/BonodereSubmissionRequest.cs new file mode 100644 index 000000000..389ccc7a3 --- /dev/null +++ b/ElectronicObserver/Data/Bonodere/BonodereSubmissionRequest.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; +using ElectronicObserver.Window.Wpf.SenkaLeaderboard; + +namespace ElectronicObserver.Data.Bonodere; + +public class BonodereSubmissionRequest +{ + [JsonPropertyName("data")] + public required List Data { get; set; } +} diff --git a/ElectronicObserver/Data/Bonodere/BonodereSubmissionResources.en.resx b/ElectronicObserver/Data/Bonodere/BonodereSubmissionResources.en.resx new file mode 100644 index 000000000..bf64301f3 --- /dev/null +++ b/ElectronicObserver/Data/Bonodere/BonodereSubmissionResources.en.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Bonodere error + + + Bonodere submission : Success + + + Inconsistant data detected + + \ No newline at end of file diff --git a/ElectronicObserver/Data/Bonodere/BonodereSubmissionResources.resx b/ElectronicObserver/Data/Bonodere/BonodereSubmissionResources.resx new file mode 100644 index 000000000..11c32b90f --- /dev/null +++ b/ElectronicObserver/Data/Bonodere/BonodereSubmissionResources.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Bonodereエラー + + + Bonodere提出:成功 + + + 不整合データ検出 + + \ No newline at end of file diff --git a/ElectronicObserver/Data/Bonodere/BonodereSubmissionService.cs b/ElectronicObserver/Data/Bonodere/BonodereSubmissionService.cs new file mode 100644 index 000000000..ecc7aad60 --- /dev/null +++ b/ElectronicObserver/Data/Bonodere/BonodereSubmissionService.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security; +using System.Threading.Tasks; +using ElectronicObserver.Utility; +using ElectronicObserver.Window.Wpf.SenkaLeaderboard; + +namespace ElectronicObserver.Data.Bonodere; + +public class BonodereSubmissionService +{ + private BonodereSubmissionTranslationViewModel BonodereSubmission { get; } + + private BonodereHttpClient BonodereClient { get; } + + public string Username { get; set; } = ""; + + public BonodereSubmissionService(BonodereSubmissionTranslationViewModel translations) + { + BonodereSubmission = translations; + BonodereClient = new(BonodereSubmission); + + _ = LoginFromSavedToken(); + + Configuration.Instance.ConfigurationChanged += async () => await LoginFromSavedToken(); + } + + public async Task Login(string login, SecureString password) + { + return await BonodereClient.Login(login, password); + } + + public async Task LoginFromSavedToken() + { + + if (string.IsNullOrEmpty(Configuration.Config.DataSubmission.BonodereToken)) return; + + try + { + BonodereUserDataResponse? loginResponse = await BonodereClient.LoginFromToken(Configuration.Config.DataSubmission.BonodereToken, Configuration.Config.DataSubmission.BonodereUserId); + + if (loginResponse is not null) + { + Username = loginResponse.User.UserInfo.Username; + } + } + catch (Exception ex) + { + LogError(ex); + } + } + + public async Task Logout() + { + if (!BonodereClient.IsReady) return; + + try + { + await BonodereClient.Logout(); + Username = ""; + } + catch (Exception ex) + { + LogError(ex); + } + } + + public async Task SubmitData(List data) + { + if (!BonodereClient.IsReady) return; + + if (!IsDataValid(data)) + { + Logger.Add(2, $"{BonodereSubmission.Error}: {BonodereSubmission.InconsistantDataDetected}"); + return; + } + + try + { + await BonodereClient.SubmitData(data); + } + catch (Exception ex) + { + LogError(ex); + } + } + + private bool IsDataValid(List data) + { + if (data.Any(entry => entry.Points < 0)) return false; + if (data.Any(entry => entry.Position > 500)) return false; + if (data.Any(entry => entry.Position <= 0)) return false; + if (data.Any(entry => !entry.IsKnown)) return false; + + return true; + } + + private void LogError(Exception e) + { + Logger.Add(2, BonodereSubmission.Error, e); + } +} diff --git a/ElectronicObserver/Data/Bonodere/BonodereSubmissionTranslationViewModel.cs b/ElectronicObserver/Data/Bonodere/BonodereSubmissionTranslationViewModel.cs new file mode 100644 index 000000000..dc2598e39 --- /dev/null +++ b/ElectronicObserver/Data/Bonodere/BonodereSubmissionTranslationViewModel.cs @@ -0,0 +1,10 @@ +using ElectronicObserver.ViewModels.Translations; + +namespace ElectronicObserver.Data.Bonodere; + +public class BonodereSubmissionTranslationViewModel : TranslationBaseViewModel +{ + public string InconsistantDataDetected => BonodereSubmissionResources.InconsistantDataDetected; + public string Error => BonodereSubmissionResources.BonodereError; + public string Success => BonodereSubmissionResources.BonodereSubmissionSuccess; +} diff --git a/ElectronicObserver/Data/Bonodere/BonodereUser.cs b/ElectronicObserver/Data/Bonodere/BonodereUser.cs new file mode 100644 index 000000000..61c35cd88 --- /dev/null +++ b/ElectronicObserver/Data/Bonodere/BonodereUser.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace ElectronicObserver.Data.Bonodere; + +public class BonodereUser +{ + [JsonPropertyName("_id")] + public required string Id { get; set; } + + [JsonPropertyName("info")] + public required BonodereUserInfo UserInfo { get; set; } +} diff --git a/ElectronicObserver/Data/Bonodere/BonodereUserDataResponse.cs b/ElectronicObserver/Data/Bonodere/BonodereUserDataResponse.cs new file mode 100644 index 000000000..4b84ed50c --- /dev/null +++ b/ElectronicObserver/Data/Bonodere/BonodereUserDataResponse.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace ElectronicObserver.Data.Bonodere; + +public class BonodereUserDataResponse +{ + [JsonPropertyName("data")] + public required BonodereUser User { get; set; } +} diff --git a/ElectronicObserver/Data/Bonodere/BonodereUserInfo.cs b/ElectronicObserver/Data/Bonodere/BonodereUserInfo.cs new file mode 100644 index 000000000..c7da69660 --- /dev/null +++ b/ElectronicObserver/Data/Bonodere/BonodereUserInfo.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace ElectronicObserver.Data.Bonodere; + +public class BonodereUserInfo +{ + [JsonPropertyName("name")] + public required string Username { get; set; } +} diff --git a/ElectronicObserver/Data/ConstantsRes.en.resx b/ElectronicObserver/Data/ConstantsRes.en.resx index e7491de23..5c6ec7225 100644 --- a/ElectronicObserver/Data/ConstantsRes.en.resx +++ b/ElectronicObserver/Data/ConstantsRes.en.resx @@ -132,6 +132,9 @@ Air Battle + + AI- + AI @@ -633,20 +636,20 @@ - Air Base - - - Contact: + + Formation: - - / Enemy Contact: + + / Enemy Formation: Engagement: - - Formation: + + Contact: - - / Enemy Formation: + + / Enemy Contact: Combined Fleet @@ -654,24 +657,27 @@ == {0} == - - Base {0} - == Battle Finished == - - Enemy Contact + + Base {0} Contact + + Enemy Contact + #{0}: {1} {2} HP: {3} / {4} - FP:{5}, Torp:{6}, AA:{7}, Armor:{8} - FP:{0}, Torp:{1}, AA:{2}, Armor:{3} + + ◆ Battle Result ◆ + Rank: {0} @@ -681,17 +687,20 @@ MVP (Escort Fleet): {0} - - ◆ Battle Result ◆ + + Ship Exp: +{0} + + + Admiral Exp: +{0} Drop: - - Admiral Exp: +{0} + + Enemy Starshell: : {0} #{1} - - Ship Exp: +{0} + + Enemy Searchlight: {0} #{1} Starshell: : {0} #{1} @@ -699,15 +708,12 @@ Searchlight: {0} #{1} - - Enemy Searchlight: {0} #{1} - - - Enemy Starshell: : {0} #{1} - Night Contact: + + Enemy Night Contact: + Detection @@ -717,57 +723,51 @@ Air Raid + + Combined Fleet Air Raid + Combined Fleet Air Battle - - Combined Fleet Air Raid + + Air Base Raid + + + Suijou Butai Combined Fleet Day Battle Combined Fleet Opening Night Battle - - Kidou Butai Day Battle + + Practice Night Battle - - Suijou Butai Combined Fleet Day Battle + + Practice Day Battle - - Opening Night Battle + + Night Battle Day Battle - - Night Battle + + Opening Night Battle Enemy Combined Fleet Day Battle - - Kidou Butai Combined Fleet Day Battle - - - Air Base Raid - Enemy Combined Fleet Night Battle - - Enemy Night Contact: - - - Practice Day Battle + + Kidou Butai Day Battle - - Practice Night Battle + + Kidou Butai Combined Fleet Day Battle AA Cut-in type #{2} ( {0}, {1} ) - - AI- - DD CI (Torpx2+Lookout) @@ -834,6 +834,9 @@ Base Damaged + + No Damage + Vanguard @@ -924,9 +927,6 @@ Amphibious Attack (Toku Daihatsu+Tank) - - No Damage - CI (MG+Torp) diff --git a/ElectronicObserver/Data/SenkaLeaderboardRefreshKind.cs b/ElectronicObserver/Data/SenkaLeaderboardRefreshKind.cs new file mode 100644 index 000000000..63603c75e --- /dev/null +++ b/ElectronicObserver/Data/SenkaLeaderboardRefreshKind.cs @@ -0,0 +1,7 @@ +namespace ElectronicObserver.Data; + +public enum SenkaLeaderboardRefreshKind +{ + NewDay, + MidDay, +} diff --git a/ElectronicObserver/Data/TsunDbSubmission/TsunDbSubmissionManager.cs b/ElectronicObserver/Data/TsunDbSubmission/TsunDbSubmissionManager.cs index 0ac37cb4d..df0ef6fc7 100644 --- a/ElectronicObserver/Data/TsunDbSubmission/TsunDbSubmissionManager.cs +++ b/ElectronicObserver/Data/TsunDbSubmission/TsunDbSubmissionManager.cs @@ -35,7 +35,7 @@ private void ConfigurationChanged() /// api_data or RawData public override void LoadFromResponse(string apiname, dynamic data) { - if (Configuration.Config.Control.SubmitDataToTsunDb != true) return; + if (!Configuration.Config.DataSubmission.SubmitDataToTsunDb) return; KCDatabase db = KCDatabase.Instance; diff --git a/ElectronicObserver/FormMainWpf.xaml b/ElectronicObserver/FormMainWpf.xaml index 94f1ace38..4443338b8 100644 --- a/ElectronicObserver/FormMainWpf.xaml +++ b/ElectronicObserver/FormMainWpf.xaml @@ -414,6 +414,16 @@ + + + + + + diff --git a/ElectronicObserver/Observer/APIObserver.cs b/ElectronicObserver/Observer/APIObserver.cs index 4d3e77c04..0b8d2c12b 100644 --- a/ElectronicObserver/Observer/APIObserver.cs +++ b/ElectronicObserver/Observer/APIObserver.cs @@ -546,11 +546,10 @@ public sealed class APIObserver public kcsapi.api_req_combined_battle.goback_port ApiReqCombinedBattle_GoBackPort { get; } = new(); /// - /// Ranking list before 2016/08/01 (?)
- /// + /// Ranking list
+ /// ///
- [Obsolete] - public kcsapi.api_req_ranking.getlist ApiReqRanking_GetList { get; } = new(); + public kcsapi.api_req_ranking.mxltvkpyuklh ApiReqRanking_Mxltvkpyuklh { get; } = new(); /// /// FCF single fleet
@@ -672,7 +671,7 @@ private APIObserver() ApiReqKousyou_RemodelSlot, ApiGetMember_Material, ApiReqMission_Result, - ApiReqRanking_GetList, + ApiReqRanking_Mxltvkpyuklh, ApiReqSortie_AirBattle, ApiGetMember_ShipDeck, ApiReqKaisou_Marriage, @@ -1060,12 +1059,6 @@ public void LoadResponse(string path, string data) ResponseReceived(shortpath, json); APIList.OnResponseReceived(shortpath, json); } - else if (shortpath.Contains("api_req_ranking")) - { - shortpath = "api_req_ranking/getlist"; - ResponseReceived(shortpath, json.api_data); - APIList.OnResponseReceived(shortpath, json.api_data); - } else if (json.IsDefined("api_data")) { ResponseReceived(shortpath, json.api_data); diff --git a/ElectronicObserver/Observer/kcsapi/api_req_ranking/getlist.cs b/ElectronicObserver/Observer/kcsapi/api_req_ranking/mxltvkpyuklh.cs similarity index 58% rename from ElectronicObserver/Observer/kcsapi/api_req_ranking/getlist.cs rename to ElectronicObserver/Observer/kcsapi/api_req_ranking/mxltvkpyuklh.cs index d44bd51c4..6bd206fa2 100644 --- a/ElectronicObserver/Observer/kcsapi/api_req_ranking/getlist.cs +++ b/ElectronicObserver/Observer/kcsapi/api_req_ranking/mxltvkpyuklh.cs @@ -5,7 +5,7 @@ namespace ElectronicObserver.Observer.kcsapi.api_req_ranking; -public class getlist : APIBase +public class mxltvkpyuklh : APIBase { public override void OnResponseReceived(dynamic data) { @@ -13,25 +13,28 @@ public override void OnResponseReceived(dynamic data) string pattern = new StringBuilder("\"api_.{12}\":[0-9]*,\"api_.{12}\":\"").AppendFormat("{0}\"", db.Admiral.AdmiralName).ToString(); - Regex regex = new Regex(pattern); + Regex regex = new Regex(pattern, RegexOptions.None, TimeSpan.FromMilliseconds(1000)); try { string rankData = regex.Match(data.ToString()).Value; - if (string.IsNullOrEmpty(rankData)) return; - rankData = rankData.Split(',')[0].Split(':')[1].Replace('"', '\0'); - db.Admiral.Senka = int.Parse(rankData); + + if (!string.IsNullOrEmpty(rankData)) + { + rankData = rankData.Split(',')[0].Split(':')[1].Replace('"', '\0'); + db.Admiral.Senka = int.Parse(rankData); + } } catch (Exception ex) - { //ファイルがロックされている; 頻繁に出るのでエラーレポートを残さない - + { + //ファイルがロックされている; 頻繁に出るのでエラーレポートを残さない Utility.Logger.Add(3, LoggerRes.FailedSaveAPI + ex.Message); } base.OnResponseReceived((object)data); } - public override string APIName => "api_req_ranking/getlist"; + public override string APIName => "api_req_ranking/mxltvkpyuklh"; public override bool IsResponseSupported => true; } diff --git a/ElectronicObserver/Properties/Window/Dialog/ConfigurationResources.en.resx b/ElectronicObserver/Properties/Window/Dialog/ConfigurationResources.en.resx index 6fa884a58..27d43298a 100644 --- a/ElectronicObserver/Properties/Window/Dialog/ConfigurationResources.en.resx +++ b/ElectronicObserver/Properties/Window/Dialog/ConfigurationResources.en.resx @@ -689,12 +689,12 @@ It only works if automatic refresh is enabled. May increase processing load.The proxy auto-config script has been saved. The file path was copied to clipboard, paste it to the proxy settings in Internet Explorer. - - Failed to save proxy auto-config script. - PAC Script Saved + + Failed to save proxy auto-config script. + BGM player volume will be set to {0}. Are you sure? @@ -711,15 +711,15 @@ Are you sure? Japanese + + Use Gadget Redirect * + You should restart EO after changing the theme or language. Language: - - Use Gadget Redirect * - Redirect the gadget api call to bypass the foreigner block. If you live in Japan or use a Japanese VPN you can keep this option disabled. @@ -775,4 +775,28 @@ For example, if attempting to use "http://luckyjervis.com/gadget_html5/js/kcs_co Training plan completed + + Bonodere integration + + + Logged in as + + + Login + + + Logout + + + Password + + + Username + + + Privacy policy + + + Data submission FAQ + \ No newline at end of file diff --git a/ElectronicObserver/Properties/Window/Dialog/ConfigurationResources.resx b/ElectronicObserver/Properties/Window/Dialog/ConfigurationResources.resx index 5ecd2d9c9..86fb40496 100644 --- a/ElectronicObserver/Properties/Window/Dialog/ConfigurationResources.resx +++ b/ElectronicObserver/Properties/Window/Dialog/ConfigurationResources.resx @@ -655,9 +655,6 @@ APIリストの書式や用法はオンラインヘルプを参照してくだ 秘書のアイコンをゲーム画像として使用 - - - TsunDb送信を有効にする @@ -799,4 +796,28 @@ APIリストの書式や用法はオンラインヘルプを参照してくだ 艦娘訓練終了 + + Bonodere統合 + + + ログイン名 + + + ログイン + + + ログアウト + + + パスワード + + + ユーザー名 + + + プライバシーポリシー + + + データ提出に関するFAQ + \ No newline at end of file diff --git a/ElectronicObserver/Properties/Window/HeadquartersResources.en.resx b/ElectronicObserver/Properties/Window/HeadquartersResources.en.resx index 92b2bceb4..d0d979a8b 100644 --- a/ElectronicObserver/Properties/Window/HeadquartersResources.en.resx +++ b/ElectronicObserver/Properties/Window/HeadquartersResources.en.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + HQ @@ -194,14 +197,14 @@ Weekly: {1:+##;-##;±0} Monthly: {2:+##;-##;±0} - - buckets - (S) x {0} ( +{1} ) (M) x {2} ( +{3} ) (L) x {4} ( +{5} ) + + buckets + devmats diff --git a/ElectronicObserver/Services/TimeChangeService.cs b/ElectronicObserver/Services/TimeChangeService.cs index 80898d3b5..48c0d71ab 100644 --- a/ElectronicObserver/Services/TimeChangeService.cs +++ b/ElectronicObserver/Services/TimeChangeService.cs @@ -11,23 +11,35 @@ namespace ElectronicObserver.Services; public class TimeChangeService : ObservableObject { public DayOfWeek CurrentDayOfWeekJST { get; private set; } + private int CurrentHour { get; set; } public event Action DayChanged = delegate { }; + public event Action HourChanged = delegate { }; public TimeChangeService() { PropertyChanged += TimeChangeService_PropertyChanged; - SystemEvents.UpdateTimerTick += SystemEvents_UpdateTimerTick; + SystemEvents.UpdateTimerTick += OnTick; } - private void SystemEvents_UpdateTimerTick() + private void OnTick() { - CurrentDayOfWeekJST = DateTimeHelper.GetJapanStandardTimeNow().DayOfWeek; + DateTime time = DateTimeHelper.GetJapanStandardTimeNow(); + CurrentDayOfWeekJST = time.DayOfWeek; + CurrentHour = time.Hour; } private void TimeChangeService_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) { - if (e.PropertyName == nameof(CurrentDayOfWeekJST)) DayChanged(); + if (e.PropertyName == nameof(CurrentDayOfWeekJST)) + { + DayChanged(); + } + + if (e.PropertyName == nameof(CurrentHour)) + { + HourChanged(); + } } } diff --git a/ElectronicObserver/Utility/ConfigDataSubmission.cs b/ElectronicObserver/Utility/ConfigDataSubmission.cs index 1c1c13c73..68fede439 100644 --- a/ElectronicObserver/Utility/ConfigDataSubmission.cs +++ b/ElectronicObserver/Utility/ConfigDataSubmission.cs @@ -3,4 +3,10 @@ public sealed class ConfigDataSubmission : Configuration.ConfigurationData.ConfigPartBase { public bool SendDataToPoiPreview { get; set; } = true; + + public bool BonodereIntegrationEnabled { get; set; } + public string BonodereUserId { get; set; } = ""; + public string BonodereToken { get; set; } = ""; + + public bool SubmitDataToTsunDb { get; set; } } diff --git a/ElectronicObserver/Utility/Configuration.cs b/ElectronicObserver/Utility/Configuration.cs index 8a7f5ab22..407f9610e 100644 --- a/ElectronicObserver/Utility/Configuration.cs +++ b/ElectronicObserver/Utility/Configuration.cs @@ -1891,6 +1891,7 @@ public ConfigFleetImageGenerator() BackgroundColor = "#FF000000"; } } + [DataMember] public ConfigFleetImageGenerator FleetImageGenerator { get; private set; } @@ -1949,7 +1950,6 @@ public ConfigurationData() public override void Initialize() { - Connection = new ConfigConnection(); UI = new ConfigUI(); Log = new ConfigLog(); @@ -1987,7 +1987,6 @@ public override void Initialize() Whitecap = new ConfigWhitecap(); VersionUpdateTime = DateTimeHelper.TimeToCSVString(SoftwareInformation.UpdateTime); - } } private static ConfigurationData _config; @@ -2013,6 +2012,7 @@ internal void OnConfigurationChanged() public void Load() { var temp = (ConfigurationData)_config.Load(SaveFileName); + if (temp != null) { // hack: set defaults for players that have a configuration before language was added @@ -2706,6 +2706,8 @@ private void CheckUpdate() if (dt <= DateTimeHelper.CSVStringToTime("2020/06/07 23:00:00")) Update460_AddSallyAreaColorScheme(); + if (dt <= DateTimeHelper.CSVStringToTime("2024/11/24 20:00:00")) + Update538_ChangeTsunDbConfig(); Config.VersionUpdateTime = DateTimeHelper.TimeToCSVString(SoftwareInformation.UpdateTime); } @@ -2964,4 +2966,9 @@ private void Update460_AddSallyAreaColorScheme() Utility.Logger.Add(1, "<= ver. 4.6.0 移行処理: カラースキームの追加が完了しました。"); } } + + private void Update538_ChangeTsunDbConfig() + { + Config.DataSubmission.SubmitDataToTsunDb = Config.Control.SubmitDataToTsunDb is true; + } } diff --git a/ElectronicObserver/Utility/SoftwareInformation.cs b/ElectronicObserver/Utility/SoftwareInformation.cs index 5554164b6..0cb28f004 100644 --- a/ElectronicObserver/Utility/SoftwareInformation.cs +++ b/ElectronicObserver/Utility/SoftwareInformation.cs @@ -33,7 +33,6 @@ public static class SoftwareInformation ///
public static string VersionEnglish => typeof(App).Assembly.GetName().Version.ToString(); - /// /// 更新日時 /// diff --git a/ElectronicObserver/Utility/Storage/DataStorage.cs b/ElectronicObserver/Utility/Storage/DataStorage.cs index ba0f59c9a..b8d559cd4 100644 --- a/ElectronicObserver/Utility/Storage/DataStorage.cs +++ b/ElectronicObserver/Utility/Storage/DataStorage.cs @@ -82,18 +82,14 @@ public void Save(StringBuilder stringBuilder) public DataStorage Load(string path) { - try { - var serializer = new DataContractSerializer(this.GetType()); using (XmlReader xr = XmlReader.Create(path)) { return (DataStorage)serializer.ReadObject(xr); } - - } catch (FileNotFoundException) { diff --git a/ElectronicObserver/ViewModels/FormMainViewModel.cs b/ElectronicObserver/ViewModels/FormMainViewModel.cs index 2b6ecc04c..139ac8648 100644 --- a/ElectronicObserver/ViewModels/FormMainViewModel.cs +++ b/ElectronicObserver/ViewModels/FormMainViewModel.cs @@ -75,6 +75,7 @@ using MessageBox = System.Windows.MessageBox; using Timer = System.Windows.Forms.Timer; using ElectronicObserver.Avalonia.ExpeditionCalculator; +using ElectronicObserver.Window.Wpf.SenkaLeaderboard; #if DEBUG using System.Text.Encodings.Web; @@ -141,6 +142,7 @@ public partial class FormMainViewModel : ObservableObject public ShipGroupAvaloniaViewModel ShipGroup { get; } public FleetPresetViewModel FleetPreset { get; } public ShipTrainingPlanViewerViewModel ShipTrainingPlanViewer { get; } + public SenkaLeaderboardViewModel SenkaLeaderboardViewer { get; } public DockViewModel Dock { get; } public ArsenalViewModel Arsenal { get; } @@ -148,6 +150,7 @@ public partial class FormMainViewModel : ObservableObject public BaseAirCorpsViewModel BaseAirCorps { get; } public HeadquartersViewModel Headquarters { get; } + public QuestViewModel Quest { get; } public ExpeditionCheckViewModel ExpeditionCheck { get; } public InformationViewModel FormInformation { get; } @@ -253,6 +256,8 @@ public FormMainViewModel(DockingManager dockingManager, FormMainWpf window) Views.Add(FleetPreset = new FleetPresetViewModel()); ShipTrainingPlanViewer = Ioc.Default.GetRequiredService(); Views.Add(ShipTrainingPlanViewer); + SenkaLeaderboardViewer = Ioc.Default.GetRequiredService().CurrentCutoffData; + Views.Add(SenkaLeaderboardViewer); Views.Add(Dock = new DockViewModel()); Views.Add(Arsenal = new ArsenalViewModel()); @@ -1021,12 +1026,6 @@ private async Task LoadBaseAPI() await LoadAPIResponse("api_get_member/require_info"); await LoadAPIResponse("api_port/port"); await LoadAPIResponse("api_get_member/questlist"); - /*await LoadAPIResponse("api_get_member/mapinfo"); - await LoadAPIResponse("api_req_map/start_air_base"); - await LoadAPIResponse("api_req_map/start"); - await LoadAPIResponse("api_req_sortie/battle"); - await LoadAPIResponse("api_req_sortie/battleresult"); - await LoadAPIResponse("api_req_map/next");*/ } catch (Exception ex) { diff --git a/ElectronicObserver/ViewModels/Translations/FormMainTranslationViewModel.cs b/ElectronicObserver/ViewModels/Translations/FormMainTranslationViewModel.cs index 529979445..e18347ef6 100644 --- a/ElectronicObserver/ViewModels/Translations/FormMainTranslationViewModel.cs +++ b/ElectronicObserver/ViewModels/Translations/FormMainTranslationViewModel.cs @@ -70,6 +70,7 @@ public class FormMainTranslationViewModel : TranslationBaseViewModel public string StripMenu_Tool_ConstructionRecord => MainResources.Tool_ConstructionRecord.Replace("_", "__").Replace("&", "_"); public string StripMenu_Tool_ResourceChart => MainResources.Tool_ResourceChart.Replace("_", "__").Replace("&", "_"); public string SenkaViewer => SenkaViewerResources.Title; + public string SenkaLeaderboard => SenkaLeaderboardResources.Title; public string ExpeditionRecordViewer => ExpeditionRecordViewerResources.Title; public string StripMenu_Tool_AlbumMasterShip => MainResources.Tool_AlbumMasterShip.Replace("_", "__").Replace("&", "_"); public string StripMenu_Tool_AlbumMasterEquipment => MainResources.Tool_AlbumMasterEquipment.Replace("_", "__").Replace("&", "_"); diff --git a/ElectronicObserver/Window/Control/Paging/PagingControlViewModel.cs b/ElectronicObserver/Window/Control/Paging/PagingControlViewModel.cs index 184ecaccc..e0d6a8151 100644 --- a/ElectronicObserver/Window/Control/Paging/PagingControlViewModel.cs +++ b/ElectronicObserver/Window/Control/Paging/PagingControlViewModel.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; @@ -12,7 +13,7 @@ public partial class PagingControlViewModel : ObservableObject public List Items { get; set; } = new(); - public List DisplayedItems { get; private set; } = new(); + public ObservableCollection DisplayedItems { get; } = []; public int ItemsPerPage { get; set; } = 10; @@ -27,6 +28,15 @@ public PagingControlViewModel() UpdateCollection(); } + public void DisplayPageFromElementKey(int elementKey) + { + int page = elementKey / ItemsPerPage; + + if (page > LastPage) return; + + CurrentPage = page + 1; + } + private void OnPagerUpdate2(object? sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName is nameof(CurrentPage) or nameof(LastPage)) return; @@ -46,15 +56,19 @@ private void UpdateCollection() { CurrentPage = Math.Clamp(CurrentPage, 1, LastPage); - DisplayedItems = Items switch + DisplayedItems.Clear(); + + if (Items.Count > 0) { - { Count: > 0 } => Items + IEnumerable items = Items .Skip(ItemsPerPage * (CurrentPage - 1)) - .Take(ItemsPerPage) - .ToList(), + .Take(ItemsPerPage); - _ => new(), - }; + foreach (object item in items) + { + DisplayedItems.Add(item); + } + } OnPropertyChanged(nameof(LastPage)); } diff --git a/ElectronicObserver/Window/Dialog/DialogLocalAPILoader2.cs b/ElectronicObserver/Window/Dialog/DialogLocalAPILoader2.cs index 63c45ae08..f0410532f 100644 --- a/ElectronicObserver/Window/Dialog/DialogLocalAPILoader2.cs +++ b/ElectronicObserver/Window/Dialog/DialogLocalAPILoader2.cs @@ -31,6 +31,8 @@ public partial class DialogLocalAPILoader2 : Form private List ApiFilesBeforeSortie { get; set; } = []; private List ApiFilesAfterSortie { get; set; } = []; + private List ApiFilesToLoad { get; set; } = []; + private string CurrentPath { get; set; } @@ -46,6 +48,11 @@ public DialogLocalAPILoader2(SortieRecord sortieRecord) : this() SortieRecord = sortieRecord; } + public DialogLocalAPILoader2(List fileses) : this() + { + ApiFilesToLoad = fileses; + } + public void Translate() { APIView_FileName.HeaderText = LocalAPILoader2Resources.APIView_FileName; @@ -74,6 +81,8 @@ private void DialogLocalAPILoader2_Load(object sender, EventArgs e) { LoadSortieRecordFiles(SortieRecord); } + + LoadSpecificApiFiles(ApiFilesToLoad); } @@ -135,13 +144,13 @@ private void ButtonExecuteNext_Click(object sender, EventArgs e) DataGridViewRow row = APIView.SelectedRows[0]; int index = APIView.SelectedRows[0].Index; - if (SortieRecord is null) + if (ApiFilesToLoad.Count > 0) { - ExecuteAPI((string)row.Cells[APIView_FileName.Index].Value); + ExecuteDatabaseSavedRecordApi((string)row.Cells[APIView_FileName.Index].Value); } else { - ExecuteSortieRecordApi((string)row.Cells[APIView_FileName.Index].Value); + ExecuteAPI((string)row.Cells[APIView_FileName.Index].Value); } APIView.ClearSelection(); @@ -192,10 +201,6 @@ private void LoadSortieRecordFiles(SortieRecord sortieRecord) { if (sortieRecord.ApiFiles.Count is 0) return; - APIView.Rows.Clear(); - - List rows = []; - int firstSortieApiFileId = sortieRecord.ApiFiles.MinBy(f => f.Id)!.Id; int lastSortieApiFileId = sortieRecord.ApiFiles.MaxBy(f => f.Id)!.Id; @@ -227,11 +232,24 @@ private void LoadSortieRecordFiles(SortieRecord sortieRecord) .Where(f => f.Id <= portFileIdAfterSortieId) .ToList(); - IEnumerable apiFiles = ApiFilesBeforeSortie + ApiFilesToLoad = ApiFilesBeforeSortie .Concat(sortieRecord.ApiFiles) - .Concat(ApiFilesAfterSortie); + .Concat(ApiFilesAfterSortie) + .ToList(); + } - foreach (string file in apiFiles.Select(f => $"{f.Id} {f.ApiFileType} {f.Name}")) + private void LoadSpecificApiFiles(List files) + { + if (files.Count is 0) return; + + APIView.Rows.Clear(); + + List rows = []; + + ElectronicObserverContext db = new(); + db.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; + + foreach (string file in files.Select(f => $"{f.Id} {f.ApiFileType} {f.Name}")) { DataGridViewRow row = new(); row.CreateCells(APIView); @@ -245,7 +263,6 @@ private void LoadSortieRecordFiles(SortieRecord sortieRecord) } - //filename format: yyyyMMdd_hhmmssff[Q|S]@apipath@apiname.json private string GetAPIName(string fileName) { @@ -302,10 +319,8 @@ private void ExecuteAPI(string filename) } - private void ExecuteSortieRecordApi(string filename) + private void ExecuteDatabaseSavedRecordApi(string filename) { - Debug.Assert(SortieRecord is not null); - string[] values = filename.Split(" "); int recordId = int.Parse(values[0]); @@ -314,10 +329,7 @@ private void ExecuteSortieRecordApi(string filename) if (!APIObserver.Instance.APIList.ContainsKey(apiName)) return; - ApiFile apiFile = ApiFilesBeforeSortie - .Concat(SortieRecord.ApiFiles) - .Concat(ApiFilesAfterSortie) - .First(f => f.Id == recordId); + ApiFile apiFile = ApiFilesToLoad.First(f => f.Id == recordId); if (apiFile is { Name: "api_port/port", ApiFileType: ApiFileType.Response }) { @@ -337,20 +349,23 @@ private void ExecuteSortieRecordApi(string filename) apiFilePortResponse.ApiData.ApiLog = savedPortResponse.ApiData.ApiLog; apiFilePortResponse.ApiData.ApiNdock = savedPortResponse.ApiData.ApiNdock; - apiFilePortResponse.ApiData.ApiDeckPort = SortieRecord.FleetData.Fleets - .Select((f, i) => f switch - { - null => null, - - _ => new FleetDataDto + if (SortieRecord is not null) + { + apiFilePortResponse.ApiData.ApiDeckPort = SortieRecord.FleetData.Fleets + .Select((f, i) => f switch { - ApiId = i + 1, - ApiShip = f.Ships.Select(s => s.DropId ?? 0).ToList(), - ApiMission = [0, 0, 0, 0], - }, - }) - .OfType() - .ToList(); + null => null, + + _ => new FleetDataDto + { + ApiId = i + 1, + ApiShip = f.Ships.Select(s => s.DropId ?? 0).ToList(), + ApiMission = [0, 0, 0, 0], + }, + }) + .OfType() + .ToList(); + } apiFile.Content = JsonSerializer.Serialize(apiFilePortResponse, JsonSerializerOptions); } @@ -377,10 +392,10 @@ private void APICaller_DoWork(object sender, DoWorkEventArgs e) { if (e.Argument is not IEnumerable files) return; - Action act = SortieRecord switch + Action act = ApiFilesToLoad.Count switch { - null => ExecuteAPI, - _ => ExecuteSortieRecordApi, + 0 => ExecuteAPI, + _ => ExecuteDatabaseSavedRecordApi, }; foreach (string? file in files) diff --git a/ElectronicObserver/Window/Dialog/DialogTsunDb.Designer.cs b/ElectronicObserver/Window/Dialog/DialogTsunDb.Designer.cs deleted file mode 100644 index 74c9f5b79..000000000 --- a/ElectronicObserver/Window/Dialog/DialogTsunDb.Designer.cs +++ /dev/null @@ -1,112 +0,0 @@ -namespace ElectronicObserver.Window.Dialog -{ - partial class DialogTsunDb - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.buttonEnable = new System.Windows.Forms.Button(); - this.buttonDisable = new System.Windows.Forms.Button(); - this.labelTsunDbText = new System.Windows.Forms.Label(); - this.labelTsunDbText2 = new System.Windows.Forms.Label(); - this.linkLabelTsunDbText = new System.Windows.Forms.LinkLabel(); - this.SuspendLayout(); - // - // buttonEnable - // - this.buttonEnable.Location = new System.Drawing.Point(12, 57); - this.buttonEnable.Name = "buttonEnable"; - this.buttonEnable.Size = new System.Drawing.Size(131, 23); - this.buttonEnable.TabIndex = 0; - this.buttonEnable.Text = "Help the tsuns"; - this.buttonEnable.UseVisualStyleBackColor = true; - this.buttonEnable.Click += new System.EventHandler(this.buttonEnable_Click); - // - // buttonDisable - // - this.buttonDisable.Location = new System.Drawing.Point(166, 57); - this.buttonDisable.Name = "buttonDisable"; - this.buttonDisable.Size = new System.Drawing.Size(164, 23); - this.buttonDisable.TabIndex = 0; - this.buttonDisable.Text = "Disable data submission"; - this.buttonDisable.UseVisualStyleBackColor = true; - this.buttonDisable.Click += new System.EventHandler(this.buttonDisable_Click); - // - // labelTsunDbText - // - this.labelTsunDbText.AutoSize = true; - this.labelTsunDbText.Location = new System.Drawing.Point(12, 10); - this.labelTsunDbText.Name = "labelTsunDbText"; - this.labelTsunDbText.Size = new System.Drawing.Size(285, 15); - this.labelTsunDbText.TabIndex = 1; - this.labelTsunDbText.Text = "You can help out by submitting your data to TsunDb "; - // - // labelTsunDbText2 - // - this.labelTsunDbText2.AutoSize = true; - this.labelTsunDbText2.Location = new System.Drawing.Point(12, 30); - this.labelTsunDbText2.Name = "labelTsunDbText2"; - this.labelTsunDbText2.Size = new System.Drawing.Size(158, 15); - this.labelTsunDbText2.TabIndex = 1; - this.labelTsunDbText2.Text = "Check out our privacy policy"; - // - // linkLabelTsunDbText - // - this.linkLabelTsunDbText.AutoSize = true; - this.linkLabelTsunDbText.Location = new System.Drawing.Point(167, 30); - this.linkLabelTsunDbText.Name = "linkLabelTsunDbText"; - this.linkLabelTsunDbText.Size = new System.Drawing.Size(30, 15); - this.linkLabelTsunDbText.TabIndex = 2; - this.linkLabelTsunDbText.TabStop = true; - this.linkLabelTsunDbText.Text = "here"; - this.linkLabelTsunDbText.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelTsunDbText_LinkClicked); - // - // DialogTsunDb - // - this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(342, 89); - this.Controls.Add(this.linkLabelTsunDbText); - this.Controls.Add(this.labelTsunDbText2); - this.Controls.Add(this.labelTsunDbText); - this.Controls.Add(this.buttonDisable); - this.Controls.Add(this.buttonEnable); - this.Name = "DialogTsunDb"; - this.Text = "Enabling TsunDb data submission"; - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Button buttonEnable; - private System.Windows.Forms.Button buttonDisable; - private System.Windows.Forms.Label labelTsunDbText; - private System.Windows.Forms.Label labelTsunDbText2; - private System.Windows.Forms.LinkLabel linkLabelTsunDbText; - } -} \ No newline at end of file diff --git a/ElectronicObserver/Window/Dialog/DialogTsunDb.cs b/ElectronicObserver/Window/Dialog/DialogTsunDb.cs deleted file mode 100644 index 1d86289bf..000000000 --- a/ElectronicObserver/Window/Dialog/DialogTsunDb.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Diagnostics; -using System.Windows.Forms; -using ElectronicObserver.Utility; - -namespace ElectronicObserver.Window.Dialog; - -public partial class DialogTsunDb : Form -{ - public DialogTsunDb() - { - InitializeComponent(); - } - - #region Events - private void linkLabelTsunDbText_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - Process.Start(new ProcessStartInfo("https://github.com/Jebzou/ElectronicObserver/wiki/Privacy-policy") { UseShellExecute = true }); - } - #endregion - - private void buttonEnable_Click(object sender, EventArgs e) - { - Configuration.Config.Control.SubmitDataToTsunDb = true; - this.DialogResult = DialogResult.Yes; - this.Close(); - } - - private void buttonDisable_Click(object sender, EventArgs e) - { - Configuration.Config.Control.SubmitDataToTsunDb = false; - this.DialogResult = DialogResult.No; - this.Close(); - } -} diff --git a/ElectronicObserver/Window/Settings/Behavior/ConfigurationBehaviorTranslationViewModel.cs b/ElectronicObserver/Window/Settings/Behavior/ConfigurationBehaviorTranslationViewModel.cs index a384ee3e5..9b36cda54 100644 --- a/ElectronicObserver/Window/Settings/Behavior/ConfigurationBehaviorTranslationViewModel.cs +++ b/ElectronicObserver/Window/Settings/Behavior/ConfigurationBehaviorTranslationViewModel.cs @@ -33,7 +33,6 @@ public class ConfigurationBehaviorTranslationViewModel : TranslationBaseViewMode public string Control_DiscordRPCShowFCM => ConfigurationResources.Control_DiscordRPCShowFCM; public string Control_DiscordRPCShowFCMToolTip => ConfigurationResources.Control_DiscordRPCShowFCMToolTip; public string CheckBoxUseSecretaryIconForRPC => ConfigurationResources.checkBoxUseSecretaryIconForRPC; - public string CheckBoxUseSecretaryIconForRPCToolTip => ConfigurationResources.checkBoxUseSecretaryIconForRPCToolTip; public string DiscordRPCMessage => ConfigurationResources.DiscordRPCMessage; public string Control_DiscordRPCMessageToolTip => ConfigurationResources.Control_DiscordRPCMessageToolTip; @@ -44,6 +43,4 @@ public class ConfigurationBehaviorTranslationViewModel : TranslationBaseViewMode public string TranslationURL => ConfigurationResources.TranslationURL; public string Control_translationURLToolTip => ConfigurationResources.Control_translationURLToolTip; public string Control_ForceUpdate => ConfigurationResources.Control_ForceUpdate; - - public string Control_EnableTsunDbSubmission => ConfigurationResources.Control_EnableTsunDbSubmission; } diff --git a/ElectronicObserver/Window/Settings/Behavior/ConfigurationBehaviorUserControl.xaml b/ElectronicObserver/Window/Settings/Behavior/ConfigurationBehaviorUserControl.xaml index f1e4c3652..1ef3e7065 100644 --- a/ElectronicObserver/Window/Settings/Behavior/ConfigurationBehaviorUserControl.xaml +++ b/ElectronicObserver/Window/Settings/Behavior/ConfigurationBehaviorUserControl.xaml @@ -224,11 +224,7 @@ ToolTip="{Binding Translation.Control_DiscordRPCShowFCMToolTip}" /> - + @@ -288,7 +284,5 @@ Content="{Binding Translation.Control_ForceUpdate}" /> - - diff --git a/ElectronicObserver/Window/Settings/Behavior/ConfigurationBehaviorViewModel.cs b/ElectronicObserver/Window/Settings/Behavior/ConfigurationBehaviorViewModel.cs index d54ce8825..06c4bf618 100644 --- a/ElectronicObserver/Window/Settings/Behavior/ConfigurationBehaviorViewModel.cs +++ b/ElectronicObserver/Window/Settings/Behavior/ConfigurationBehaviorViewModel.cs @@ -3,8 +3,6 @@ using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Input; using ElectronicObserver.Utility; -using ElectronicObserver.ViewModels; -using ElectronicObserver.Window.Dialog; using ElectronicObserverTypes; namespace ElectronicObserver.Window.Settings.Behavior; @@ -39,30 +37,12 @@ public partial class ConfigurationBehaviorViewModel : ConfigurationViewModelBase public bool UseFlagshipIconForRPC { get; set; } - public bool? SubmitDataToTsunDb { get; set; } - public ConfigurationBehaviorViewModel(Configuration.ConfigurationData.ConfigControl config) { Translation = Ioc.Default.GetRequiredService(); Config = config; Load(config); - - PropertyChanged += (sender, args) => - { - if (args.PropertyName is not nameof(SubmitDataToTsunDb)) return; - if (SubmitDataToTsunDb is false) return; - - // --- ask for confirmation - DialogTsunDb dialogTsunDb = new(); - dialogTsunDb.FormClosed += (sender, e) => - { - if (sender is not DialogTsunDb dialog) return; - - SubmitDataToTsunDb = dialog.DialogResult == System.Windows.Forms.DialogResult.Yes; - }; - dialogTsunDb.ShowDialog(App.Current!.MainWindow!); - }; } private void Load(Configuration.ConfigurationData.ConfigControl config) @@ -79,7 +59,6 @@ private void Load(Configuration.ConfigurationData.ConfigControl config) DiscordRPCApplicationId = config.DiscordRPCApplicationId; UpdateRepoURL = config.UpdateRepoURL; UseFlagshipIconForRPC = config.UseFlagshipIconForRPC; - SubmitDataToTsunDb = config.SubmitDataToTsunDb; } public override void Save() @@ -96,7 +75,6 @@ public override void Save() Config.DiscordRPCApplicationId = DiscordRPCApplicationId; Config.UpdateRepoURL = UpdateRepoURL; Config.UseFlagshipIconForRPC = UseFlagshipIconForRPC; - Config.SubmitDataToTsunDb = SubmitDataToTsunDb; } [RelayCommand] diff --git a/ElectronicObserver/Window/Settings/DataSubmission/ConfigurationDataSubmissionTranslationViewModel.cs b/ElectronicObserver/Window/Settings/DataSubmission/ConfigurationDataSubmissionTranslationViewModel.cs index f9efaec2d..a846915bf 100644 --- a/ElectronicObserver/Window/Settings/DataSubmission/ConfigurationDataSubmissionTranslationViewModel.cs +++ b/ElectronicObserver/Window/Settings/DataSubmission/ConfigurationDataSubmissionTranslationViewModel.cs @@ -4,5 +4,14 @@ namespace ElectronicObserver.Window.Settings.DataSubmission; public class ConfigurationDataSubmissionTranslationViewModel : TranslationBaseViewModel { - + public string BonodereIntegration => ConfigurationResources.DataSubmission_BonodereIntegration; + public string DataSubmissionFAQ => ConfigurationResources.DataSubmission_DataSubmissionFAQ; + public string LoggedInAs => ConfigurationResources.DataSubmission_LoggedInAs; + public string Login => ConfigurationResources.DataSubmission_Login; + public string Logout => ConfigurationResources.DataSubmission_Logout; + public string Password => ConfigurationResources.DataSubmission_Password; + public string Username => ConfigurationResources.DataSubmission_Username; + + public string EnableTsunDbSubmission => ConfigurationResources.Control_EnableTsunDbSubmission; + public string PrivacyPolicy => ConfigurationResources.DataSubmission_PrivacyPolicy; } diff --git a/ElectronicObserver/Window/Settings/DataSubmission/ConfigurationDataSubmissionUserControl.xaml b/ElectronicObserver/Window/Settings/DataSubmission/ConfigurationDataSubmissionUserControl.xaml index 4dd17dc59..f093e9cc2 100644 --- a/ElectronicObserver/Window/Settings/DataSubmission/ConfigurationDataSubmissionUserControl.xaml +++ b/ElectronicObserver/Window/Settings/DataSubmission/ConfigurationDataSubmissionUserControl.xaml @@ -10,7 +10,107 @@ d:DesignWidth="800" mc:Ignorable="d" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +