2024-08-07 18:48:13 -05:00
|
|
|
|
using LANCommander.Launcher.Data;
|
2024-08-04 17:53:19 -05:00
|
|
|
|
using LANCommander.Launcher.Data.Models;
|
|
|
|
|
|
using LANCommander.Launcher.Models;
|
2024-07-15 18:17:04 -05:00
|
|
|
|
using LANCommander.SDK;
|
2024-09-16 21:00:07 -05:00
|
|
|
|
using LANCommander.SDK.Extensions;
|
2024-05-23 23:41:38 -05:00
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
2024-09-11 00:24:34 -05:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
2024-05-25 15:40:31 -05:00
|
|
|
|
using System.Collections.ObjectModel;
|
2024-05-25 22:21:04 -05:00
|
|
|
|
using System.Diagnostics;
|
2026-01-24 15:32:40 -06:00
|
|
|
|
using LANCommander.SDK.Services;
|
2024-05-20 20:26:15 -05:00
|
|
|
|
|
2024-08-04 17:53:19 -05:00
|
|
|
|
namespace LANCommander.Launcher.Services
|
2024-05-20 20:26:15 -05:00
|
|
|
|
{
|
2025-01-19 00:06:44 -06:00
|
|
|
|
public class LibraryService : BaseDatabaseService<Library>
|
2024-05-20 20:26:15 -05:00
|
|
|
|
{
|
2025-01-20 12:10:30 -06:00
|
|
|
|
private readonly AuthenticationService AuthenticationService;
|
2024-10-26 15:48:47 -05:00
|
|
|
|
private readonly InstallService InstallService;
|
2024-05-29 02:02:40 -05:00
|
|
|
|
private readonly GameService GameService;
|
2026-01-24 15:32:40 -06:00
|
|
|
|
private readonly LibraryClient LibraryClient;
|
2024-05-20 20:26:15 -05:00
|
|
|
|
|
2024-05-25 22:21:04 -05:00
|
|
|
|
public Dictionary<Guid, Process> RunningProcesses = new Dictionary<Guid, Process>();
|
2024-05-25 15:40:31 -05:00
|
|
|
|
|
2024-11-09 17:15:04 -06:00
|
|
|
|
public ObservableCollection<ListItem> Items { get; set; } = new ObservableCollection<ListItem>();
|
2024-06-28 03:50:21 -05:00
|
|
|
|
|
2024-11-09 17:15:04 -06:00
|
|
|
|
public delegate Task OnLibraryChangedHandler(IEnumerable<ListItem> items);
|
2025-05-25 22:19:55 +02:00
|
|
|
|
public event OnLibraryChangedHandler? OnLibraryChanged;
|
|
|
|
|
|
|
2025-05-26 22:32:59 +02:00
|
|
|
|
public delegate Task OnLibraryItemsUpdatedHandler(IEnumerable<ListItem> itemsUpdatedOrAdded, IEnumerable<ListItem> itemsRemoved);
|
2025-05-25 22:19:55 +02:00
|
|
|
|
public event OnLibraryItemsUpdatedHandler? OnLibraryItemsUpdated;
|
2024-05-29 02:02:40 -05:00
|
|
|
|
|
2024-11-09 17:15:04 -06:00
|
|
|
|
public delegate Task OnPreLibraryItemsFilteredHandler(IEnumerable<ListItem> items);
|
2024-07-13 12:55:42 -05:00
|
|
|
|
public event OnPreLibraryItemsFilteredHandler OnPreLibraryItemsFiltered;
|
|
|
|
|
|
|
2024-11-09 17:15:04 -06:00
|
|
|
|
public delegate Task OnItemsFilteredHandler(IEnumerable<ListItem> items);
|
|
|
|
|
|
public event OnItemsFilteredHandler OnItemsFiltered;
|
2024-06-28 03:50:21 -05:00
|
|
|
|
|
2024-11-09 17:15:04 -06:00
|
|
|
|
public LibraryFilter Filter { get; set; } = new LibraryFilter();
|
2024-07-08 19:15:57 -05:00
|
|
|
|
|
2024-05-23 18:38:13 -05:00
|
|
|
|
public LibraryService(
|
2025-01-19 00:06:44 -06:00
|
|
|
|
DatabaseContext databaseContext,
|
2024-09-11 00:24:34 -05:00
|
|
|
|
ILogger<LibraryService> logger,
|
2025-01-20 12:10:30 -06:00
|
|
|
|
AuthenticationService authenticationService,
|
2024-10-26 15:48:47 -05:00
|
|
|
|
InstallService installService,
|
2024-05-23 18:38:13 -05:00
|
|
|
|
GameService gameService,
|
2026-01-24 15:32:40 -06:00
|
|
|
|
LibraryClient libraryClient) : base(databaseContext, logger)
|
2024-05-20 20:26:15 -05:00
|
|
|
|
{
|
2025-01-20 12:10:30 -06:00
|
|
|
|
AuthenticationService = authenticationService;
|
2024-10-26 15:48:47 -05:00
|
|
|
|
InstallService = installService;
|
2024-05-29 02:02:40 -05:00
|
|
|
|
GameService = gameService;
|
2026-01-24 15:32:40 -06:00
|
|
|
|
LibraryClient = libraryClient;
|
2024-05-29 02:02:40 -05:00
|
|
|
|
|
2024-10-26 15:48:47 -05:00
|
|
|
|
InstallService.OnInstallComplete += InstallService_OnInstallComplete;
|
2024-10-30 00:22:24 -05:00
|
|
|
|
Filter.OnChanged += Filter_OnChanged;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task Filter_OnChanged()
|
|
|
|
|
|
{
|
2024-11-09 17:15:04 -06:00
|
|
|
|
if (OnItemsFiltered != null)
|
|
|
|
|
|
await OnItemsFiltered.Invoke(Filter.ApplyFilter(Items));
|
2024-07-13 13:43:24 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-10-26 15:48:47 -05:00
|
|
|
|
private async Task InstallService_OnInstallComplete(Game game)
|
2024-05-29 02:02:40 -05:00
|
|
|
|
{
|
2025-05-25 22:19:55 +02:00
|
|
|
|
await LibraryChanged();
|
2024-05-20 20:26:15 -05:00
|
|
|
|
}
|
2024-05-23 18:38:13 -05:00
|
|
|
|
|
2025-05-25 22:19:55 +02:00
|
|
|
|
public async Task<IEnumerable<ListItem>> RefreshItemsAsync(bool forcePersistent = false)
|
2024-06-28 03:50:21 -05:00
|
|
|
|
{
|
2025-10-08 19:51:44 -05:00
|
|
|
|
using (var op = Logger.BeginOperation("Refreshing library items"))
|
2025-05-25 22:19:55 +02:00
|
|
|
|
{
|
2025-10-08 19:51:44 -05:00
|
|
|
|
if (forcePersistent)
|
|
|
|
|
|
{
|
|
|
|
|
|
// clearing pending changes in tracker to force load data from database
|
|
|
|
|
|
Context.ChangeTracker.Clear();
|
|
|
|
|
|
}
|
2025-05-25 22:19:55 +02:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
Items = new ObservableCollection<ListItem>(await GetItemsAsync());
|
2024-06-28 03:50:21 -05:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
await LibraryChanged();
|
2025-05-25 22:19:55 +02:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
if (OnItemsFiltered != null)
|
|
|
|
|
|
await OnItemsFiltered.Invoke(Filter.ApplyFilter(Items));
|
|
|
|
|
|
|
|
|
|
|
|
op.Complete();
|
2024-10-30 00:22:24 -05:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
return Items;
|
|
|
|
|
|
}
|
2024-06-28 03:50:21 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-09 17:15:04 -06:00
|
|
|
|
public IEnumerable<ListItem> GetItems<T>()
|
2024-06-28 03:50:21 -05:00
|
|
|
|
{
|
2024-11-09 17:15:04 -06:00
|
|
|
|
return Items.Where(i => i.DataItem is T).DistinctBy(i => i.Key);
|
2024-06-28 03:50:21 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-19 00:06:44 -06:00
|
|
|
|
public async Task<Library> GetByUserAsync(Guid userId)
|
|
|
|
|
|
{
|
2025-10-08 19:51:44 -05:00
|
|
|
|
using (var op = Logger.BeginDebugOperation("Getting library by user"))
|
2025-01-20 12:10:30 -06:00
|
|
|
|
{
|
2025-10-08 19:51:44 -05:00
|
|
|
|
op.Enrich("UserId", userId);
|
|
|
|
|
|
|
|
|
|
|
|
var user = await Context
|
|
|
|
|
|
.Users
|
|
|
|
|
|
.Include(u => u.Library)
|
|
|
|
|
|
.ThenInclude(l => l.Games)
|
|
|
|
|
|
.FirstOrDefaultAsync(u => u.Id == userId);
|
|
|
|
|
|
|
|
|
|
|
|
try
|
2025-01-20 12:10:30 -06:00
|
|
|
|
{
|
2025-10-08 19:51:44 -05:00
|
|
|
|
if (user == null)
|
2025-01-20 12:10:30 -06:00
|
|
|
|
{
|
2025-10-08 19:51:44 -05:00
|
|
|
|
user = new User
|
|
|
|
|
|
{
|
|
|
|
|
|
Id = userId,
|
|
|
|
|
|
};
|
2025-01-20 12:10:30 -06:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
user = Context.Users.Add(user).Entity;
|
2025-09-05 02:00:59 -05:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
await Context.SaveChangesAsync();
|
|
|
|
|
|
}
|
2025-01-20 12:10:30 -06:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
if (user.Library == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
user.Library = new Library();
|
2025-01-20 12:10:30 -06:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
user = Context.Users.Update(user).Entity;
|
2025-01-20 12:10:30 -06:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
await Context.SaveChangesAsync();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.LogError(ex, "Failed to get user library");
|
2025-01-20 12:10:30 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
op.Complete();
|
|
|
|
|
|
|
|
|
|
|
|
return user.Library;
|
2025-01-20 12:10:30 -06:00
|
|
|
|
}
|
2025-01-19 00:06:44 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-23 21:44:00 +02:00
|
|
|
|
private static bool IsInstalled(ListItem item)
|
|
|
|
|
|
{
|
|
|
|
|
|
return item != null && (item.State == ListItemState.Installed || item.State == ListItemState.UpdateAvailable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-02-28 14:02:27 -06:00
|
|
|
|
public bool IsInstalled(Guid itemId)
|
|
|
|
|
|
{
|
2025-05-23 21:44:00 +02:00
|
|
|
|
return Items.Any(i => i.Key == itemId && IsInstalled(i));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async Task<bool> IsInstalledAsync(Guid itemId)
|
|
|
|
|
|
{
|
2025-10-08 19:51:44 -05:00
|
|
|
|
using (var op = Logger.BeginDebugOperation("Checking if library item is installed"))
|
|
|
|
|
|
{
|
|
|
|
|
|
var items = await GetItemsAsync();
|
|
|
|
|
|
|
|
|
|
|
|
var installed = items.Any(i => IsInstalled(i));
|
|
|
|
|
|
|
|
|
|
|
|
op.Complete();
|
|
|
|
|
|
|
|
|
|
|
|
return installed;
|
|
|
|
|
|
}
|
2025-02-28 14:02:27 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-25 18:35:01 +02:00
|
|
|
|
public bool IsInLibrary(Guid itemId)
|
|
|
|
|
|
{
|
|
|
|
|
|
return Items.Any(i => i.Key == itemId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 22:12:18 +11:00
|
|
|
|
public async Task<bool> IsInLibraryAsync(Guid gameId)
|
|
|
|
|
|
{
|
|
|
|
|
|
var userId = AuthenticationService.GetUserId();
|
|
|
|
|
|
return await Context.Games
|
|
|
|
|
|
.AnyAsync(g => g.Id == gameId && g.Libraries.Any(l => l.UserId == userId));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-09 17:15:04 -06:00
|
|
|
|
public async Task<IEnumerable<ListItem>> GetItemsAsync()
|
2024-05-23 23:41:38 -05:00
|
|
|
|
{
|
2024-11-09 17:15:04 -06:00
|
|
|
|
Items.Clear();
|
2024-09-11 18:59:40 -05:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
using (var op = Logger.BeginDebugOperation("Loading library items from local database"))
|
2024-09-11 18:59:40 -05:00
|
|
|
|
{
|
2025-01-20 20:32:51 -06:00
|
|
|
|
var games = await Context
|
|
|
|
|
|
.Games
|
2025-01-26 15:25:41 -06:00
|
|
|
|
.AsSplitQuery()
|
2025-01-20 20:32:51 -06:00
|
|
|
|
.Where(g => g.Libraries.Any(l => l.UserId == AuthenticationService.GetUserId()))
|
|
|
|
|
|
.Include(g => g.Media)
|
|
|
|
|
|
.Include(g => g.Platforms)
|
|
|
|
|
|
.Include(g => g.Collections)
|
|
|
|
|
|
.Include(g => g.Genres)
|
|
|
|
|
|
.Include(g => g.Engine)
|
|
|
|
|
|
.Include(g => g.Publishers)
|
|
|
|
|
|
.Include(g => g.Developers)
|
|
|
|
|
|
.Include(g => g.Tags)
|
|
|
|
|
|
.Include(g => g.MultiplayerModes)
|
2025-05-25 18:35:01 +02:00
|
|
|
|
.Include(g => g.DependentGames)
|
2025-01-20 20:32:51 -06:00
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
|
|
Filter.Populate(games);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var item in games.Select(g => new ListItem(g)).OrderByTitle(g => !String.IsNullOrWhiteSpace(g.SortName) ? g.SortName : g.Name))
|
2024-09-16 21:00:07 -05:00
|
|
|
|
{
|
2024-11-09 17:15:04 -06:00
|
|
|
|
Items.Add(item);
|
2024-09-16 21:00:07 -05:00
|
|
|
|
}
|
2024-09-25 20:27:48 -05:00
|
|
|
|
|
|
|
|
|
|
op.Complete();
|
2024-09-11 18:59:40 -05:00
|
|
|
|
}
|
2024-07-12 18:22:17 -05:00
|
|
|
|
|
2024-11-09 17:15:04 -06:00
|
|
|
|
return Items;
|
2024-07-12 18:22:17 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-09 17:15:04 -06:00
|
|
|
|
public IEnumerable<ListItem> GetFilteredItems()
|
2024-07-12 18:22:17 -05:00
|
|
|
|
{
|
2024-11-09 17:15:04 -06:00
|
|
|
|
return Filter.ApplyFilter(Items);
|
2024-05-23 23:41:38 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-09 17:15:04 -06:00
|
|
|
|
public ListItem GetItem(Guid key)
|
2024-06-28 03:50:21 -05:00
|
|
|
|
{
|
2024-11-09 17:15:04 -06:00
|
|
|
|
var item = Items.FirstOrDefault(i => i.Key == key);
|
2024-06-28 03:50:21 -05:00
|
|
|
|
|
|
|
|
|
|
if (item == null)
|
2024-11-09 17:15:04 -06:00
|
|
|
|
item = Items.FirstOrDefault(i => i.Key == key);
|
2024-06-28 03:50:21 -05:00
|
|
|
|
|
|
|
|
|
|
return item;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-09 17:15:04 -06:00
|
|
|
|
public async Task<ListItem> GetItemAsync(ListItem libraryItem)
|
2024-06-02 17:23:36 -05:00
|
|
|
|
{
|
2024-11-09 17:15:04 -06:00
|
|
|
|
return await GetItemAsync(libraryItem.Key);
|
2024-08-01 17:21:44 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-09 17:15:04 -06:00
|
|
|
|
public async Task<ListItem> GetItemAsync(Guid key)
|
2024-08-01 17:21:44 -05:00
|
|
|
|
{
|
2025-10-08 19:51:44 -05:00
|
|
|
|
using (var op = Logger.BeginOperation("Getting library item"))
|
|
|
|
|
|
{
|
|
|
|
|
|
op.Enrich("Key", key);
|
|
|
|
|
|
|
|
|
|
|
|
var game = await Context.Games
|
|
|
|
|
|
.AsSplitQuery()
|
|
|
|
|
|
.Include(g => g.Collections)
|
|
|
|
|
|
.Include(g => g.Developers)
|
|
|
|
|
|
.Include(g => g.Genres)
|
|
|
|
|
|
.Include(g => g.Publishers)
|
|
|
|
|
|
.Include(g => g.Tags)
|
|
|
|
|
|
.Include(g => g.PlaySessions)
|
|
|
|
|
|
.Include(g => g.Engine)
|
|
|
|
|
|
.Include(g => g.Platforms)
|
|
|
|
|
|
.Include(g => g.Media)
|
|
|
|
|
|
.Include(g => g.MultiplayerModes)
|
|
|
|
|
|
.Include(g => g.DependentGames)
|
|
|
|
|
|
.FirstOrDefaultAsync(g => g.Id == key);
|
|
|
|
|
|
|
|
|
|
|
|
op.Complete();
|
|
|
|
|
|
|
|
|
|
|
|
return new ListItem(game);
|
|
|
|
|
|
}
|
2024-06-02 17:23:36 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-02-15 23:45:51 -06:00
|
|
|
|
public async Task AddToLibraryAsync(Game game)
|
2024-11-12 02:35:28 -06:00
|
|
|
|
{
|
2025-10-08 19:51:44 -05:00
|
|
|
|
using (var op = Logger.BeginOperation("Adding game to library"))
|
2025-01-20 12:10:30 -06:00
|
|
|
|
{
|
2025-10-08 19:51:44 -05:00
|
|
|
|
op.Enrich("Id", game.Id);
|
|
|
|
|
|
op.Enrich("Title", game.Title);
|
|
|
|
|
|
|
|
|
|
|
|
var library = await GetByUserAsync(AuthenticationService.GetUserId());
|
2025-02-15 23:45:51 -06:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
if (library.Games.Where(g => g != null).All(g => g.Id != game.Id))
|
|
|
|
|
|
{
|
|
|
|
|
|
library.Games.Add(game);
|
2024-11-12 02:35:28 -06:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
await UpdateAsync(library);
|
|
|
|
|
|
}
|
2024-11-12 02:35:28 -06:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
if (Items.All(i => i.Key != game.Id))
|
|
|
|
|
|
{
|
|
|
|
|
|
var item = new ListItem(game);
|
|
|
|
|
|
Items.Add(item);
|
|
|
|
|
|
|
|
|
|
|
|
await LibraryItemsUpdated(itemsUpdatedOrAdded: [item]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
op.Complete();
|
2025-02-15 23:45:51 -06:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async Task AddToLibraryAsync(Guid id)
|
|
|
|
|
|
{
|
2025-10-08 19:51:44 -05:00
|
|
|
|
using (var op = Logger.BeginOperation("Adding game to library using ID"))
|
|
|
|
|
|
{
|
|
|
|
|
|
op.Enrich("Id", id);
|
|
|
|
|
|
|
|
|
|
|
|
var localGame = await GameService.GetAsync(id);
|
2025-02-15 23:45:51 -06:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
await AddToLibraryAsync(localGame);
|
2025-02-15 23:45:51 -06:00
|
|
|
|
|
2026-01-24 15:32:40 -06:00
|
|
|
|
await LibraryClient.AddToLibrary(id);
|
2025-10-08 19:51:44 -05:00
|
|
|
|
|
|
|
|
|
|
op.Complete();
|
|
|
|
|
|
}
|
2024-11-12 02:35:28 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-25 18:35:01 +02:00
|
|
|
|
public Task RemoveFromLibraryAsync(Guid id)
|
|
|
|
|
|
{
|
|
|
|
|
|
return RemoveFromLibraryAsync(id, []);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async Task RemoveFromLibraryAsync(Guid id, params Guid[] addonIds)
|
2024-11-12 02:35:28 -06:00
|
|
|
|
{
|
2025-10-08 19:51:44 -05:00
|
|
|
|
using (var op = Logger.BeginOperation("Removing game from library"))
|
|
|
|
|
|
{
|
|
|
|
|
|
op.Enrich("Id", id);
|
|
|
|
|
|
op.Enrich("AddonId", addonIds);
|
|
|
|
|
|
|
|
|
|
|
|
var localGame = await GameService.GetAsync(id);
|
|
|
|
|
|
var library = await GetByUserAsync(AuthenticationService.GetUserId());
|
2024-11-12 02:35:28 -06:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
// update library items
|
2025-05-25 22:19:55 +02:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
addonIds ??= [];
|
|
|
|
|
|
foreach (var addonId in addonIds)
|
2025-05-25 18:35:01 +02:00
|
|
|
|
{
|
2025-10-08 19:51:44 -05:00
|
|
|
|
var localAddon = await GameService.GetAsync(addonId);
|
|
|
|
|
|
if (localAddon != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
library.Games.Remove(localAddon);
|
|
|
|
|
|
}
|
2025-05-25 18:35:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
library.Games.Remove(localGame);
|
2025-01-20 12:10:30 -06:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
await UpdateAsync(library);
|
2025-05-25 18:35:01 +02:00
|
|
|
|
|
2026-01-24 15:32:40 -06:00
|
|
|
|
await LibraryClient.RemoveFromLibrary(id, addonIds);
|
2025-05-25 22:19:55 +02:00
|
|
|
|
|
|
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
// handle removing item from libray list locally
|
2025-02-06 19:47:09 -06:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
var itemToRemove = Items.FirstOrDefault(i => i.Key == id);
|
2025-02-06 19:47:09 -06:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
if (itemToRemove != null)
|
|
|
|
|
|
Items.Remove(itemToRemove);
|
2024-11-12 02:35:28 -06:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
var addonsToRemove = Items.Where(i => addonIds.Contains(i.Key));
|
|
|
|
|
|
Items.RemoveRange(addonsToRemove);
|
2025-05-25 18:35:01 +02:00
|
|
|
|
|
2025-10-08 19:51:44 -05:00
|
|
|
|
var itemsRemoved = addonsToRemove.Concat([itemToRemove!]) ?? [];
|
|
|
|
|
|
await LibraryItemsUpdated(itemsRemoved: itemsRemoved);
|
|
|
|
|
|
|
|
|
|
|
|
op.Complete();
|
|
|
|
|
|
}
|
2024-11-12 02:35:28 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-25 22:19:55 +02:00
|
|
|
|
public async Task LibraryChanged(IEnumerable<ListItem>? items = null)
|
2024-05-29 02:02:40 -05:00
|
|
|
|
{
|
2024-07-13 12:55:42 -05:00
|
|
|
|
if (OnLibraryChanged != null)
|
2025-05-25 22:19:55 +02:00
|
|
|
|
await OnLibraryChanged.Invoke(items ?? Items);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async Task LibraryItemsUpdated(IEnumerable<ListItem>? itemsUpdatedOrAdded = null, IEnumerable<ListItem>? itemsRemoved = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (OnLibraryItemsUpdated != null)
|
2025-05-26 22:32:59 +02:00
|
|
|
|
{
|
|
|
|
|
|
itemsUpdatedOrAdded = itemsUpdatedOrAdded?.ToArray() ?? [];
|
|
|
|
|
|
itemsRemoved = itemsRemoved?.ToArray() ?? [];
|
2025-05-25 22:19:55 +02:00
|
|
|
|
await OnLibraryItemsUpdated(itemsUpdatedOrAdded: itemsUpdatedOrAdded, itemsRemoved: itemsRemoved);
|
2025-05-26 22:32:59 +02:00
|
|
|
|
}
|
2024-07-13 12:55:42 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async Task FilterChanged()
|
|
|
|
|
|
{
|
2024-11-09 17:15:04 -06:00
|
|
|
|
Items = new ObservableCollection<ListItem>(await GetItemsAsync());
|
2024-05-29 02:02:40 -05:00
|
|
|
|
}
|
2024-05-20 20:26:15 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|