diff --git a/YMCL.Main/App.axaml b/YMCL.Main/App.axaml index 0b2cf98..e5a62de 100644 --- a/YMCL.Main/App.axaml +++ b/YMCL.Main/App.axaml @@ -29,5 +29,6 @@ + \ No newline at end of file diff --git a/YMCL.Main/Public/Classes/Sundry.cs b/YMCL.Main/Public/Classes/Sundry.cs index e8c9180..949d4a5 100644 --- a/YMCL.Main/Public/Classes/Sundry.cs +++ b/YMCL.Main/Public/Classes/Sundry.cs @@ -12,6 +12,13 @@ namespace YMCL.Main.Public.Classes; +public class AggregateSearch() +{ + public string Tag { get; set; } + public string Type { get; set; } + public string Summary { get; set; } + public string Text { get; set; } +} public class FolderInfo() { public string Name { get; set; } @@ -296,3 +303,65 @@ public class UrlImageDataListEntry() public string Url { get; set; } public Bitmap Bitmap { get; set; } } + +public class MojangJavaNews() +{ + public class Image + { + /// + /// + /// + public string url { get; set; } + /// + /// + /// + public string title { get; set; } + } + + public class EntriesItem + { + public string BitmapBase64 { get; set; } + + /// + /// + /// + public string title { get; set; } + /// + /// + /// + public string type { get; set; } + /// + /// + /// + public string version { get; set; } + /// + /// + /// + public Image image { get; set; } + /// + /// + /// + public string body { get; set; } + /// + /// + /// + public string id { get; set; } + /// + /// + /// + public string contentPath { get; set; } + } + + public class Root + { + /// + /// + /// + public int version { get; set; } + /// + /// + /// + public List entries { get; set; } + } + +} \ No newline at end of file diff --git a/YMCL.Main/Public/Const.cs b/YMCL.Main/Public/Const.cs index 6e66a74..3598c12 100644 --- a/YMCL.Main/Public/Const.cs +++ b/YMCL.Main/Public/Const.cs @@ -34,6 +34,7 @@ public abstract class String Path.Combine(UserDataRootPath, "YMCL.MinecraftFolder.DaiYu"); public static string JavaDataPath { get; } = Path.Combine(UserDataRootPath, "YMCL.Java.DaiYu"); + public static string JavaNewsDataPath { get; } = Path.Combine(UserDataRootPath, "YMCL.JavaNews.DaiYu"); public static string AppPathDataPath { get; } = Path.Combine(UserDataRootPath, "YMCL.AppPath.DaiYu"); public static string PlayerDataPath { get; } = Path.Combine(UserDataRootPath, "YMCL.Player.DaiYu"); diff --git a/YMCL.Main/Public/Controls/JavaNewsEntry/JavaNewsEntry.axaml b/YMCL.Main/Public/Controls/JavaNewsEntry/JavaNewsEntry.axaml new file mode 100644 index 0000000..f4b5553 --- /dev/null +++ b/YMCL.Main/Public/Controls/JavaNewsEntry/JavaNewsEntry.axaml @@ -0,0 +1,29 @@ + + + + + + + + + + diff --git a/YMCL.Main/Public/Controls/JavaNewsEntry/JavaNewsEntry.axaml.cs b/YMCL.Main/Public/Controls/JavaNewsEntry/JavaNewsEntry.axaml.cs new file mode 100644 index 0000000..cbe1784 --- /dev/null +++ b/YMCL.Main/Public/Controls/JavaNewsEntry/JavaNewsEntry.axaml.cs @@ -0,0 +1,94 @@ +using System; +using System.Diagnostics; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Documents; +using Avalonia.Markup.Xaml; +using Avalonia.Media; +using HtmlAgilityPack; + +namespace YMCL.Main.Public.Controls; + +public partial class JavaNewsEntry : UserControl +{ + public JavaNewsEntry(string img, string text) + { + InitializeComponent(); + ImageC.Source = "https://launchercontent.mojang.com" + img; + + var htmlDoc = new HtmlDocument(); + htmlDoc.LoadHtml(text); + + var wrapPanel = WrapPanelC; + + // 解析并添加段落 + var paragraphs = htmlDoc.DocumentNode.SelectNodes("//p"); + if (paragraphs != null) + { + foreach (var paragraph in paragraphs) + { + var textBlock = new TextBlock + { + Text = paragraph.InnerText, FontFamily = (FontFamily)Application.Current.Resources["Font"]!, + TextWrapping = TextWrapping.Wrap + }; + wrapPanel.Children.Add(textBlock); + } + } + + // 解析并添加标题 + var h1 = htmlDoc.DocumentNode.SelectSingleNode("//h1"); + if (h1 != null) + { + var textBlock = new TextBlock + { + Text = h1.InnerText, FontWeight = FontWeight.Bold, + FontFamily = (FontFamily)Application.Current.Resources["Font"]!, + TextWrapping = TextWrapping.Wrap + }; + wrapPanel.Children.Add(textBlock); + } + + // 解析并添加实验特性 + var h2 = htmlDoc.DocumentNode.SelectSingleNode("//h2"); + if (h2 != null) + { + var textBlock = new TextBlock + { + Text = h2.InnerText, FontWeight = FontWeight.Bold, + FontFamily = (FontFamily)Application.Current.Resources["Font"]!, + TextWrapping = TextWrapping.Wrap + }; + wrapPanel.Children.Add(textBlock); + } + + // 解析并添加列表项 + var listItems = htmlDoc.DocumentNode.SelectNodes("//ul/li"); + if (listItems != null) + { + foreach (var item in listItems) + { + var textBlock = new TextBlock + { Text = item.InnerText, FontFamily = (FontFamily)Application.Current.Resources["Font"]!, + TextWrapping = TextWrapping.Wrap }; + wrapPanel.Children.Add(textBlock); + wrapPanel.Children.Add(new TextBlock { Text = "\n" }); // 添加换行 + } + } + + // 解析并添加超链接 + var links = htmlDoc.DocumentNode.SelectNodes("//a[@href]"); + if (links != null) + { + foreach (var link in links) + { + var hyperlink = new HyperlinkButton() + { + Content = link.InnerText, FontFamily = (FontFamily)Application.Current.Resources["Font"]!, + NavigateUri = new Uri(link.Attributes["href"].Value) + }; + wrapPanel.Children.Add(hyperlink); + } + } + } +} \ No newline at end of file diff --git a/YMCL.Main/Public/Enum.cs b/YMCL.Main/Public/Enum.cs index 0527c83..87d228c 100644 --- a/YMCL.Main/Public/Enum.cs +++ b/YMCL.Main/Public/Enum.cs @@ -73,7 +73,8 @@ public enum CustomHomePageWay { None, Local, - Network + Network, + Presetting_JavaNews } public enum DaiYuLoaderType diff --git a/YMCL.Main/Public/Langs/MainLang.Designer.cs b/YMCL.Main/Public/Langs/MainLang.Designer.cs index 5c6643f..3917d9a 100644 --- a/YMCL.Main/Public/Langs/MainLang.Designer.cs +++ b/YMCL.Main/Public/Langs/MainLang.Designer.cs @@ -194,6 +194,15 @@ public static string AfterLaunchMinimizeAndShowWhenGameExit { } } + /// + /// Looks up a localized string similar to 杈撳叆鍏抽敭璇嶄互鍦╕MCL涓悳绱 . + /// + public static string AggregateSearchTip { + get { + return ResourceManager.GetString("AggregateSearchTip", resourceCulture); + } + } + /// /// Looks up a localized string similar to 灞呬腑瀵归綈. /// @@ -509,6 +518,15 @@ public static string CustomHomePageSourceCodeError { } } + /// + /// Looks up a localized string similar to 棰勮-Java鏂伴椈. + /// + public static string CustomHomePageWay_Presetting_JavaNews { + get { + return ResourceManager.GetString("CustomHomePageWay_Presetting_JavaNews", resourceCulture); + } + } + /// /// Looks up a localized string similar to 鑷畾涔夋洿鏂癠rl. /// @@ -1565,6 +1583,15 @@ public static string NeedToSelectMinecraftFolder { } } + /// + /// Looks up a localized string similar to 缃戠粶婧. + /// + public static string NetworkSource { + get { + return ResourceManager.GetString("NetworkSource", resourceCulture); + } + } + /// /// Looks up a localized string similar to 鏃犻檮鍔犲畨瑁. /// @@ -1610,6 +1637,15 @@ public static string NoCrashInfo { } } + /// + /// Looks up a localized string similar to 鐜颁笉鏀寔. + /// + public static string NoSupportNow { + get { + return ResourceManager.GetString("NoSupportNow", resourceCulture); + } + } + /// /// Looks up a localized string similar to 鍏抽棴. /// diff --git a/YMCL.Main/Public/Langs/MainLang.resx b/YMCL.Main/Public/Langs/MainLang.resx index 8074f8c..6849a3a 100644 --- a/YMCL.Main/Public/Langs/MainLang.resx +++ b/YMCL.Main/Public/Langs/MainLang.resx @@ -924,4 +924,16 @@ win10 浠ヤ笅绯荤粺(涓嶅寘鎷10)涓嶆敮鎸佽嚜鍔ㄦ洿鏂 鎵撳紑娴忚鍣 + + 棰勮-Java鏂伴椈 + + + 缃戠粶婧 + + + 鐜颁笉鏀寔 + + + 杈撳叆鍏抽敭璇嶄互鍦╕MCL涓悳绱 + \ No newline at end of file diff --git a/YMCL.Main/Public/Method.cs b/YMCL.Main/Public/Method.cs index 0fbf05e..e7d8b00 100644 --- a/YMCL.Main/Public/Method.cs +++ b/YMCL.Main/Public/Method.cs @@ -333,7 +333,7 @@ public static void RestartApp() "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36 Edg/91.0.864.54"); var githubApiJson = JArray.Parse(await httpClient.GetStringAsync(Const.String.GithubUpdateApiUrl)); var apiVersion = (string)githubApiJson[0]["name"]!; - return (true, apiVersion != version, apiVersion, (string)githubApiJson[0]["html_url"]!); + return (true, apiVersion != version, apiVersion, (string)githubApiJson[0]["html_url"]!); } catch { @@ -1612,7 +1612,9 @@ public static async Task LaunchClientUsingMinecraftLaunchAsync(string p_id } Launcher launcher = new(gameResolver, config); - + bool _showed = false; + string _gameMsg = String.Empty; + bool _firstOut = true; await Task.Run(async () => { try @@ -1647,6 +1649,12 @@ await Dispatcher.UIThread.InvokeAsync(async () => var crashAnalyzer = new GameCrashAnalyzer(gameEntry, l_enableIndependencyCore); var reports = crashAnalyzer.AnalysisLogs(); var msg = string.Empty; + if (_firstOut == true && !setting.ShowGameOutput) + { + task.UpdateTextProgress(_gameMsg, false); + _firstOut = false; + } + try { if (reports == null || reports.Count() == 0) @@ -1663,26 +1671,32 @@ await Dispatcher.UIThread.InvokeAsync(async () => task.UpdateTextProgress(string.Empty, false); task.UpdateTextProgress($"YMCL -----> {MainLang.MineratCrashed}"); task.isFinish = true; - + task.Show(); var dialogResult = await Ui.ShowDialogAsync(MainLang.MineratCrashed, msg, b_primary: MainLang.Ok); task.Destory(); } }); }; + watcher.OutputLogReceived += async (_, args) => { Console.WriteLine(args.Log); - if (setting.ShowGameOutput) - await Dispatcher.UIThread.InvokeAsync(() => - { - task.UpdateTextProgress(args.Original, false); - }); - else - await Dispatcher.UIThread.InvokeAsync(() => + if ((!setting.ShowGameOutput && !_showed)) + { + _gameMsg += args.Log; + } + + if (setting.ShowGameOutput || (!setting.ShowGameOutput && _showed)) + { + if (_firstOut) { - task.entry.UpdateTextProgress(args.Original, false); - }); + task.UpdateTextProgress(_gameMsg, false); + _firstOut = false; + } + + task.UpdateTextProgress(args.Original, false); + } }; await Dispatcher.UIThread.InvokeAsync(() => @@ -1702,6 +1716,11 @@ await Dispatcher.UIThread.InvokeAsync(() => Dispatcher.UIThread.Invoke(() => { + if (!setting.ShowGameOutput) + { + task.Hide(); + } + switch (setting.LauncherVisibility) { case LauncherVisibility.AfterLaunchExitLauncher: diff --git a/YMCL.Main/Views/Initialize/InitializeWindow.axaml.cs b/YMCL.Main/Views/Initialize/InitializeWindow.axaml.cs index dca99fb..aa7b09f 100644 --- a/YMCL.Main/Views/Initialize/InitializeWindow.axaml.cs +++ b/YMCL.Main/Views/Initialize/InitializeWindow.axaml.cs @@ -80,6 +80,9 @@ private void Init() if (!File.Exists(Const.String.PluginDataPath)) File.WriteAllText(Const.String.PluginDataPath, JsonConvert.SerializeObject(new List(), Formatting.Indented)); + if (!File.Exists(Const.String.JavaNewsDataPath)) + File.WriteAllText(Const.String.JavaNewsDataPath, + "{}"); if (!File.Exists(Const.String.PlayerDataPath)) File.WriteAllText(Const.String.PlayerDataPath, JsonConvert.SerializeObject(new List(), Formatting.Indented)); diff --git a/YMCL.Main/Views/Main/MainWindow.axaml.cs b/YMCL.Main/Views/Main/MainWindow.axaml.cs index 410b22c..3e11ba5 100644 --- a/YMCL.Main/Views/Main/MainWindow.axaml.cs +++ b/YMCL.Main/Views/Main/MainWindow.axaml.cs @@ -22,6 +22,7 @@ using Newtonsoft.Json; using YMCL.Main.Public; using YMCL.Main.Public.Classes; +using YMCL.Main.Public.Controls; using YMCL.Main.Public.Controls.WindowTask; using YMCL.Main.Public.Langs; using YMCL.Main.Views.Main.Pages.Download; @@ -224,7 +225,25 @@ public void LoadWindow() Const.Window.main.Show(); Const.Window.initialize.Close(); - if (setting.CustomHomePage == CustomHomePageWay.Local) + _ = FetchJavaNews(); + _ = LoadCustomHomePage(); + + _ = downloadPage.curseForgeFetcherPage.InitModFromCurseForge(); + Method.Ui.SetWindowBackGroundImg(); + } + + private async Task FetchJavaNews() + { + using var client = new HttpClient(); + var json = await client.GetStringAsync("https://launchercontent.mojang.com/javaPatchNotes.json"); + await File.WriteAllTextAsync(Const.String.JavaNewsDataPath, json); + // _ = LoadCustomHomePage(); + } + + private async Task LoadCustomHomePage() + { + if (Const.Data.Setting.CustomHomePage == CustomHomePageWay.Local) + { try { var c = (Control)AvaloniaRuntimeXamlLoader.Load( @@ -235,9 +254,27 @@ public void LoadWindow() { Method.Ui.ShowLongException(MainLang.CustomHomePageSourceCodeError, ex); } - - downloadPage.curseForgeFetcherPage.SearchModFromCurseForge(); - Method.Ui.SetWindowBackGroundImg(); + } + else if (Const.Data.Setting.CustomHomePage == CustomHomePageWay.Presetting_JavaNews) + { + try + { + var viewer = new ScrollViewer(); + var container = new StackPanel() + { + Spacing = 10 + }; + viewer.Content = container; + launchPage.CustomPageRoot.Child = viewer; + var news = JsonConvert.DeserializeObject( + await File.ReadAllTextAsync(Const.String.JavaNewsDataPath)); + news.entries.ForEach(v => + container.Children.Add(new JavaNewsEntry(v.image.url, v.body))); + } + catch (Exception ex) + { + } + } } public async void HandleDrop(object sender, DragEventArgs e) diff --git a/YMCL.Main/Views/Main/Pages/Download/Pages/CurseForge/CurseForgeFetcher.axaml.cs b/YMCL.Main/Views/Main/Pages/Download/Pages/CurseForge/CurseForgeFetcher.axaml.cs index 9555bf4..2f1becd 100644 --- a/YMCL.Main/Views/Main/Pages/Download/Pages/CurseForge/CurseForgeFetcher.axaml.cs +++ b/YMCL.Main/Views/Main/Pages/Download/Pages/CurseForge/CurseForgeFetcher.axaml.cs @@ -82,6 +82,7 @@ async void OpenDetail() SearchConsoleRoot.Opacity = 0; } + Loaded += (_, _) => { Method.Ui.PageLoadAnimation((0, 50, 0, -50), (0, 0, 0, 0), TimeSpan.FromSeconds(0.30), Root, true); @@ -170,7 +171,7 @@ await Task.Run(() => index++; } }); - + ModFileLoading.IsVisible = false; if (shouldReturn) return; List mcVersions = new(); @@ -485,7 +486,7 @@ public async void SearchModFromCurseForge() categoryId: -1, classId: classId); if (ModNameTextBox.Text != keyword) return; - + mods.Data.ForEach(mod => { var entry = new SearchModListViewItemEntry(mod); @@ -518,6 +519,71 @@ public async void SearchModFromCurseForge() } } + public async Task InitModFromCurseForge() + { + await Task.Run(async () => + { + Const.Data.UrlImageDataList.Clear(); + var keyword = ModNameTextBox.Text; + _keyword = keyword; + var gameVersion = ModVersionTextBox.Text; + _gameVersion = gameVersion; + ModLoaderType loaderType; + + if (mapping.TryGetValue((DaiYuLoaderType)LoaderTypeComboBox.SelectedIndex, out var modLoaderType)) + loaderType = modLoaderType; + else + loaderType = ModLoaderType.Any; + + _loaderType = loaderType; + try + { + var classId = GetClassIdFromResultTypeComboBoxSelectedIndex(ResultTypeComboBox.SelectedIndex); + + GenericListResponse mods; + if (loaderType == ModLoaderType.Any) + mods = await cfApiClient.SearchModsAsync(_gameId, gameVersion: gameVersion, + searchFilter: keyword, index: _page * 25, pageSize: 25, categoryId: -1, classId: classId); + else + mods = await cfApiClient.SearchModsAsync(_gameId, gameVersion: gameVersion, + searchFilter: keyword, modLoaderType: loaderType, index: _page * 25, pageSize: 25, + categoryId: -1, classId: classId); + + if (ModNameTextBox.Text != keyword) return; + + mods.Data.ForEach(mod => + { + var entry = new SearchModListViewItemEntry(mod); + entry.StringDownloadCount = Method.Value.ConvertToWanOrYi(mod.DownloadCount); + var localDateTime = mod.DateReleased.DateTime.ToLocalTime(); + var formattedDateTime = localDateTime.ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture); + entry.StringDateTime = formattedDateTime; + entry.ModSource = ModSource.CurseForge; + ModListView.Items.Add(entry); + }); + ModNameTextBox.IsEnabled = true; + ModVersionTextBox.IsEnabled = true; + SearchBtn.IsEnabled = true; + Loading.IsVisible = false; + LoadMoreBtn.IsVisible = true; + if (mods.Data.Count == 0) + { + Method.Ui.Toast(MainLang.SearchNoResult); + LoadMoreBtn.IsVisible = false; + } + } + catch (Exception ex) + { + ModNameTextBox.IsEnabled = true; + ModVersionTextBox.IsEnabled = true; + SearchBtn.IsEnabled = true; + Loading.IsVisible = false; + LoadMoreBtn.IsVisible = false; + Method.Ui.ShowShortException(MainLang.ErrorCallingApi, ex); + } + }); + } + public class VersionComparer : IComparer { public int Compare(string x, string y) diff --git a/YMCL.Main/Views/Main/Pages/Setting/Pages/Personalize/PersonalizeSettingPage.axaml b/YMCL.Main/Views/Main/Pages/Setting/Pages/Personalize/PersonalizeSettingPage.axaml index 11caaa0..2ff42ce 100644 --- a/YMCL.Main/Views/Main/Pages/Setting/Pages/Personalize/PersonalizeSettingPage.axaml +++ b/YMCL.Main/Views/Main/Pages/Setting/Pages/Personalize/PersonalizeSettingPage.axaml @@ -280,6 +280,8 @@ + + diff --git a/YMCL.Main/Views/Main/Pages/Setting/Pages/Personalize/PersonalizeSettingPage.axaml.cs b/YMCL.Main/Views/Main/Pages/Setting/Pages/Personalize/PersonalizeSettingPage.axaml.cs index 2ae4ea9..3843026 100644 --- a/YMCL.Main/Views/Main/Pages/Setting/Pages/Personalize/PersonalizeSettingPage.axaml.cs +++ b/YMCL.Main/Views/Main/Pages/Setting/Pages/Personalize/PersonalizeSettingPage.axaml.cs @@ -58,6 +58,12 @@ private void BindingEvent() CustomHomePageComboBox.SelectionChanged += (s, e) => { var setting = Const.Data.Setting; + if (CustomHomePageComboBox.SelectedIndex == 2) + { + CustomHomePageComboBox.SelectedIndex = 0; + Method.Ui.Toast(MainLang.NoSupportNow); + return; + } EditCustomHomePageBtn.IsVisible = CustomHomePageComboBox.SelectedIndex == 1 ? true : false; if (CustomHomePageComboBox.SelectedIndex != (int)setting.CustomHomePage) { diff --git a/YMCL.Main/YMCL.Main.csproj b/YMCL.Main/YMCL.Main.csproj index f58c45c..2ed45a9 100644 --- a/YMCL.Main/YMCL.Main.csproj +++ b/YMCL.Main/YMCL.Main.csproj @@ -46,16 +46,17 @@ - - - + + + + - - - + + +