using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Robust.Shared.ContentPack;
using Robust.Shared.IoC;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Utility;
#nullable enable
namespace Content.Client.Changelog
{
public sealed class ChangelogManager
{
// If you fork SS14, change this to have the changelog "last seen" date stored separately.
public const string ForkId = "Wizards";
[Dependency] private readonly IResourceManager _resource = default!;
[Dependency] private readonly ISerializationManager _serialization = default!;
public bool NewChangelogEntries { get; private set; }
public int LastReadId { get; private set; }
public int MaxId { get; private set; }
public event Action? NewChangelogEntriesChanged;
///
/// Ran when the user opens ("read") the changelog,
/// stores the new ID to disk and clears .
///
///
/// is NOT cleared
/// since that's used in the changelog menu to show the "since you last read" bar.
///
public void SaveNewReadId()
{
NewChangelogEntries = false;
NewChangelogEntriesChanged?.Invoke();
using var file = _resource.UserData.Create(new ResourcePath($"/changelog_last_seen_{ForkId}"));
using var sw = new StreamWriter(file);
sw.Write(MaxId.ToString());
}
public async void Initialize()
{
// Open changelog purely to compare to the last viewed date.
var changelog = await LoadChangelog();
if (changelog.Count == 0)
{
return;
}
MaxId = changelog.Max(c => c.Id);
var path = new ResourcePath($"/changelog_last_seen_{ForkId}");
if (_resource.UserData.Exists(path))
{
LastReadId = int.Parse(_resource.UserData.ReadAllText(path));
}
NewChangelogEntries = LastReadId < MaxId;
NewChangelogEntriesChanged?.Invoke();
}
public Task> LoadChangelog()
{
return Task.Run(() =>
{
var yamlData = _resource.ContentFileReadYaml(new ResourcePath("/Changelog/Changelog.yml"));
if (yamlData.Documents.Count == 0)
return new List();
var node = (MappingDataNode)yamlData.Documents[0].RootNode.ToDataNode();
return _serialization.ReadValueOrThrow>(node["Entries"]);
});
}
[DataDefinition]
public sealed class ChangelogEntry : ISerializationHooks
{
[DataField("id")]
public int Id { get; private set; }
[field: DataField("author")]
public string Author { get; } = "";
[DataField("time")] private string _time = default!;
public DateTime Time { get; private set; }
[field: DataField("changes")]
public List Changes { get; } = default!;
void ISerializationHooks.AfterDeserialization()
{
Time = DateTime.Parse(_time, null, DateTimeStyles.RoundtripKind);
}
}
[DataDefinition]
public sealed class ChangelogChange : ISerializationHooks
{
[DataField("type")]
public ChangelogLineType Type { get; private set; }
[DataField("message")]
public string Message { get; private set; } = "";
}
public enum ChangelogLineType
{
Add,
Remove,
Fix,
Tweak,
}
}
}