using System.Linq; using Content.Client.Resources; using Content.Client.Stylesheets; using Content.Client.UserInterface.Systems.EscapeMenu; using Content.Shared.Administration; using JetBrains.Annotations; using Robust.Client.AutoGenerated; using Robust.Client.ResourceManagement; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Console; using Robust.Shared.Utility; using static Content.Client.Changelog.ChangelogManager; using static Robust.Client.UserInterface.Controls.BoxContainer; namespace Content.Client.Changelog { [GenerateTypedNameReferences] public sealed partial class ChangelogWindow : BaseWindow { [Dependency] private readonly ChangelogManager _changelog = default!; [Dependency] private readonly IResourceCache _resourceCache = default!; public ChangelogWindow() { IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); Stylesheet = IoCManager.Resolve().SheetSpace; CloseButton.OnPressed += _ => Close(); } protected override void Opened() { base.Opened(); _changelog.SaveNewReadId(); PopulateChangelog(); } private async void PopulateChangelog() { // Changelog is not kept in memory so load it again. var changelog = await _changelog.LoadChangelog(); var byDay = changelog .GroupBy(e => e.Time.ToLocalTime().Date) .OrderByDescending(c => c.Key); var hasRead = _changelog.MaxId <= _changelog.LastReadId; foreach (var dayEntries in byDay) { var day = dayEntries.Key; var groupedEntries = dayEntries .GroupBy(c => (c.Author, Read: c.Id <= _changelog.LastReadId)) .OrderBy(c => c.Key.Read) .ThenBy(c => c.Key.Author); string dayNice; var today = DateTime.Today; if (day == today) dayNice = Loc.GetString("changelog-today"); else if (day == today.AddDays(-1)) dayNice = Loc.GetString("changelog-yesterday"); else dayNice = day.ToShortDateString(); ChangelogBody.AddChild(new Label { Text = dayNice, StyleClasses = {"LabelHeading"}, Margin = new Thickness(4, 6, 0, 0) }); var first = true; foreach (var groupedEntry in groupedEntries) { var (author, read) = groupedEntry.Key; if (!first) { ChangelogBody.AddChild(new Control {Margin = new Thickness(4)}); } if (read && !hasRead) { hasRead = true; var upArrow = _resourceCache.GetTexture("/Textures/Interface/Changelog/up_arrow.svg.192dpi.png"); var readDivider = new BoxContainer { Orientation = LayoutOrientation.Vertical }; var hBox = new BoxContainer { Orientation = LayoutOrientation.Horizontal, HorizontalAlignment = HAlignment.Center, Children = { new TextureRect { Texture = upArrow, ModulateSelfOverride = Color.FromHex("#888"), TextureScale = (0.5f, 0.5f), Margin = new Thickness(4, 3), VerticalAlignment = VAlignment.Bottom }, new Label { Align = Label.AlignMode.Center, Text = Loc.GetString("changelog-new-changes"), FontColorOverride = Color.FromHex("#888"), }, new TextureRect { Texture = upArrow, ModulateSelfOverride = Color.FromHex("#888"), TextureScale = (0.5f, 0.5f), Margin = new Thickness(4, 3), VerticalAlignment = VAlignment.Bottom } } }; readDivider.AddChild(hBox); readDivider.AddChild(new PanelContainer {StyleClasses = {"LowDivider"}}); ChangelogBody.AddChild(readDivider); if (first) readDivider.SetPositionInParent(ChangelogBody.ChildCount - 2); } first = false; var authorLabel = new RichTextLabel { Margin = new Thickness(6, 0, 0, 0), }; authorLabel.SetMessage( FormattedMessage.FromMarkup(Loc.GetString("changelog-author-changed", ("author", author)))); ChangelogBody.AddChild(authorLabel); foreach (var change in groupedEntry.SelectMany(c => c.Changes)) { var text = new RichTextLabel(); text.SetMessage(FormattedMessage.FromMarkup(change.Message)); ChangelogBody.AddChild(new BoxContainer { Orientation = LayoutOrientation.Horizontal, Margin = new Thickness(14, 1, 10, 2), Children = { GetIcon(change.Type), text } }); } } } var version = typeof(ChangelogWindow).Assembly.GetName().Version ?? new Version(1, 0); VersionLabel.Text = Loc.GetString("changelog-version-tag", ("version", version.ToString())); } private TextureRect GetIcon(ChangelogLineType type) { var (file, color) = type switch { ChangelogLineType.Add => ("plus.svg.192dpi.png", "#6ED18D"), ChangelogLineType.Remove => ("minus.svg.192dpi.png", "#D16E6E"), ChangelogLineType.Fix => ("bug.svg.192dpi.png", "#D1BA6E"), ChangelogLineType.Tweak => ("wrench.svg.192dpi.png", "#6E96D1"), _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) }; return new TextureRect { Texture = _resourceCache.GetTexture(new ResourcePath($"/Textures/Interface/Changelog/{file}")), VerticalAlignment = VAlignment.Top, TextureScale = (0.5f, 0.5f), Margin = new Thickness(2, 4, 6, 2), ModulateSelfOverride = Color.FromHex(color) }; } protected override DragMode GetDragModeFor(Vector2 relativeMousePos) { return DragMode.Move; } } [UsedImplicitly, AnyCommand] public sealed class ChangelogCommand : IConsoleCommand { public string Command => "changelog"; public string Description => "Opens the changelog"; public string Help => "Usage: changelog"; public void Execute(IConsoleShell shell, string argStr, string[] args) { IoCManager.Resolve().GetUIController().ToggleWindow(); } } }