using System.Text; using Avalonia.Media; using ModpackUpdater.Apps.Manager.Api.Model; using ModpackUpdater.Apps.Manager.LangRes; using ModpackUpdater.Apps.Manager.Ui; using ModpackUpdater.Apps.Manager.Ui.Models.MainWindow; using ModpackUpdater.Apps.Manager.Ui.Models.UpdatesCollectorViewMode; using ModpackUpdater.Manager; using OfficeOpenXml; using OfficeOpenXml.Table; using Pilz.UI.AvaloniaUI.Dialogs; namespace ModpackUpdater.Apps.Manager.Features; internal static class SharedFunctions { private static readonly IImage? imageSourceSuccess = AppGlobals.Symbols.GetImageSource(AppSymbols.done); private static readonly IImage? imageSourceWorking = AppGlobals.Symbols.GetImageSource(AppSymbols.hourglass); private static readonly IImage? imageSourceFailed = AppGlobals.Symbols.GetImageSource(AppSymbols.close); public static async Task CheckActionHealthy(IMainApi api, params MainWindowGridRow[] rows) { var rowsCount = rows.Length; var failed = false; var factory = new ModpackFactory(); api.Model.Progress.Start(rowsCount); for (var i = 0; i < rowsCount; i++) { var row = rows[i]; if (row.SourceType == SourceType.DirectLink) continue; row.StateImage = imageSourceWorking; try { var result = await factory.ResolveSourceUrl(row.Action); failed = string.IsNullOrWhiteSpace(result); } catch { // Ignore } if (api.HasClosed) return; row.StateImage = failed ? imageSourceFailed : imageSourceSuccess; api.Model.Progress.Set(i); } api.Model.Progress.Stop(); } public static async Task CollectUpdates(IMainApi api, params InstallAction[] actions) { if (api.Model.CurrentWorkspace?.UpdateInfos is null || api.Model.CurrentTreeNodes is null) return false; // Collect updates var result = await AvaloniaFlyoutBase.Show(new UpdatesCollectorView(api.Model.CurrentWorkspace, actions), api.MainWindow); if (api.HasClosed || result.Result is not ModUpdates resultUpdates) return false; // Collect versions with changes var updates = resultUpdates.List.Where(update => update.Origin.SourceTag != update.AvailableVersions[update.NewVersion].Tag).ToList(); // Path install actions foreach (var update in updates) { var sourceTag = update.AvailableVersions[update.NewVersion].Tag; if (api.Model.CurrentGridRows?.FirstOrDefault(n => n.Action == update.Origin) is { } row) row.SourceTag = sourceTag; else update.Origin.SourceTag = sourceTag; } // Create update actions var updateSet = new UpdateInfo(); foreach (var update in updates) { updateSet.Actions.Add(new() { InheritFrom = update.Origin.Id, }); } api.Model.CurrentWorkspace.UpdateInfos.Updates.Insert(0, updateSet); // Add update to ui api.Model.CurrentTreeNodes[1].Nodes.Insert(0, new ActionSetTreeNode(updateSet)); return true; } public static async Task FindNewDirectLinks(IMainApi api, params MainWindowGridRow[] rows) { var factory = new ModpackFactory(); api.Model.Progress.Start(rows.Length); for (var i = 0; i < rows.Length; i++) { var row = rows[i]; if (row.SourceType == SourceType.DirectLink) continue; row.StateImage = imageSourceWorking; try { row.SourceUrl = await factory.ResolveSourceUrl(row.Action); row.StateImage = imageSourceSuccess; } catch (Exception) { row.StateImage = imageSourceFailed; } if (api.HasClosed) return; api.Model.Progress.Set(i); } api.Model.Progress.Stop(); } public static void ClearDirectLinks(IMainApi api, params MainWindowGridRow[] rows) { api.Model.Progress.Start(rows.Length); for (var i = 0; i < rows.Length; i++) { var row = rows[i]; if (row.SourceType != SourceType.DirectLink) row.SourceUrl = null; row.StateImage = null; api.Model.Progress.Set(i); } api.Model.Progress.Stop(); } public static string GenerateChangelog(InstallInfos installInfos, UpdateInfo updateInfos) { var log = new StringBuilder(); foreach (var action in updateInfos.Actions.OrderBy(n => n.Type)) { // Create copy var copy = new UpdateAction(); ModpackInstaller.DuplicateTo(action, copy); // Resolve inherit if (!string.IsNullOrWhiteSpace(copy.InheritFrom)) ModpackInstaller.ResolveInherit(copy, installInfos); if (string.IsNullOrWhiteSpace(copy.Name) || copy.Type != UpdateActionType.Update) continue; // Append bullet log.Append('-'); // Append action indicator log.Append(' '); log.Append("⚒️"); // Append name log.Append(' '); log.Append("**"); log.Append(copy.Name); log.Append("**"); // Append new version if (!string.IsNullOrWhiteSpace(copy.SourceTag)) { log.Append(' '); log.Append('`'); log.Append(copy.SourceTag); log.Append('`'); } // Append new line log.AppendLine(); } return log.ToString().TrimEnd(); } public static string GenerateModlistAsMarkdown(InstallInfos installInfos) { var sb = new StringBuilder(); sb.Append("|" + ActionsListLangRes.Col_Name); sb.Append("|" + ActionsListLangRes.Col_SrcTag); sb.Append("|" + ActionsListLangRes.Col_Side); sb.Append("|" + ActionsListLangRes.Col_SrcType); sb.Append("|" + ActionsListLangRes.Col_SrcOwner); sb.Append("|" + ActionsListLangRes.Col_SrcName); sb.AppendLine("|"); sb.AppendLine("|---|---|---|---|---|---|"); // Rows foreach (var action in installInfos.Actions.OrderBy(n => n.Name)) { if (action.IsExtra || action.IsZip || string.IsNullOrWhiteSpace(action.Id) || !action.Id.StartsWith("mod:")) continue; if (string.IsNullOrWhiteSpace(action.Website)) sb.Append($"|{action.Name}"); else sb.Append($"|[{action.Name}]({action.Website})"); if (string.IsNullOrWhiteSpace(action.SourceUrl)) sb.Append($"|{action.SourceTag}"); else sb.Append($"|[{action.SourceTag}]({action.GetSourceUrl(installInfos.Version)})"); sb.Append($"|{action.Side.ToString()}"); sb.Append($"|{action.SourceType}"); sb.Append($"|{action.SourceOwner}"); sb.Append($"|{action.SourceName}"); sb.AppendLine("|"); } return sb.ToString().TrimEnd(); } public static ExcelPackage GenerateModlistAsExcel(InstallInfos installInfos) { var pkg = new ExcelPackage(); var ws = pkg.Workbook.Worksheets.Add(string.Format(GeneralLangRes.ModlistForVersionX, installInfos.Version)); var cr = 1; var cc = 1; // Header ws.Cells[cr, cc++].Value = ActionsListLangRes.Col_Name; ws.Cells[cr, cc++].Value = ActionsListLangRes.Col_SrcTag; ws.Cells[cr, cc++].Value = ActionsListLangRes.Col_Side; ws.Cells[cr, cc++].Value = ActionsListLangRes.Col_SrcType; ws.Cells[cr, cc++].Value = ActionsListLangRes.Col_SrcOwner; ws.Cells[cr, cc++].Value = ActionsListLangRes.Col_SrcName; cr += 1; cc = 1; // Rows foreach (var action in installInfos.Actions.OrderBy(n => n.Name)) { if (action.IsExtra || action.IsZip || string.IsNullOrWhiteSpace(action.Id) || !action.Id.StartsWith("mod:")) continue; var cellName = ws.Cells[cr, cc++]; cellName.Value = action.Name; if (!string.IsNullOrWhiteSpace(action.Website)) cellName.SetHyperlink(new Uri(action.Website)); var cellTag = ws.Cells[cr, cc++]; cellTag.Value = string.IsNullOrWhiteSpace(action.SourceTag) ? "direct link" : action.SourceTag; if (!string.IsNullOrWhiteSpace(action.SourceUrl)) cellTag.SetHyperlink(new Uri(action.GetSourceUrl(installInfos.Version))); ws.Cells[cr, cc++].Value = action.Side.ToString(); ws.Cells[cr, cc++].Value = action.SourceType; ws.Cells[cr, cc++].Value = action.SourceOwner; ws.Cells[cr, cc++].Value = action.SourceName; cr += 1; cc = 1; } // Styling cc = 1; ws.Column(cc++).Width = 30; ws.Column(cc++).Width = 20; ws.Column(cc++).Width = 10; ws.Column(cc++).Width = 20; ws.Column(cc++).Width = 20; ws.Column(cc++).Width = 30; var tableDef = ws.Tables.Add(ws.Cells[1, 1, cr - 1, cc - 1], "Table"); tableDef.TableStyle = TableStyles.Medium16; tableDef.ShowHeader = true; return pkg; } }