Co-authored-by: defnotken <itsdefnotken@gmail.com> Co-authored-by: cake <admin@cakeandbanana.nl> Reviewed-on: #88 Reviewed-by: cake <cake@noreply.git.lightless-sync.org> Co-authored-by: defnotken <defnotken@noreply.git.lightless-sync.org> Co-committed-by: defnotken <defnotken@noreply.git.lightless-sync.org>
226 lines
6.5 KiB
C#
226 lines
6.5 KiB
C#
using System.Collections.ObjectModel;
|
|
using LightlessSync.API.Dto.Group;
|
|
using LightlessSync.PlayerData.Factories;
|
|
using LightlessSync.PlayerData.Pairs;
|
|
using LightlessSync.Services.Mediator;
|
|
using LightlessSync.UI.Models;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace LightlessSync.UI.Services;
|
|
|
|
public sealed class PairUiService : DisposableMediatorSubscriberBase
|
|
{
|
|
private readonly PairLedger _pairLedger;
|
|
private readonly PairFactory _pairFactory;
|
|
private readonly PairManager _pairManager;
|
|
|
|
private readonly object _snapshotGate = new();
|
|
private PairUiSnapshot _snapshot = PairUiSnapshot.Empty;
|
|
private Pair? _lastAddedPair;
|
|
private bool _needsRefresh = true;
|
|
|
|
public PairUiService(
|
|
ILogger<PairUiService> logger,
|
|
LightlessMediator mediator,
|
|
PairLedger pairLedger,
|
|
PairFactory pairFactory,
|
|
PairManager pairManager) : base(logger, mediator)
|
|
{
|
|
_pairLedger = pairLedger;
|
|
_pairFactory = pairFactory;
|
|
_pairManager = pairManager;
|
|
|
|
Mediator.Subscribe<PairDataChangedMessage>(this, _ => MarkDirty());
|
|
Mediator.Subscribe<GroupCollectionChangedMessage>(this, _ => MarkDirty());
|
|
Mediator.Subscribe<VisibilityChange>(this, _ => MarkDirty());
|
|
|
|
EnsureSnapshot();
|
|
}
|
|
|
|
public PairUiSnapshot GetSnapshot()
|
|
{
|
|
EnsureSnapshot();
|
|
lock (_snapshotGate)
|
|
{
|
|
return _snapshot;
|
|
}
|
|
}
|
|
|
|
public Pair? GetLastAddedPair()
|
|
{
|
|
EnsureSnapshot();
|
|
lock (_snapshotGate)
|
|
{
|
|
return _lastAddedPair;
|
|
}
|
|
}
|
|
|
|
public void ClearLastAddedPair()
|
|
{
|
|
_pairManager.ClearLastAddedUser();
|
|
lock (_snapshotGate)
|
|
{
|
|
_lastAddedPair = null;
|
|
}
|
|
}
|
|
|
|
private void MarkDirty()
|
|
{
|
|
lock (_snapshotGate)
|
|
{
|
|
_needsRefresh = true;
|
|
}
|
|
}
|
|
|
|
private void EnsureSnapshot()
|
|
{
|
|
bool shouldBuild;
|
|
lock (_snapshotGate)
|
|
{
|
|
shouldBuild = _needsRefresh;
|
|
if (shouldBuild)
|
|
{
|
|
_needsRefresh = false;
|
|
}
|
|
}
|
|
|
|
if (!shouldBuild)
|
|
{
|
|
return;
|
|
}
|
|
|
|
PairUiSnapshot snapshot;
|
|
Pair? lastAddedPair;
|
|
try
|
|
{
|
|
(snapshot, lastAddedPair) = BuildSnapshot();
|
|
}
|
|
catch
|
|
{
|
|
lock (_snapshotGate)
|
|
{
|
|
_needsRefresh = true;
|
|
}
|
|
|
|
throw;
|
|
}
|
|
|
|
lock (_snapshotGate)
|
|
{
|
|
_snapshot = snapshot;
|
|
_lastAddedPair = lastAddedPair;
|
|
}
|
|
|
|
Mediator.Publish(new PairUiUpdatedMessage(snapshot));
|
|
}
|
|
|
|
private (PairUiSnapshot Snapshot, Pair? LastAddedPair) BuildSnapshot()
|
|
{
|
|
var entries = _pairLedger.GetAllEntries();
|
|
var pairByUid = new Dictionary<string, Pair>(StringComparer.Ordinal);
|
|
|
|
var directPairsList = new List<Pair>();
|
|
var groupPairsTemp = new Dictionary<GroupFullInfoDto, List<Pair>>();
|
|
var pairsWithGroupsTemp = new Dictionary<Pair, List<GroupFullInfoDto>>();
|
|
|
|
foreach (var entry in entries)
|
|
{
|
|
var pair = _pairFactory.Create(entry);
|
|
if (pair is null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pairByUid[entry.Ident.UserId] = pair;
|
|
|
|
if (entry.IsDirectlyPaired)
|
|
{
|
|
directPairsList.Add(pair);
|
|
}
|
|
|
|
var uniqueGroups = new HashSet<string>(StringComparer.Ordinal);
|
|
var groupList = new List<GroupFullInfoDto>();
|
|
foreach (var group in entry.Groups)
|
|
{
|
|
if (!uniqueGroups.Add(group.Group.GID))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!groupPairsTemp.TryGetValue(group, out var members))
|
|
{
|
|
members = new List<Pair>();
|
|
groupPairsTemp[group] = members;
|
|
}
|
|
|
|
members.Add(pair);
|
|
groupList.Add(group);
|
|
}
|
|
|
|
pairsWithGroupsTemp[pair] = groupList;
|
|
}
|
|
|
|
var allGroupsList = _pairLedger.GetAllSyncshells()
|
|
.Values
|
|
.Select(s => s.GroupFullInfo)
|
|
.ToList();
|
|
|
|
foreach (var group in allGroupsList)
|
|
{
|
|
if (!groupPairsTemp.ContainsKey(group))
|
|
{
|
|
groupPairsTemp[group] = new List<Pair>();
|
|
}
|
|
}
|
|
|
|
var directPairs = new ReadOnlyCollection<Pair>(directPairsList);
|
|
|
|
var groupPairsFinal = new Dictionary<GroupFullInfoDto, IReadOnlyList<Pair>>();
|
|
foreach (var (group, members) in groupPairsTemp)
|
|
{
|
|
groupPairsFinal[group] = new ReadOnlyCollection<Pair>(members);
|
|
}
|
|
|
|
var pairsWithGroupsFinal = new Dictionary<Pair, IReadOnlyList<GroupFullInfoDto>>();
|
|
foreach (var (pair, groups) in pairsWithGroupsTemp)
|
|
{
|
|
pairsWithGroupsFinal[pair] = new ReadOnlyCollection<GroupFullInfoDto>(groups);
|
|
}
|
|
|
|
var groupsReadOnly = new ReadOnlyCollection<GroupFullInfoDto>(allGroupsList);
|
|
var pairsByUidReadOnly = new ReadOnlyDictionary<string, Pair>(pairByUid);
|
|
var groupsByGidReadOnly = new ReadOnlyDictionary<string, GroupFullInfoDto>(allGroupsList.ToDictionary(g => g.Group.GID, g => g, StringComparer.Ordinal));
|
|
|
|
Pair? lastAddedPair = null;
|
|
var lastAdded = _pairManager.GetLastAddedUser();
|
|
if (lastAdded is not null)
|
|
{
|
|
if (!pairByUid.TryGetValue(lastAdded.User.UID, out lastAddedPair))
|
|
{
|
|
var groups = lastAdded.Groups.Keys
|
|
.Select(gid =>
|
|
{
|
|
var result = _pairManager.GetGroup(gid);
|
|
return result.Success ? result.Value.GroupFullInfo : null;
|
|
})
|
|
.Where(g => g is not null)
|
|
.Cast<GroupFullInfoDto>()
|
|
.ToList();
|
|
|
|
var entry = new PairDisplayEntry(new PairUniqueIdentifier(lastAdded.User.UID), lastAdded, groups, null);
|
|
lastAddedPair = _pairFactory.Create(entry);
|
|
}
|
|
}
|
|
|
|
var snapshot = new PairUiSnapshot(
|
|
pairsByUidReadOnly,
|
|
directPairs,
|
|
new ReadOnlyDictionary<GroupFullInfoDto, IReadOnlyList<Pair>>(groupPairsFinal),
|
|
new ReadOnlyDictionary<Pair, IReadOnlyList<GroupFullInfoDto>>(pairsWithGroupsFinal),
|
|
groupsByGidReadOnly,
|
|
groupsReadOnly);
|
|
|
|
return (snapshot, lastAddedPair);
|
|
}
|
|
}
|