Merge branch 'main' of https://github.com/Penumbra-Sync/client
This commit is contained in:
2
MareAPI
2
MareAPI
Submodule MareAPI updated: 0065dd3cda...22346739d2
@@ -94,5 +94,9 @@ csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
|
||||
csharp_style_prefer_tuple_swap = true:suggestion
|
||||
csharp_style_prefer_utf8_string_literals = true:suggestion
|
||||
dotnet_diagnostic.S1075.severity = silent
|
||||
dotnet_diagnostic.SS3358.severity = true:suggestion
|
||||
dotnet_diagnostic.MA0007.severity = silent
|
||||
dotnet_diagnostic.MA0075.severity = silent
|
||||
dotnet_diagnostic.MA0075.severity = silent
|
||||
|
||||
# S3358: Ternary operators should not be nested
|
||||
dotnet_diagnostic.S3358.severity = suggestion
|
||||
|
||||
@@ -66,7 +66,7 @@ public sealed class FileCacheManager : IDisposable
|
||||
var fullName = fi.FullName.ToLowerInvariant();
|
||||
if (!fullName.Contains(_configService.Current.CacheFolder.ToLowerInvariant(), StringComparison.Ordinal)) return null;
|
||||
string prefixedPath = fullName.Replace(_configService.Current.CacheFolder.ToLowerInvariant(), _cachePrefix + "\\", StringComparison.Ordinal).Replace("\\\\", "\\", StringComparison.Ordinal);
|
||||
return CreateFileCacheEntity(fi, prefixedPath, fi.Name.ToUpper(CultureInfo.InvariantCulture));
|
||||
return CreateFileCacheEntity(fi, prefixedPath);
|
||||
}
|
||||
|
||||
public FileCacheEntity? CreateFileEntry(string path)
|
||||
@@ -122,10 +122,13 @@ public sealed class FileCacheManager : IDisposable
|
||||
return validatedCacheEntry;
|
||||
}
|
||||
|
||||
public void RemoveHash(FileCacheEntity entity)
|
||||
public void RemoveHash(FileCacheEntity? entity)
|
||||
{
|
||||
_logger.LogTrace("Removing {path}", entity.ResolvedFilepath);
|
||||
_fileCaches.Remove(entity.PrefixedFilePath, out _);
|
||||
if (entity != null)
|
||||
{
|
||||
_logger.LogTrace("Removing {path}", entity.ResolvedFilepath);
|
||||
_fileCaches.Remove(entity.PrefixedFilePath, out _);
|
||||
}
|
||||
}
|
||||
|
||||
public string ResolveFileReplacement(string gamePath)
|
||||
|
||||
@@ -15,7 +15,7 @@ public sealed class PeriodicFileScanner : DisposableMediatorSubscriberBase
|
||||
private readonly PerformanceCollectorService _performanceCollector;
|
||||
private long _currentFileProgress = 0;
|
||||
private bool _fileScanWasRunning = false;
|
||||
private CancellationTokenSource? _scanCancellationTokenSource;
|
||||
private CancellationTokenSource _scanCancellationTokenSource = new();
|
||||
private TimeSpan _timeUntilNextScan = TimeSpan.Zero;
|
||||
|
||||
public PeriodicFileScanner(ILogger<PeriodicFileScanner> logger, IpcManager ipcManager, MareConfigService configService,
|
||||
@@ -246,7 +246,7 @@ public sealed class PeriodicFileScanner : DisposableMediatorSubscriberBase
|
||||
Logger.LogWarning(ex, "Error during enumerating FileCaches");
|
||||
}
|
||||
|
||||
Task.WaitAll(dbTasks);
|
||||
Task.WaitAll(dbTasks, _scanCancellationTokenSource.Token);
|
||||
|
||||
if (!_ipcManager.CheckPenumbraApi())
|
||||
{
|
||||
@@ -308,7 +308,7 @@ public sealed class PeriodicFileScanner : DisposableMediatorSubscriberBase
|
||||
if (ct.IsCancellationRequested) return;
|
||||
}
|
||||
|
||||
Task.WaitAll(dbTasks);
|
||||
Task.WaitAll(dbTasks, _scanCancellationTokenSource.Token);
|
||||
|
||||
Logger.LogTrace("Scanner added new files to db");
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace MareSynchronos.MareConfiguration;
|
||||
#pragma warning disable CS0618 // ignore Obsolete tag, the point of this migrator is to migrate obsolete configs to new ones
|
||||
#pragma warning disable CS0612 // ignore Obsolete tag, the point of this migrator is to migrate obsolete configs to new ones
|
||||
|
||||
public class ConfigurationMigrator : IHostedService
|
||||
{
|
||||
@@ -22,7 +23,7 @@ public class ConfigurationMigrator : IHostedService
|
||||
|
||||
public void Migrate()
|
||||
{
|
||||
if (_pi.GetPluginConfig() is Configuration oldConfig)
|
||||
if (_pi.GetPluginConfig() is Configurations.Obsolete.Configuration oldConfig)
|
||||
{
|
||||
_logger.LogInformation("Migrating Configuration from old config style to 1");
|
||||
|
||||
@@ -52,11 +53,15 @@ public class ConfigurationMigrator : IHostedService
|
||||
{
|
||||
try
|
||||
{
|
||||
var serverConfig = JsonConvert.DeserializeObject<ServerConfigV0>(File.ReadAllText(ConfigurationPath(ServerConfigService.ConfigName)))!;
|
||||
|
||||
if (serverConfig.Version == 0)
|
||||
var content = File.ReadAllText(ConfigurationPath(ServerConfigService.ConfigName));
|
||||
if (!content.Contains("\"Version\": 1"))
|
||||
{
|
||||
MigrateServerConfigV0toV1(serverConfig);
|
||||
var serverConfig = JsonConvert.DeserializeObject<ServerConfigV0>(content);
|
||||
|
||||
if (serverConfig != null && serverConfig.Version == 0)
|
||||
{
|
||||
MigrateServerConfigV0toV1(serverConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -92,7 +97,6 @@ public class ConfigurationMigrator : IHostedService
|
||||
|
||||
MareConfig mareConfigV1 = mareConfigV0.ToV1();
|
||||
|
||||
int i = 0;
|
||||
var serverConfig = new ServerConfig()
|
||||
{
|
||||
ServerStorage = mareConfigV0.ServerStorage.Select(p => p.Value.ToV1()).ToList()
|
||||
@@ -152,4 +156,5 @@ public class ConfigurationMigrator : IHostedService
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore CS0612 // ignore Obsolete tag, the point of this migrator is to migrate obsolete configs to new ones
|
||||
#pragma warning restore CS0618 // ignore Obsolete tag, the point of this migrator is to migrate obsolete configs to new ones
|
||||
@@ -10,6 +10,7 @@ public class MareConfig : IMareConfiguration
|
||||
public string CacheFolder { get; set; } = string.Empty;
|
||||
public bool DisableOptionalPluginWarnings { get; set; } = false;
|
||||
public NotificationLocation ErrorNotification { get; set; } = NotificationLocation.Both;
|
||||
public string ExportFolder { get; set; } = string.Empty;
|
||||
public bool FileScanPaused { get; set; } = false;
|
||||
public NotificationLocation InfoNotification { get; set; } = NotificationLocation.Toast;
|
||||
public bool InitialScanComplete { get; set; } = false;
|
||||
@@ -19,6 +20,9 @@ public class MareConfig : IMareConfiguration
|
||||
public bool OpenGposeImportOnGposeStart { get; set; } = false;
|
||||
public bool OpenPopupOnAdd { get; set; } = true;
|
||||
public int ParallelDownloads { get; set; } = 10;
|
||||
public float ProfileDelay { get; set; } = 2;
|
||||
public bool ProfilesAllowNsfw { get; set; } = false;
|
||||
public bool ProfilesShow { get; set; } = true;
|
||||
public bool ReverseUserSort { get; set; } = false;
|
||||
public bool ShowCharacterNameInsteadOfNotesForVisible { get; set; } = false;
|
||||
public bool ShowOfflineUsersSeparately { get; set; } = true;
|
||||
|
||||
@@ -4,7 +4,7 @@ using MareSynchronos.WebAPI;
|
||||
namespace MareSynchronos.MareConfiguration.Configurations.Obsolete;
|
||||
|
||||
[Serializable]
|
||||
[Obsolete]
|
||||
[Obsolete("Replaced with ServerConfig")]
|
||||
public class ServerConfigV0 : IMareConfiguration
|
||||
{
|
||||
public string CurrentServer { get; set; } = string.Empty;
|
||||
@@ -15,4 +15,4 @@ public class ServerConfigV0 : IMareConfiguration
|
||||
};
|
||||
|
||||
public int Version { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<Authors></Authors>
|
||||
<Company></Company>
|
||||
<Version>0.8.8</Version>
|
||||
<Version>0.8.10</Version>
|
||||
<Description></Description>
|
||||
<Copyright></Copyright>
|
||||
<PackageProjectUrl>https://github.com/Penumbra-Sync/client</PackageProjectUrl>
|
||||
@@ -37,6 +37,7 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||
<PackageReference Include="Penumbra.Api" Version="1.0.7" />
|
||||
<PackageReference Include="Penumbra.String" Version="1.0.3" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.0" />
|
||||
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.54.0.64047">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -84,8 +84,8 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
||||
|
||||
public IntPtr Address { get; set; }
|
||||
public unsafe Character* Character => (Character*)Address;
|
||||
public Lazy<Dalamud.Game.ClientState.Objects.Types.GameObject?> GameObjectLazy { get; private set; }
|
||||
public IntPtr CurrentAddress => _getAddress.Invoke();
|
||||
public Lazy<Dalamud.Game.ClientState.Objects.Types.GameObject?> GameObjectLazy { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public ObjectKind ObjectKind { get; }
|
||||
private byte[] CustomizeData { get; set; } = new byte[26];
|
||||
@@ -101,6 +101,8 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
||||
{
|
||||
curPtr = _getAddress.Invoke();
|
||||
|
||||
if (curPtr == IntPtr.Zero) return true;
|
||||
|
||||
var drawObj = GetDrawObj(curPtr);
|
||||
return IsBeingDrawn(drawObj, curPtr);
|
||||
}
|
||||
|
||||
@@ -158,21 +158,29 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase
|
||||
_charaHandler?.Dispose();
|
||||
_charaHandler = null;
|
||||
|
||||
if (!_lifetime.ApplicationStopping.IsCancellationRequested && !_dalamudUtil.IsZoning && !_dalamudUtil.IsInCutscene)
|
||||
if (!_lifetime.ApplicationStopping.IsCancellationRequested)
|
||||
{
|
||||
Logger.LogTrace("[{applicationId}] Restoring state for {name} ({OnlineUser})", applicationId, name, OnlineUser);
|
||||
_ipcManager.PenumbraRemoveTemporaryCollection(Logger, applicationId, name);
|
||||
|
||||
foreach (KeyValuePair<ObjectKind, List<FileReplacementData>> item in _cachedData.FileReplacements)
|
||||
if (_dalamudUtil.IsZoning)
|
||||
{
|
||||
try
|
||||
Logger.LogTrace("[{applicationId}] Removing temp collection for {name} ({OnlineUser})", applicationId, name, OnlineUser);
|
||||
_ipcManager.PenumbraRemoveTemporaryCollection(Logger, applicationId, name);
|
||||
}
|
||||
else if (!_dalamudUtil.IsZoning && !_dalamudUtil.IsInCutscene)
|
||||
{
|
||||
Logger.LogTrace("[{applicationId}] Restoring state for {name} ({OnlineUser})", applicationId, name, OnlineUser);
|
||||
_ipcManager.PenumbraRemoveTemporaryCollection(Logger, applicationId, name);
|
||||
|
||||
foreach (KeyValuePair<ObjectKind, List<FileReplacementData>> item in _cachedData.FileReplacements)
|
||||
{
|
||||
RevertCustomizationData(item.Key, name, applicationId).GetAwaiter().GetResult();
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
Logger.LogWarning("Failed disposing player (not present anymore?)", ex);
|
||||
break;
|
||||
try
|
||||
{
|
||||
RevertCustomizationData(item.Key, name, applicationId).GetAwaiter().GetResult();
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
Logger.LogWarning("Failed disposing player (not present anymore?)", ex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -408,7 +416,7 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase
|
||||
while ((!_applicationTask?.IsCompleted ?? false) && !downloadToken.IsCancellationRequested && !_applicationCancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
// block until current application is done
|
||||
Logger.LogDebug("Waiting for current data application (Id: {id}) to finish", _applicationId);
|
||||
Logger.LogDebug("Waiting for current data application (Id: {id}) for player ({handler}) to finish", _applicationId, PlayerName);
|
||||
await Task.Delay(250).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -419,22 +427,34 @@ public sealed class CachedPlayer : DisposableMediatorSubscriberBase
|
||||
var token = _applicationCancellationTokenSource.Token;
|
||||
_applicationTask = Task.Run(async () =>
|
||||
{
|
||||
_applicationId = Guid.NewGuid();
|
||||
Logger.LogDebug("[{applicationId}] Starting application task", _applicationId);
|
||||
|
||||
if (updateModdedPaths && (moddedPaths.Any() || !string.IsNullOrEmpty(charaData.ManipulationData)))
|
||||
try
|
||||
{
|
||||
await ApplyBaseData(_applicationId, moddedPaths, charaData.ManipulationData, token).ConfigureAwait(false);
|
||||
_applicationId = Guid.NewGuid();
|
||||
Logger.LogDebug("[{applicationId}] Starting application task", _applicationId);
|
||||
|
||||
Logger.LogDebug("[{applicationId}] Waiting for initial draw for for {handler}", _applicationId, _charaHandler);
|
||||
await _dalamudUtil.WaitWhileCharacterIsDrawing(Logger, _charaHandler, _applicationId, 30000, token).ConfigureAwait(false);
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
if (updateModdedPaths && (moddedPaths.Any() || !string.IsNullOrEmpty(charaData.ManipulationData)))
|
||||
{
|
||||
await ApplyBaseData(_applicationId, moddedPaths, charaData.ManipulationData, token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
foreach (var kind in updatedData)
|
||||
{
|
||||
await ApplyCustomizationData(_applicationId, kind, charaData, token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Logger.LogDebug("[{applicationId}] Application finished", _applicationId);
|
||||
}
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
foreach (var kind in updatedData)
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ApplyCustomizationData(_applicationId, kind, charaData, token).ConfigureAwait(false);
|
||||
Logger.LogInformation("[{applicationId}] Cancelled, reason: {msg}", _applicationId, ex.Message);
|
||||
}
|
||||
|
||||
Logger.LogDebug("[{applicationId}] Application finished", _applicationId);
|
||||
}, token);
|
||||
}, downloadToken);
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ public sealed class PairManager : DisposableMediatorSubscriberBase
|
||||
{
|
||||
if (_allClientPairs.TryGetValue(user, out var pair))
|
||||
{
|
||||
Mediator.Publish(new ClearProfileDataMessage(pair.UserData));
|
||||
pair.MarkOffline();
|
||||
RecreateLazy();
|
||||
}
|
||||
@@ -107,6 +108,9 @@ public sealed class PairManager : DisposableMediatorSubscriberBase
|
||||
public void MarkPairOnline(OnlineUserIdentDto dto, bool sendNotif = true)
|
||||
{
|
||||
if (!_allClientPairs.ContainsKey(dto.User)) throw new InvalidOperationException("No user found for " + dto);
|
||||
|
||||
Mediator.Publish(new ClearProfileDataMessage(dto.User));
|
||||
|
||||
var pair = _allClientPairs[dto.User];
|
||||
if (pair.HasCachedPlayer) return;
|
||||
|
||||
@@ -213,6 +217,12 @@ public sealed class PairManager : DisposableMediatorSubscriberBase
|
||||
|
||||
if (pair.UserPair == null) throw new InvalidOperationException("No direct pair for " + dto);
|
||||
|
||||
if (pair.UserPair.OtherPermissions.IsPaused() != dto.Permissions.IsPaused()
|
||||
|| pair.UserPair.OtherPermissions.IsPaired() != dto.Permissions.IsPaired())
|
||||
{
|
||||
Mediator.Publish(new ClearProfileDataMessage(dto.User));
|
||||
}
|
||||
|
||||
pair.UserPair.OtherPermissions = dto.Permissions;
|
||||
|
||||
Logger.LogTrace("Paired: {synced}, Paused: {paused}, Anims: {anims}, Sounds: {sounds}",
|
||||
@@ -229,6 +239,12 @@ public sealed class PairManager : DisposableMediatorSubscriberBase
|
||||
|
||||
if (pair.UserPair == null) throw new InvalidOperationException("No direct pair for " + dto);
|
||||
|
||||
if (pair.UserPair.OwnPermissions.IsPaused() != dto.Permissions.IsPaused()
|
||||
|| pair.UserPair.OwnPermissions.IsPaired() != dto.Permissions.IsPaired())
|
||||
{
|
||||
Mediator.Publish(new ClearProfileDataMessage(dto.User));
|
||||
}
|
||||
|
||||
pair.UserPair.OwnPermissions = dto.Permissions;
|
||||
|
||||
Logger.LogTrace("Paired: {synced}, Paused: {paused}, Anims: {anims}, Sounds: {sounds}",
|
||||
@@ -326,13 +342,14 @@ public sealed class PairManager : DisposableMediatorSubscriberBase
|
||||
private void DisposePairs(bool recreate = false)
|
||||
{
|
||||
Logger.LogDebug("Disposing all Pairs");
|
||||
foreach (var item in _allClientPairs)
|
||||
Parallel.ForEach(_allClientPairs, item =>
|
||||
{
|
||||
if (recreate)
|
||||
item.Value.RecreateCachedPlayer();
|
||||
else
|
||||
item.Value.MarkOffline();
|
||||
}
|
||||
});
|
||||
|
||||
RecreateLazy();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ using MareSynchronos.Services;
|
||||
using MareSynchronos.Services.Mediator;
|
||||
using MareSynchronos.Services.ServerConfiguration;
|
||||
using MareSynchronos.UI;
|
||||
using MareSynchronos.UI.Handlers;
|
||||
using MareSynchronos.WebAPI;
|
||||
using MareSynchronos.WebAPI.Files;
|
||||
using MareSynchronos.WebAPI.SignalR;
|
||||
@@ -65,6 +66,11 @@ public sealed class Plugin : IDalamudPlugin
|
||||
collection.AddSingleton<FileUploadManager>();
|
||||
collection.AddSingleton<FileTransferOrchestrator>();
|
||||
collection.AddSingleton<MarePlugin>();
|
||||
collection.AddSingleton<MareProfileManager>();
|
||||
collection.AddSingleton<UidDisplayHandler>((s) => new UidDisplayHandler(s.GetRequiredService<ILogger<UidDisplayHandler>>(), pluginInterface.UiBuilder,
|
||||
s.GetRequiredService<MareProfileManager>(),
|
||||
s.GetRequiredService<UiSharedService>(), s.GetRequiredService<PairManager>(),
|
||||
s.GetRequiredService<ServerConfigurationManager>(), s.GetRequiredService<MareConfigService>()));
|
||||
collection.AddSingleton((s) => new DalamudUtilService(s.GetRequiredService<ILogger<DalamudUtilService>>(),
|
||||
clientState, objectTable, framework, gameGui, condition, gameData,
|
||||
s.GetRequiredService<MareMediator>(), s.GetRequiredService<PerformanceCollectorService>()));
|
||||
@@ -117,6 +123,9 @@ public sealed class Plugin : IDalamudPlugin
|
||||
collection.AddScoped<WindowMediatorSubscriberBase, GposeUi>();
|
||||
collection.AddScoped<WindowMediatorSubscriberBase, IntroUi>();
|
||||
collection.AddScoped<WindowMediatorSubscriberBase, DownloadUi>();
|
||||
collection.AddScoped<WindowMediatorSubscriberBase, EditProfileUi>((s) => new EditProfileUi(s.GetRequiredService<ILogger<EditProfileUi>>(),
|
||||
s.GetRequiredService<MareMediator>(), s.GetRequiredService<ApiController>(), pluginInterface.UiBuilder, s.GetRequiredService<UiSharedService>(),
|
||||
s.GetRequiredService<FileDialogManager>(), s.GetRequiredService<MareProfileManager>()));
|
||||
collection.AddScoped<CacheCreationService>();
|
||||
collection.AddScoped<TransientResourceManager>();
|
||||
collection.AddScoped<PlayerDataFactory>();
|
||||
|
||||
@@ -55,6 +55,12 @@ public sealed class CommandManagerService : IDisposable
|
||||
|
||||
if (string.Equals(splitArgs[0], "toggle", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (_apiController.ServerState == WebAPI.SignalR.Utils.ServerState.Disconnecting)
|
||||
{
|
||||
_mediator.Publish(new NotificationMessage("Mare disconnecting", "Cannot use /toggle while Mare Synchronos is still disconnecting",
|
||||
Dalamud.Interface.Internal.Notifications.NotificationType.Error));
|
||||
}
|
||||
|
||||
if (_serverConfigurationManager.CurrentServer == null) return;
|
||||
var fullPause = splitArgs.Length > 1 ? splitArgs[1] switch
|
||||
{
|
||||
|
||||
80
MareSynchronos/Services/MareProfileManager.cs
Normal file
80
MareSynchronos/Services/MareProfileManager.cs
Normal file
File diff suppressed because one or more lines are too long
@@ -1,5 +1,6 @@
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Interface.Internal.Notifications;
|
||||
using MareSynchronos.API.Data;
|
||||
using MareSynchronos.API.Dto;
|
||||
using MareSynchronos.PlayerData.Handlers;
|
||||
using MareSynchronos.WebAPI.Files.Models;
|
||||
@@ -54,5 +55,6 @@ public record DownloadStartedMessage(GameObjectHandler DownloadId, Dictionary<st
|
||||
public record DownloadFinishedMessage(GameObjectHandler DownloadId) : IMessage;
|
||||
public record UiToggleMessage(Type UiType) : IMessage;
|
||||
public record PlayerUploadingMessage(GameObjectHandler Handler, bool IsUploading) : IMessage;
|
||||
public record ClearProfileDataMessage(UserData? UserData = null) : IMessage;
|
||||
|
||||
#pragma warning restore MA0048 // File name must match type name
|
||||
@@ -23,17 +23,29 @@ public class ServerConfigurationManager
|
||||
_serverTagConfig = serverTagConfig;
|
||||
_notesConfig = notesConfig;
|
||||
_dalamudUtil = dalamudUtil;
|
||||
|
||||
if (_configService.Current.CurrentServer < 0)
|
||||
{
|
||||
_configService.Current.CurrentServer = 0;
|
||||
_configService.Save();
|
||||
}
|
||||
}
|
||||
|
||||
public string CurrentApiUrl => CurrentServer.ServerUri;
|
||||
public ServerStorage CurrentServer => _configService.Current.ServerStorage[CurrentServerIndex];
|
||||
public int CurrentServerIndex => _configService.Current.CurrentServer;
|
||||
|
||||
public int CurrentServerIndex
|
||||
{
|
||||
set
|
||||
{
|
||||
_configService.Current.CurrentServer = value;
|
||||
_configService.Save();
|
||||
}
|
||||
get
|
||||
{
|
||||
if (_configService.Current.CurrentServer < 0)
|
||||
{
|
||||
_configService.Current.CurrentServer = 0;
|
||||
_configService.Save();
|
||||
}
|
||||
|
||||
return _configService.Current.CurrentServer;
|
||||
}
|
||||
}
|
||||
|
||||
public string? GetSecretKey(int serverIdx = -1)
|
||||
{
|
||||
|
||||
@@ -27,9 +27,6 @@ namespace MareSynchronos.UI;
|
||||
|
||||
public class CompactUi : WindowMediatorSubscriberBase
|
||||
{
|
||||
public readonly Dictionary<string, bool> ShowUidForEntry = new(StringComparer.Ordinal);
|
||||
public string EditNickEntry = string.Empty;
|
||||
public string EditUserComment = string.Empty;
|
||||
public float TransferPartHeight;
|
||||
public float WindowContentWidth;
|
||||
private readonly ApiController _apiController;
|
||||
@@ -43,6 +40,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
private readonly SelectPairForGroupUi _selectPairsForGroupUi;
|
||||
private readonly ServerConfigurationManager _serverManager;
|
||||
private readonly Stopwatch _timeout = new();
|
||||
private readonly UidDisplayHandler _uidDisplayHandler;
|
||||
private readonly UiSharedService _uiShared;
|
||||
private bool _buttonState;
|
||||
private string _characterOrCommentFilter = string.Empty;
|
||||
@@ -55,7 +53,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
private bool _wasOpen;
|
||||
|
||||
public CompactUi(ILogger<CompactUi> logger, UiSharedService uiShared, MareConfigService configService, ApiController apiController, PairManager pairManager,
|
||||
ServerConfigurationManager serverManager, MareMediator mediator, FileUploadManager fileTransferManager) : base(logger, mediator, "###MareSynchronosMainUI")
|
||||
ServerConfigurationManager serverManager, MareMediator mediator, FileUploadManager fileTransferManager, UidDisplayHandler uidDisplayHandler) : base(logger, mediator, "###MareSynchronosMainUI")
|
||||
{
|
||||
_uiShared = uiShared;
|
||||
_configService = configService;
|
||||
@@ -63,12 +61,13 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
_pairManager = pairManager;
|
||||
_serverManager = serverManager;
|
||||
_fileTransferManager = fileTransferManager;
|
||||
_uidDisplayHandler = uidDisplayHandler;
|
||||
var tagHandler = new TagHandler(_serverManager);
|
||||
|
||||
_groupPanel = new(this, uiShared, _pairManager, _serverManager, _configService);
|
||||
_selectGroupForPairUi = new(tagHandler);
|
||||
_selectPairsForGroupUi = new(tagHandler);
|
||||
_pairGroupsUi = new(configService, tagHandler, DrawPairedClient, apiController, _selectPairsForGroupUi);
|
||||
_groupPanel = new(this, uiShared, _pairManager, uidDisplayHandler, _serverManager);
|
||||
_selectGroupForPairUi = new(tagHandler, uidDisplayHandler);
|
||||
_selectPairsForGroupUi = new(tagHandler, uidDisplayHandler);
|
||||
_pairGroupsUi = new(configService, tagHandler, apiController, _selectPairsForGroupUi);
|
||||
|
||||
#if DEBUG
|
||||
string dev = "Dev Build";
|
||||
@@ -164,8 +163,8 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
ImGui.Separator();
|
||||
UiSharedService.DrawWithID("transfers", DrawTransfers);
|
||||
TransferPartHeight = ImGui.GetCursorPosY() - TransferPartHeight;
|
||||
UiSharedService.DrawWithID("group-user-popup", () => _selectPairsForGroupUi.Draw(_pairManager.DirectPairs, ShowUidForEntry));
|
||||
UiSharedService.DrawWithID("grouping-popup", () => _selectGroupForPairUi.Draw(ShowUidForEntry));
|
||||
UiSharedService.DrawWithID("group-user-popup", () => _selectPairsForGroupUi.Draw(_pairManager.DirectPairs));
|
||||
UiSharedService.DrawWithID("grouping-popup", () => _selectGroupForPairUi.Draw());
|
||||
}
|
||||
|
||||
if (_configService.Current.OpenPopupOnAdd && _pairManager.LastAddedUser != null)
|
||||
@@ -202,8 +201,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
|
||||
public override void OnClose()
|
||||
{
|
||||
EditNickEntry = string.Empty;
|
||||
EditUserComment = string.Empty;
|
||||
_uidDisplayHandler.Clear();
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
@@ -213,8 +211,6 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
var keys = _serverManager.CurrentServer!.SecretKeys;
|
||||
if (keys.TryGetValue(_secretKeyIdx, out var secretKey))
|
||||
{
|
||||
var friendlyName = secretKey.FriendlyName;
|
||||
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Plus, "Add current character with secret key"))
|
||||
{
|
||||
_serverManager.CurrentServer!.Authentications.Add(new MareConfiguration.Models.Authentication()
|
||||
@@ -350,210 +346,6 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPairedClient(Pair entry)
|
||||
{
|
||||
if (entry.UserPair == null) return;
|
||||
|
||||
var pauseIcon = entry.UserPair!.OwnPermissions.IsPaused() ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
|
||||
var pauseIconSize = UiSharedService.GetIconButtonSize(pauseIcon);
|
||||
var barButtonSize = UiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars);
|
||||
var entryUID = entry.UserData.AliasOrUID;
|
||||
var textSize = ImGui.CalcTextSize(entryUID);
|
||||
var originalY = ImGui.GetCursorPosY();
|
||||
var buttonSizes = pauseIconSize.Y + barButtonSize.Y;
|
||||
var spacingX = ImGui.GetStyle().ItemSpacing.X;
|
||||
var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth();
|
||||
|
||||
var textPos = originalY + pauseIconSize.Y / 2 - textSize.Y / 2;
|
||||
ImGui.SetCursorPosY(textPos);
|
||||
FontAwesomeIcon connectionIcon;
|
||||
string connectionText = string.Empty;
|
||||
Vector4 connectionColor;
|
||||
if (!(entry.UserPair!.OwnPermissions.IsPaired() && entry.UserPair!.OtherPermissions.IsPaired()))
|
||||
{
|
||||
connectionIcon = FontAwesomeIcon.ArrowUp;
|
||||
connectionText = entryUID + " has not added you back";
|
||||
connectionColor = ImGuiColors.DalamudRed;
|
||||
}
|
||||
else if (entry.UserPair!.OwnPermissions.IsPaused() || entry.UserPair!.OtherPermissions.IsPaused())
|
||||
{
|
||||
connectionIcon = FontAwesomeIcon.PauseCircle;
|
||||
connectionText = "Pairing status with " + entryUID + " is paused";
|
||||
connectionColor = ImGuiColors.DalamudYellow;
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionIcon = FontAwesomeIcon.Check;
|
||||
connectionText = "You are paired with " + entryUID;
|
||||
connectionColor = ImGuiColors.ParsedGreen;
|
||||
}
|
||||
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
UiSharedService.ColorText(connectionIcon.ToIconString(), connectionColor);
|
||||
ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip(connectionText);
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosY(textPos);
|
||||
if (entry is { IsOnline: true, IsVisible: true })
|
||||
{
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
UiSharedService.ColorText(FontAwesomeIcon.Eye.ToIconString(), ImGuiColors.ParsedGreen);
|
||||
ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip(entryUID + " is visible: " + entry.PlayerName!);
|
||||
}
|
||||
|
||||
var textIsUid = true;
|
||||
ShowUidForEntry.TryGetValue(entry.UserPair!.User.UID, out var showUidInsteadOfName);
|
||||
string? playerText = _serverManager.GetNoteForUid(entry.UserPair!.User.UID);
|
||||
if (!showUidInsteadOfName && playerText != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(playerText))
|
||||
{
|
||||
playerText = entryUID;
|
||||
}
|
||||
else
|
||||
{
|
||||
textIsUid = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
playerText = entryUID;
|
||||
}
|
||||
|
||||
if (_configService.Current.ShowCharacterNameInsteadOfNotesForVisible && entry.IsVisible && !showUidInsteadOfName)
|
||||
{
|
||||
playerText = entry.PlayerName;
|
||||
textIsUid = false;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (!string.Equals(EditNickEntry, entry.UserData.UID, StringComparison.Ordinal))
|
||||
{
|
||||
ImGui.SetCursorPosY(textPos);
|
||||
if (textIsUid) ImGui.PushFont(UiBuilder.MonoFont);
|
||||
ImGui.TextUnformatted(playerText);
|
||||
if (textIsUid) ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip("Left click to switch between UID display and nick" + Environment.NewLine +
|
||||
"Right click to change nick for " + entryUID);
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
|
||||
{
|
||||
var prevState = textIsUid;
|
||||
if (ShowUidForEntry.ContainsKey(entry.UserPair!.User.UID))
|
||||
{
|
||||
prevState = ShowUidForEntry[entry.UserPair!.User.UID];
|
||||
}
|
||||
|
||||
ShowUidForEntry[entry.UserPair!.User.UID] = !prevState;
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
var pair = _pairManager.DirectPairs.Find(p => string.Equals(p.UserData.UID, EditNickEntry, StringComparison.Ordinal));
|
||||
if (pair != null)
|
||||
{
|
||||
pair.SetNote(EditUserComment);
|
||||
_configService.Save();
|
||||
}
|
||||
EditUserComment = entry.GetNote() ?? string.Empty;
|
||||
EditNickEntry = entry.UserPair!.User.UID;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
|
||||
ImGui.SetNextItemWidth(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetCursorPosX() - buttonSizes - ImGui.GetStyle().ItemSpacing.X * 2);
|
||||
if (ImGui.InputTextWithHint("", "Nick/Notes", ref EditUserComment, 255, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
_serverManager.SetNoteForUid(entry.UserPair!.User.UID, EditUserComment);
|
||||
EditNickEntry = string.Empty;
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
EditNickEntry = string.Empty;
|
||||
}
|
||||
UiSharedService.AttachToolTip("Hit ENTER to save\nRight click to cancel");
|
||||
}
|
||||
|
||||
// Pause Button && sound warnings
|
||||
if (entry.UserPair!.OwnPermissions.IsPaired() && entry.UserPair!.OtherPermissions.IsPaired())
|
||||
{
|
||||
var individualSoundsDisabled = (entry.UserPair?.OwnPermissions.IsDisableSounds() ?? false) || (entry.UserPair?.OtherPermissions.IsDisableSounds() ?? false);
|
||||
var individualAnimDisabled = (entry.UserPair?.OwnPermissions.IsDisableAnimations() ?? false) || (entry.UserPair?.OtherPermissions.IsDisableAnimations() ?? false);
|
||||
|
||||
if (individualAnimDisabled || individualSoundsDisabled)
|
||||
{
|
||||
var infoIconPosDist = windowEndX - barButtonSize.X - spacingX - pauseIconSize.X - spacingX;
|
||||
var icon = FontAwesomeIcon.ExclamationTriangle;
|
||||
var iconwidth = UiSharedService.GetIconSize(icon);
|
||||
|
||||
ImGui.SameLine(infoIconPosDist - iconwidth.X);
|
||||
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow);
|
||||
UiSharedService.FontText(icon.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.PopStyleColor();
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.BeginTooltip();
|
||||
|
||||
ImGui.Text("Individual User permissions");
|
||||
|
||||
if (individualSoundsDisabled)
|
||||
{
|
||||
var userSoundsText = "Sound sync disabled with " + entry.UserData.AliasOrUID;
|
||||
UiSharedService.FontText(FontAwesomeIcon.VolumeOff.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text(userSoundsText);
|
||||
ImGui.NewLine();
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text("You: " + (entry.UserPair!.OwnPermissions.IsDisableSounds() ? "Disabled" : "Enabled") + ", They: " + (entry.UserPair!.OtherPermissions.IsDisableSounds() ? "Disabled" : "Enabled"));
|
||||
}
|
||||
|
||||
if (individualAnimDisabled)
|
||||
{
|
||||
var userAnimText = "Animation sync disabled with " + entry.UserData.AliasOrUID;
|
||||
UiSharedService.FontText(FontAwesomeIcon.Stop.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text(userAnimText);
|
||||
ImGui.NewLine();
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text("You: " + (entry.UserPair!.OwnPermissions.IsDisableAnimations() ? "Disabled" : "Enabled") + ", They: " + (entry.UserPair!.OtherPermissions.IsDisableAnimations() ? "Disabled" : "Enabled"));
|
||||
}
|
||||
|
||||
ImGui.EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SameLine(windowEndX - barButtonSize.X - spacingX - pauseIconSize.X);
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
if (ImGuiComponents.IconButton(pauseIcon))
|
||||
{
|
||||
var perm = entry.UserPair!.OwnPermissions;
|
||||
perm.SetPaused(!perm.IsPaused());
|
||||
_ = _apiController.UserSetPairPermissions(new(entry.UserData, perm));
|
||||
}
|
||||
UiSharedService.AttachToolTip(!entry.UserPair!.OwnPermissions.IsPaused()
|
||||
? "Pause pairing with " + entryUID
|
||||
: "Resume pairing with " + entryUID);
|
||||
}
|
||||
|
||||
// Flyout Menu
|
||||
ImGui.SameLine(windowEndX - barButtonSize.X);
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Bars))
|
||||
{
|
||||
ImGui.OpenPopup("User Flyout Menu");
|
||||
}
|
||||
if (ImGui.BeginPopup("User Flyout Menu"))
|
||||
{
|
||||
UiSharedService.DrawWithID($"buttons-{entry.UserPair!.User.UID}", () => DrawPairedClientMenu(entry));
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPairedClientMenu(Pair entry)
|
||||
{
|
||||
if (entry.IsVisible)
|
||||
@@ -624,9 +416,9 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
users.Reverse();
|
||||
}
|
||||
|
||||
var onlineUsers = users.Where(u => u.IsOnline || u.UserPair.OwnPermissions.IsPaused()).ToList();
|
||||
var visibleUsers = onlineUsers.Where(u => u.IsVisible).ToList();
|
||||
var offlineUsers = users.Except(onlineUsers).ToList();
|
||||
var onlineUsers = users.Where(u => u.IsOnline || u.UserPair!.OwnPermissions.IsPaused()).Select(c => new DrawUserPair("Online" + c.UserData.UID, c, _uidDisplayHandler, _apiController, _selectGroupForPairUi)).ToList();
|
||||
var visibleUsers = users.Where(u => u.IsVisible).Select(c => new DrawUserPair("Visible" + c.UserData.UID, c, _uidDisplayHandler, _apiController, _selectGroupForPairUi)).ToList();
|
||||
var offlineUsers = users.Where(u => !u.IsOnline && !u.UserPair!.OwnPermissions.IsPaused()).Select(c => new DrawUserPair("Offline" + c.UserData.UID, c, _uidDisplayHandler, _apiController, _selectGroupForPairUi)).ToList();
|
||||
|
||||
ImGui.BeginChild("list", new Vector2(WindowContentWidth, ySize), border: false);
|
||||
|
||||
@@ -651,7 +443,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
|
||||
if (_apiController.ServerState is ServerState.Connected)
|
||||
{
|
||||
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X) / 2 - (userSize.X + textSize.X) / 2 - ImGui.GetStyle().ItemSpacing.X / 2);
|
||||
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth()) / 2 - (userSize.X + textSize.X) / 2 - ImGui.GetStyle().ItemSpacing.X / 2);
|
||||
if (!printShard) ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextColored(ImGuiColors.ParsedGreen, userCount);
|
||||
ImGui.SameLine();
|
||||
@@ -667,17 +459,33 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
if (printShard)
|
||||
{
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().ItemSpacing.Y);
|
||||
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X) / 2 - shardTextSize.X / 2);
|
||||
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth()) / 2 - shardTextSize.X / 2);
|
||||
ImGui.TextUnformatted(shardConnection);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (printShard)
|
||||
{
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ((userSize.Y + textSize.Y) / 2 + shardTextSize.Y) / 2 - ImGui.GetStyle().ItemSpacing.Y + buttonSize.Y / 2);
|
||||
}
|
||||
var color = UiSharedService.GetBoolColor(!_serverManager.CurrentServer!.FullPause);
|
||||
var connectedIcon = !_serverManager.CurrentServer.FullPause ? FontAwesomeIcon.Link : FontAwesomeIcon.Unlink;
|
||||
|
||||
if (_apiController.ServerState is ServerState.Connected)
|
||||
{
|
||||
ImGui.SetCursorPosX(0 + ImGui.GetStyle().ItemSpacing.X);
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.UserCircle))
|
||||
{
|
||||
Mediator.Publish(new UiToggleMessage(typeof(EditProfileUi)));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Edit your Mare Profile");
|
||||
}
|
||||
|
||||
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X);
|
||||
if (printShard)
|
||||
{
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ((userSize.Y + textSize.Y) / 2 + shardTextSize.Y) / 2 - ImGui.GetStyle().ItemSpacing.Y + buttonSize.Y / 2);
|
||||
}
|
||||
var color = UiSharedService.GetBoolColor(!_serverManager.CurrentServer!.FullPause);
|
||||
var connectedIcon = !_serverManager.CurrentServer.FullPause ? FontAwesomeIcon.Link : FontAwesomeIcon.Unlink;
|
||||
|
||||
if (_apiController.ServerState is not (ServerState.Reconnecting or ServerState.Disconnecting))
|
||||
{
|
||||
|
||||
308
MareSynchronos/UI/Components/DrawGroupPair.cs
Normal file
308
MareSynchronos/UI/Components/DrawGroupPair.cs
Normal file
@@ -0,0 +1,308 @@
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Components;
|
||||
using Dalamud.Interface;
|
||||
using ImGuiNET;
|
||||
using MareSynchronos.PlayerData.Pairs;
|
||||
using MareSynchronos.API.Data.Extensions;
|
||||
using MareSynchronos.WebAPI;
|
||||
using MareSynchronos.API.Dto.User;
|
||||
using MareSynchronos.UI.Handlers;
|
||||
using MareSynchronos.API.Dto.Group;
|
||||
using MareSynchronos.API.Data.Enum;
|
||||
|
||||
namespace MareSynchronos.UI.Components;
|
||||
|
||||
public class DrawGroupPair : DrawPairBase
|
||||
{
|
||||
private readonly GroupPairFullInfoDto _fullInfoDto;
|
||||
private readonly GroupFullInfoDto _group;
|
||||
private string _banReason = string.Empty;
|
||||
private bool _banUserPopupOpen;
|
||||
private bool _showModalBanUser;
|
||||
|
||||
public DrawGroupPair(string id, Pair entry, ApiController apiController, GroupFullInfoDto group, GroupPairFullInfoDto fullInfoDto, UidDisplayHandler handler) : base(id, entry, apiController, handler)
|
||||
{
|
||||
_group = group;
|
||||
_fullInfoDto = fullInfoDto;
|
||||
}
|
||||
|
||||
protected override void DrawLeftSide(float textPosY, float originalY)
|
||||
{
|
||||
var entryUID = _pair.UserData.AliasOrUID;
|
||||
var entryIsMod = _fullInfoDto.GroupPairStatusInfo.IsModerator();
|
||||
var entryIsOwner = string.Equals(_pair.UserData.UID, _group.OwnerUID, StringComparison.Ordinal);
|
||||
var entryIsPinned = _fullInfoDto.GroupPairStatusInfo.IsPinned();
|
||||
var presenceIcon = _pair.IsVisible ? FontAwesomeIcon.Eye : (_pair.IsOnline ? FontAwesomeIcon.Link : FontAwesomeIcon.Unlink);
|
||||
var presenceColor = (_pair.IsOnline || _pair.IsVisible) ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed;
|
||||
var presenceText = entryUID + " is offline";
|
||||
|
||||
ImGui.SetCursorPosY(textPosY);
|
||||
if (_pair.IsPaused)
|
||||
{
|
||||
presenceIcon = FontAwesomeIcon.Question;
|
||||
presenceColor = ImGuiColors.DalamudGrey;
|
||||
presenceText = entryUID + " online status is unknown (paused)";
|
||||
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
UiSharedService.ColorText(FontAwesomeIcon.PauseCircle.ToIconString(), ImGuiColors.DalamudYellow);
|
||||
ImGui.PopFont();
|
||||
|
||||
UiSharedService.AttachToolTip("Pairing status with " + entryUID + " is paused");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
UiSharedService.ColorText(FontAwesomeIcon.Check.ToIconString(), ImGuiColors.ParsedGreen);
|
||||
ImGui.PopFont();
|
||||
|
||||
UiSharedService.AttachToolTip("You are paired with " + entryUID);
|
||||
}
|
||||
|
||||
if (_pair.IsOnline && !_pair.IsVisible) presenceText = entryUID + " is online";
|
||||
else if (_pair.IsOnline && _pair.IsVisible) presenceText = entryUID + " is visible: " + _pair.PlayerName;
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosY(textPosY);
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
UiSharedService.ColorText(presenceIcon.ToIconString(), presenceColor);
|
||||
ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip(presenceText);
|
||||
|
||||
if (entryIsOwner)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosY(textPosY);
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
ImGui.TextUnformatted(FontAwesomeIcon.Crown.ToIconString());
|
||||
ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip("User is owner of this Syncshell");
|
||||
}
|
||||
else if (entryIsMod)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosY(textPosY);
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
ImGui.TextUnformatted(FontAwesomeIcon.UserShield.ToIconString());
|
||||
ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip("User is moderator of this Syncshell");
|
||||
}
|
||||
else if (entryIsPinned)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosY(textPosY);
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
ImGui.TextUnformatted(FontAwesomeIcon.Thumbtack.ToIconString());
|
||||
ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip("User is pinned in this Syncshell");
|
||||
}
|
||||
}
|
||||
|
||||
protected override float DrawRightSide(float textPosY, float originalY)
|
||||
{
|
||||
var entryUID = _fullInfoDto.UserAliasOrUID;
|
||||
var entryIsMod = _fullInfoDto.GroupPairStatusInfo.IsModerator();
|
||||
var entryIsOwner = string.Equals(_pair.UserData.UID, _group.OwnerUID, StringComparison.Ordinal);
|
||||
var entryIsPinned = _fullInfoDto.GroupPairStatusInfo.IsPinned();
|
||||
var userIsOwner = string.Equals(_group.OwnerUID, _apiController.UID, StringComparison.OrdinalIgnoreCase);
|
||||
var userIsModerator = _group.GroupUserInfo.IsModerator();
|
||||
|
||||
var soundsDisabled = _fullInfoDto.GroupUserPermissions.IsDisableSounds();
|
||||
var animDisabled = _fullInfoDto.GroupUserPermissions.IsDisableAnimations();
|
||||
var individualSoundsDisabled = (_pair.UserPair?.OwnPermissions.IsDisableSounds() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableSounds() ?? false);
|
||||
var individualAnimDisabled = (_pair.UserPair?.OwnPermissions.IsDisableAnimations() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableAnimations() ?? false);
|
||||
|
||||
bool showInfo = (individualAnimDisabled || individualSoundsDisabled || animDisabled || soundsDisabled);
|
||||
bool showPlus = _pair.UserPair == null;
|
||||
bool showBars = (userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)) || !_pair.IsPaused;
|
||||
|
||||
var spacing = ImGui.GetStyle().ItemSpacing.X;
|
||||
var permIcon = (individualAnimDisabled || individualSoundsDisabled) ? FontAwesomeIcon.ExclamationTriangle
|
||||
: ((soundsDisabled || animDisabled) ? FontAwesomeIcon.InfoCircle : FontAwesomeIcon.None);
|
||||
var infoIconWidth = UiSharedService.GetIconSize(permIcon).X;
|
||||
var plusButtonWidth = UiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X;
|
||||
var barButtonWidth = UiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars).X;
|
||||
|
||||
var pos = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() + spacing
|
||||
- (showInfo ? (infoIconWidth + spacing) : 0)
|
||||
- (showPlus ? (plusButtonWidth + spacing) : 0)
|
||||
- (showBars ? (barButtonWidth + spacing) : 0);
|
||||
|
||||
ImGui.SameLine(pos);
|
||||
if (individualAnimDisabled || individualSoundsDisabled)
|
||||
{
|
||||
ImGui.SetCursorPosY(textPosY);
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow);
|
||||
UiSharedService.FontText(permIcon.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.PopStyleColor();
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.BeginTooltip();
|
||||
|
||||
ImGui.Text("Individual User permissions");
|
||||
|
||||
if (individualSoundsDisabled)
|
||||
{
|
||||
var userSoundsText = "Sound sync disabled with " + _pair.UserData.AliasOrUID;
|
||||
UiSharedService.FontText(FontAwesomeIcon.VolumeOff.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text(userSoundsText);
|
||||
ImGui.NewLine();
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text("You: " + (_pair.UserPair!.OwnPermissions.IsDisableSounds() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableSounds() ? "Disabled" : "Enabled"));
|
||||
}
|
||||
|
||||
if (individualAnimDisabled)
|
||||
{
|
||||
var userAnimText = "Animation sync disabled with " + _pair.UserData.AliasOrUID;
|
||||
UiSharedService.FontText(FontAwesomeIcon.Stop.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text(userAnimText);
|
||||
ImGui.NewLine();
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text("You: " + (_pair.UserPair!.OwnPermissions.IsDisableAnimations() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableAnimations() ? "Disabled" : "Enabled"));
|
||||
}
|
||||
|
||||
ImGui.EndTooltip();
|
||||
}
|
||||
ImGui.SameLine();
|
||||
}
|
||||
else if ((animDisabled || soundsDisabled))
|
||||
{
|
||||
ImGui.SetCursorPosY(textPosY);
|
||||
UiSharedService.FontText(permIcon.ToIconString(), UiBuilder.IconFont);
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.BeginTooltip();
|
||||
|
||||
ImGui.Text("Sycnshell User permissions");
|
||||
|
||||
if (soundsDisabled)
|
||||
{
|
||||
var userSoundsText = "Sound sync disabled by " + _pair.UserData.AliasOrUID;
|
||||
UiSharedService.FontText(FontAwesomeIcon.VolumeOff.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text(userSoundsText);
|
||||
}
|
||||
|
||||
if (animDisabled)
|
||||
{
|
||||
var userAnimText = "Animation sync disabled by " + _pair.UserData.AliasOrUID;
|
||||
UiSharedService.FontText(FontAwesomeIcon.Stop.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text(userAnimText);
|
||||
}
|
||||
|
||||
ImGui.EndTooltip();
|
||||
}
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
if (showPlus)
|
||||
{
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
|
||||
{
|
||||
_ = _apiController.UserAddPair(new UserDto(new(_pair.UserData.UID)));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Pair with " + entryUID + " individually");
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
if (showBars)
|
||||
{
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Bars))
|
||||
{
|
||||
ImGui.OpenPopup("Popup");
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.BeginPopup("Popup"))
|
||||
{
|
||||
if ((userIsModerator || userIsOwner) && !(entryIsMod || entryIsOwner))
|
||||
{
|
||||
var pinText = entryIsPinned ? "Unpin user" : "Pin user";
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Thumbtack, pinText))
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
var userInfo = _fullInfoDto.GroupPairStatusInfo ^ GroupUserInfo.IsPinned;
|
||||
_ = _apiController.GroupSetUserInfo(new GroupPairUserInfoDto(_fullInfoDto.Group, _fullInfoDto.User, userInfo));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Pin this user to the Syncshell. Pinned users will not be deleted in case of a manually initiated Syncshell clean");
|
||||
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Remove user") && UiSharedService.CtrlPressed())
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
_ = _apiController.GroupRemoveUser(_fullInfoDto);
|
||||
}
|
||||
|
||||
UiSharedService.AttachToolTip("Hold CTRL and click to remove user " + (_pair.UserData.AliasOrUID) + " from Syncshell");
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.UserSlash, "Ban User"))
|
||||
{
|
||||
_showModalBanUser = true;
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
UiSharedService.AttachToolTip("Ban user from this Syncshell");
|
||||
}
|
||||
|
||||
if (userIsOwner)
|
||||
{
|
||||
string modText = entryIsMod ? "Demod user" : "Mod user";
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.UserShield, modText) && UiSharedService.CtrlPressed())
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
var userInfo = _fullInfoDto.GroupPairStatusInfo ^ GroupUserInfo.IsModerator;
|
||||
_ = _apiController.GroupSetUserInfo(new GroupPairUserInfoDto(_fullInfoDto.Group, _fullInfoDto.User, userInfo));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Hold CTRL to change the moderator status for " + (_fullInfoDto.UserAliasOrUID) + Environment.NewLine +
|
||||
"Moderators can kick, ban/unban, pin/unpin users and clear the Syncshell.");
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Crown, "Transfer Ownership") && UiSharedService.CtrlPressed() && UiSharedService.ShiftPressed())
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
_ = _apiController.GroupChangeOwnership(_fullInfoDto);
|
||||
}
|
||||
UiSharedService.AttachToolTip("Hold CTRL and SHIFT and click to transfer ownership of this Syncshell to " + (_fullInfoDto.UserAliasOrUID) + Environment.NewLine + "WARNING: This action is irreversible.");
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
if (!_pair.IsPaused)
|
||||
{
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.ExclamationTriangle, "Report Mare Profile"))
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
_showModalReport = true;
|
||||
}
|
||||
UiSharedService.AttachToolTip("Report this users Mare Profile to the administrative team");
|
||||
}
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
if (_showModalBanUser && !_banUserPopupOpen)
|
||||
{
|
||||
ImGui.OpenPopup("Ban User");
|
||||
_banUserPopupOpen = true;
|
||||
}
|
||||
|
||||
if (!_showModalBanUser) _banUserPopupOpen = false;
|
||||
|
||||
if (ImGui.BeginPopupModal("Ban User", ref _showModalBanUser, UiSharedService.PopupWindowFlags))
|
||||
{
|
||||
UiSharedService.TextWrapped("User " + (_fullInfoDto.UserAliasOrUID) + " will be banned and removed from this Syncshell.");
|
||||
ImGui.InputTextWithHint("##banreason", "Ban Reason", ref _banReason, 255);
|
||||
if (ImGui.Button("Ban User"))
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
var reason = _banReason;
|
||||
_ = _apiController.GroupBanUser(new GroupPairDto(_group.Group, _fullInfoDto.User), reason);
|
||||
_banReason = string.Empty;
|
||||
}
|
||||
UiSharedService.TextWrapped("The reason will be displayed in the banlist. The current server-side alias if present (Vanity ID) will automatically be attached to the reason.");
|
||||
UiSharedService.SetScaledWindowSize(300);
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
return pos - spacing;
|
||||
}
|
||||
}
|
||||
84
MareSynchronos/UI/Components/DrawPairBase.cs
Normal file
84
MareSynchronos/UI/Components/DrawPairBase.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Colors;
|
||||
using ImGuiNET;
|
||||
using MareSynchronos.PlayerData.Pairs;
|
||||
using MareSynchronos.UI.Handlers;
|
||||
using MareSynchronos.WebAPI;
|
||||
|
||||
namespace MareSynchronos.UI.Components;
|
||||
|
||||
public abstract class DrawPairBase
|
||||
{
|
||||
protected static bool _showModalReport = false;
|
||||
protected readonly ApiController _apiController;
|
||||
protected Pair _pair;
|
||||
private static bool _reportPopupOpen = false;
|
||||
private static string _reportReason = string.Empty;
|
||||
private readonly UidDisplayHandler _displayHandler;
|
||||
private readonly string _id;
|
||||
|
||||
protected DrawPairBase(string id, Pair entry, ApiController apiController, UidDisplayHandler uIDDisplayHandler)
|
||||
{
|
||||
_id = id;
|
||||
_pair = entry;
|
||||
_apiController = apiController;
|
||||
_displayHandler = uIDDisplayHandler;
|
||||
}
|
||||
|
||||
public string UID => _pair.UserData.UID;
|
||||
|
||||
public void DrawPairedClient()
|
||||
{
|
||||
var originalY = ImGui.GetCursorPosY();
|
||||
var pauseIconSize = UiSharedService.GetIconButtonSize(FontAwesomeIcon.Play);
|
||||
var textSize = ImGui.CalcTextSize(_pair.UserData.AliasOrUID);
|
||||
|
||||
var textPosY = originalY + pauseIconSize.Y / 2 - textSize.Y / 2;
|
||||
DrawLeftSide(textPosY, originalY);
|
||||
ImGui.SameLine();
|
||||
var posX = ImGui.GetCursorPosX();
|
||||
var rightSide = DrawRightSide(textPosY, originalY);
|
||||
DrawName(originalY, posX, rightSide);
|
||||
|
||||
if (_showModalReport && !_reportPopupOpen)
|
||||
{
|
||||
ImGui.OpenPopup("Report Profile");
|
||||
_reportPopupOpen = true;
|
||||
}
|
||||
|
||||
if (!_showModalReport) _reportPopupOpen = false;
|
||||
|
||||
if (ImGui.BeginPopupModal("Report Profile", ref _showModalReport, UiSharedService.PopupWindowFlags))
|
||||
{
|
||||
UiSharedService.TextWrapped("Report " + (_pair.UserData.AliasOrUID) + " Mare Profile");
|
||||
ImGui.InputTextMultiline("##reportReason", ref _reportReason, 500, new System.Numerics.Vector2(500 - ImGui.GetStyle().ItemSpacing.X * 2, 200));
|
||||
UiSharedService.TextWrapped($"Note: Sending a report will disable the offending profile globally.{Environment.NewLine}" +
|
||||
$"The report will be sent to the team of your currently connected Mare Synchronos Service.{Environment.NewLine}" +
|
||||
$"The report will include your user and your contact info (Discord User).{Environment.NewLine}" +
|
||||
$"Depending on the severity of the offense the users Mare profile or account can be permanently disabled or banned.");
|
||||
UiSharedService.ColorTextWrapped("Report spam and wrong reports will not be tolerated and can lead to permanent account suspension.", ImGuiColors.DalamudRed);
|
||||
if (string.IsNullOrEmpty(_reportReason)) ImGui.BeginDisabled();
|
||||
if (ImGui.Button("Send Report"))
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
var reason = _reportReason;
|
||||
_ = _apiController.UserReportProfile(new(_pair.UserData, reason));
|
||||
_reportReason = string.Empty;
|
||||
_showModalReport = false;
|
||||
_reportPopupOpen = false;
|
||||
}
|
||||
if (string.IsNullOrEmpty(_reportReason)) ImGui.EndDisabled();
|
||||
UiSharedService.SetScaledWindowSize(500);
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void DrawLeftSide(float textPosY, float originalY);
|
||||
|
||||
protected abstract float DrawRightSide(float textPosY, float originalY);
|
||||
|
||||
private void DrawName(float originalY, float leftSide, float rightSide)
|
||||
{
|
||||
_displayHandler.DrawPairText(_id, _pair, leftSide, originalY, () => rightSide - leftSide);
|
||||
}
|
||||
}
|
||||
222
MareSynchronos/UI/Components/DrawUserPair.cs
Normal file
222
MareSynchronos/UI/Components/DrawUserPair.cs
Normal file
@@ -0,0 +1,222 @@
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Components;
|
||||
using Dalamud.Interface;
|
||||
using ImGuiNET;
|
||||
using MareSynchronos.PlayerData.Pairs;
|
||||
using System.Numerics;
|
||||
using MareSynchronos.API.Data.Extensions;
|
||||
using MareSynchronos.WebAPI;
|
||||
using MareSynchronos.API.Dto.User;
|
||||
using MareSynchronos.UI.Handlers;
|
||||
|
||||
namespace MareSynchronos.UI.Components;
|
||||
|
||||
public class DrawUserPair : DrawPairBase
|
||||
{
|
||||
private readonly SelectGroupForPairUi _selectGroupForPairUi;
|
||||
|
||||
public DrawUserPair(string id, Pair entry, UidDisplayHandler displayHandler, ApiController apiController, SelectGroupForPairUi selectGroupForPairUi) : base(id, entry, apiController, displayHandler)
|
||||
{
|
||||
if (_pair.UserPair == null) throw new ArgumentException("Pair must be UserPair", nameof(entry));
|
||||
_pair = entry;
|
||||
_selectGroupForPairUi = selectGroupForPairUi;
|
||||
}
|
||||
|
||||
public bool IsOnline => _pair.IsOnline;
|
||||
public bool IsVisible => _pair.IsVisible;
|
||||
public UserPairDto UserPair => _pair.UserPair!;
|
||||
|
||||
protected override void DrawLeftSide(float textPos, float originalY)
|
||||
{
|
||||
FontAwesomeIcon connectionIcon;
|
||||
Vector4 connectionColor;
|
||||
string connectionText;
|
||||
if (!(_pair.UserPair!.OwnPermissions.IsPaired() && _pair.UserPair!.OtherPermissions.IsPaired()))
|
||||
{
|
||||
connectionIcon = FontAwesomeIcon.ArrowUp;
|
||||
connectionText = _pair.UserData.AliasOrUID + " has not added you back";
|
||||
connectionColor = ImGuiColors.DalamudRed;
|
||||
}
|
||||
else if (_pair.UserPair!.OwnPermissions.IsPaused() || _pair.UserPair!.OtherPermissions.IsPaused())
|
||||
{
|
||||
connectionIcon = FontAwesomeIcon.PauseCircle;
|
||||
connectionText = "Pairing status with " + _pair.UserData.AliasOrUID + " is paused";
|
||||
connectionColor = ImGuiColors.DalamudYellow;
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionIcon = FontAwesomeIcon.Check;
|
||||
connectionText = "You are paired with " + _pair.UserData.AliasOrUID;
|
||||
connectionColor = ImGuiColors.ParsedGreen;
|
||||
}
|
||||
|
||||
ImGui.SetCursorPosY(textPos);
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
UiSharedService.ColorText(connectionIcon.ToIconString(), connectionColor);
|
||||
ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip(connectionText);
|
||||
if (_pair is { IsOnline: true, IsVisible: true })
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosY(textPos);
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
UiSharedService.ColorText(FontAwesomeIcon.Eye.ToIconString(), ImGuiColors.ParsedGreen);
|
||||
ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip(_pair.UserData.AliasOrUID + " is visible: " + _pair.PlayerName!);
|
||||
}
|
||||
}
|
||||
|
||||
protected override float DrawRightSide(float textPosY, float originalY)
|
||||
{
|
||||
var pauseIcon = _pair.UserPair!.OwnPermissions.IsPaused() ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
|
||||
var pauseIconSize = UiSharedService.GetIconButtonSize(pauseIcon);
|
||||
var barButtonSize = UiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars);
|
||||
var entryUID = _pair.UserData.AliasOrUID;
|
||||
var spacingX = ImGui.GetStyle().ItemSpacing.X;
|
||||
var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth();
|
||||
var rightSideStart = 0f;
|
||||
|
||||
if (_pair.UserPair!.OwnPermissions.IsPaired() && _pair.UserPair!.OtherPermissions.IsPaired())
|
||||
{
|
||||
var individualSoundsDisabled = (_pair.UserPair?.OwnPermissions.IsDisableSounds() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableSounds() ?? false);
|
||||
var individualAnimDisabled = (_pair.UserPair?.OwnPermissions.IsDisableAnimations() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableAnimations() ?? false);
|
||||
|
||||
if (individualAnimDisabled || individualSoundsDisabled)
|
||||
{
|
||||
var infoIconPosDist = windowEndX - barButtonSize.X - spacingX - pauseIconSize.X - spacingX;
|
||||
var icon = FontAwesomeIcon.ExclamationTriangle;
|
||||
var iconwidth = UiSharedService.GetIconSize(icon);
|
||||
|
||||
rightSideStart = infoIconPosDist - iconwidth.X;
|
||||
ImGui.SameLine(infoIconPosDist - iconwidth.X);
|
||||
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow);
|
||||
UiSharedService.FontText(icon.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.PopStyleColor();
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.BeginTooltip();
|
||||
|
||||
ImGui.Text("Individual User permissions");
|
||||
|
||||
if (individualSoundsDisabled)
|
||||
{
|
||||
var userSoundsText = "Sound sync disabled with " + _pair.UserData.AliasOrUID;
|
||||
UiSharedService.FontText(FontAwesomeIcon.VolumeOff.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text(userSoundsText);
|
||||
ImGui.NewLine();
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text("You: " + (_pair.UserPair!.OwnPermissions.IsDisableSounds() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableSounds() ? "Disabled" : "Enabled"));
|
||||
}
|
||||
|
||||
if (individualAnimDisabled)
|
||||
{
|
||||
var userAnimText = "Animation sync disabled with " + _pair.UserData.AliasOrUID;
|
||||
UiSharedService.FontText(FontAwesomeIcon.Stop.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text(userAnimText);
|
||||
ImGui.NewLine();
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text("You: " + (_pair.UserPair!.OwnPermissions.IsDisableAnimations() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableAnimations() ? "Disabled" : "Enabled"));
|
||||
}
|
||||
|
||||
ImGui.EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
if (rightSideStart == 0f)
|
||||
{
|
||||
rightSideStart = windowEndX - barButtonSize.X - spacingX * 2 - pauseIconSize.X;
|
||||
}
|
||||
ImGui.SameLine(windowEndX - barButtonSize.X - spacingX - pauseIconSize.X);
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
if (ImGuiComponents.IconButton(pauseIcon))
|
||||
{
|
||||
var perm = _pair.UserPair!.OwnPermissions;
|
||||
perm.SetPaused(!perm.IsPaused());
|
||||
_ = _apiController.UserSetPairPermissions(new(_pair.UserData, perm));
|
||||
}
|
||||
UiSharedService.AttachToolTip(!_pair.UserPair!.OwnPermissions.IsPaused()
|
||||
? "Pause pairing with " + entryUID
|
||||
: "Resume pairing with " + entryUID);
|
||||
}
|
||||
|
||||
// Flyout Menu
|
||||
if (rightSideStart == 0f)
|
||||
{
|
||||
rightSideStart = windowEndX - barButtonSize.X;
|
||||
}
|
||||
ImGui.SameLine(windowEndX - barButtonSize.X);
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Bars))
|
||||
{
|
||||
ImGui.OpenPopup("User Flyout Menu");
|
||||
}
|
||||
if (ImGui.BeginPopup("User Flyout Menu"))
|
||||
{
|
||||
UiSharedService.DrawWithID($"buttons-{_pair.UserData.UID}", () => DrawPairedClientMenu(_pair));
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
return rightSideStart;
|
||||
}
|
||||
|
||||
private void DrawPairedClientMenu(Pair entry)
|
||||
{
|
||||
if (entry.IsVisible)
|
||||
{
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Sync, "Reload last data"))
|
||||
{
|
||||
entry.ApplyLastReceivedData(forced: true);
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
UiSharedService.AttachToolTip("This reapplies the last received character data to this character");
|
||||
}
|
||||
|
||||
var entryUID = entry.UserData.AliasOrUID;
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Folder, "Pair Groups"))
|
||||
{
|
||||
_selectGroupForPairUi.Open(entry);
|
||||
}
|
||||
UiSharedService.AttachToolTip("Choose pair groups for " + entryUID);
|
||||
|
||||
var isDisableSounds = entry.UserPair!.OwnPermissions.IsDisableSounds();
|
||||
string disableSoundsText = isDisableSounds ? "Enable sound sync" : "Disable sound sync";
|
||||
var disableSoundsIcon = isDisableSounds ? FontAwesomeIcon.VolumeUp : FontAwesomeIcon.VolumeMute;
|
||||
if (UiSharedService.IconTextButton(disableSoundsIcon, disableSoundsText))
|
||||
{
|
||||
var permissions = entry.UserPair.OwnPermissions;
|
||||
permissions.SetDisableSounds(!isDisableSounds);
|
||||
_ = _apiController.UserSetPairPermissions(new UserPermissionsDto(entry.UserData, permissions));
|
||||
}
|
||||
|
||||
var isDisableAnims = entry.UserPair!.OwnPermissions.IsDisableAnimations();
|
||||
string disableAnimsText = isDisableAnims ? "Enable animation sync" : "Disable animation sync";
|
||||
var disableAnimsIcon = isDisableAnims ? FontAwesomeIcon.Running : FontAwesomeIcon.Stop;
|
||||
if (UiSharedService.IconTextButton(disableAnimsIcon, disableAnimsText))
|
||||
{
|
||||
var permissions = entry.UserPair.OwnPermissions;
|
||||
permissions.SetDisableAnimations(!isDisableAnims);
|
||||
_ = _apiController.UserSetPairPermissions(new UserPermissionsDto(entry.UserData, permissions));
|
||||
}
|
||||
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Unpair Permanently") && UiSharedService.CtrlPressed())
|
||||
{
|
||||
_ = _apiController.UserRemovePair(new(entry.UserData));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Hold CTRL and click to unpair permanently from " + entryUID);
|
||||
|
||||
ImGui.Separator();
|
||||
if (!entry.IsPaused)
|
||||
{
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.ExclamationTriangle, "Report Mare Profile"))
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
_showModalReport = true;
|
||||
}
|
||||
UiSharedService.AttachToolTip("Report this users Mare Profile to the administrative team");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Components;
|
||||
using Dalamud.Interface.Components;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Utility;
|
||||
using ImGuiNET;
|
||||
@@ -8,28 +7,26 @@ using System.Numerics;
|
||||
using System.Globalization;
|
||||
using MareSynchronos.API.Data;
|
||||
using MareSynchronos.API.Dto.Group;
|
||||
using MareSynchronos.API.Dto.User;
|
||||
using MareSynchronos.API.Data.Enum;
|
||||
using MareSynchronos.API.Data.Extensions;
|
||||
using MareSynchronos.API.Data.Comparer;
|
||||
using MareSynchronos.MareConfiguration;
|
||||
using MareSynchronos.PlayerData.Pairs;
|
||||
using MareSynchronos.Services.ServerConfiguration;
|
||||
using MareSynchronos.UI.Components;
|
||||
using MareSynchronos.UI.Handlers;
|
||||
|
||||
namespace MareSynchronos.UI;
|
||||
|
||||
internal sealed class GroupPanel
|
||||
{
|
||||
private readonly MareConfigService _configService;
|
||||
private readonly Dictionary<string, bool> _expandedGroupState = new(StringComparer.Ordinal);
|
||||
private readonly CompactUi _mainUi;
|
||||
private readonly PairManager _pairManager;
|
||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||
private readonly Dictionary<string, bool> _showGidForEntry = new(StringComparer.Ordinal);
|
||||
private readonly UidDisplayHandler _uidDisplayHandler;
|
||||
private readonly UiSharedService _uiShared;
|
||||
private List<BannedGroupUserDto> _bannedUsers = new();
|
||||
private string _banReason = string.Empty;
|
||||
private bool _banUserPopupOpen;
|
||||
private int _bulkInviteCount = 10;
|
||||
private List<string> _bulkOneTimeInvites = new();
|
||||
private string _editGroupComment = string.Empty;
|
||||
@@ -43,7 +40,6 @@ internal sealed class GroupPanel
|
||||
private bool _modalChangePwOpened;
|
||||
private string _newSyncShellPassword = string.Empty;
|
||||
private bool _showModalBanList = false;
|
||||
private bool _showModalBanUser;
|
||||
private bool _showModalBulkOneTimeInvites = false;
|
||||
private bool _showModalChangePassword;
|
||||
private bool _showModalCreateGroup;
|
||||
@@ -51,13 +47,13 @@ internal sealed class GroupPanel
|
||||
private string _syncShellPassword = string.Empty;
|
||||
private string _syncShellToJoin = string.Empty;
|
||||
|
||||
public GroupPanel(CompactUi mainUi, UiSharedService uiShared, PairManager pairManager, ServerConfigurationManager serverConfigurationManager, MareConfigService configurationService)
|
||||
public GroupPanel(CompactUi mainUi, UiSharedService uiShared, PairManager pairManager, UidDisplayHandler uidDisplayHandler, ServerConfigurationManager serverConfigurationManager)
|
||||
{
|
||||
_mainUi = mainUi;
|
||||
_uiShared = uiShared;
|
||||
_pairManager = pairManager;
|
||||
_uidDisplayHandler = uidDisplayHandler;
|
||||
_serverConfigurationManager = serverConfigurationManager;
|
||||
_configService = configurationService;
|
||||
}
|
||||
|
||||
private ApiController ApiController => _uiShared.ApiController;
|
||||
@@ -406,18 +402,24 @@ internal sealed class GroupPanel
|
||||
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsModerator())
|
||||
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsPinned())
|
||||
.ThenBy(u => u.GetNote() ?? u.UserData.AliasOrUID, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(c => new DrawGroupPair(groupDto.GID + c.UserData.UID, c, ApiController, groupDto, c.GroupPair.Single(g => GroupDataComparer.Instance.Equals(g.Key.Group, groupDto.Group)).Value,
|
||||
_uidDisplayHandler))
|
||||
.ToList();
|
||||
var onlineUsers = pairsInGroup.Where(u => u.IsOnline && !u.IsVisible)
|
||||
.OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal))
|
||||
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsModerator())
|
||||
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsPinned())
|
||||
.ThenBy(u => u.GetNote() ?? u.UserData.AliasOrUID, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(c => new DrawGroupPair(groupDto.GID + c.UserData.UID, c, ApiController, groupDto, c.GroupPair.Single(g => GroupDataComparer.Instance.Equals(g.Key.Group, groupDto.Group)).Value,
|
||||
_uidDisplayHandler))
|
||||
.ToList();
|
||||
var offlineUsers = pairsInGroup.Where(u => !u.IsOnline && !u.IsVisible)
|
||||
.OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal))
|
||||
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsModerator())
|
||||
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsPinned())
|
||||
.ThenBy(u => u.GetNote() ?? u.UserData.AliasOrUID, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(c => new DrawGroupPair(groupDto.GID + c.UserData.UID, c, ApiController, groupDto, c.GroupPair.Single(g => GroupDataComparer.Instance.Equals(g.Key.Group, groupDto.Group)).Value,
|
||||
_uidDisplayHandler))
|
||||
.ToList();
|
||||
|
||||
if (visibleUsers.Any())
|
||||
@@ -426,12 +428,7 @@ internal sealed class GroupPanel
|
||||
ImGui.Separator();
|
||||
foreach (var entry in visibleUsers)
|
||||
{
|
||||
UiSharedService.DrawWithID(groupDto.GID + entry.UserData.UID, () => DrawSyncshellPairedClient(
|
||||
entry,
|
||||
entry.GroupPair.Single(g => GroupDataComparer.Instance.Equals(g.Key.Group, groupDto.Group)).Value,
|
||||
groupDto.OwnerUID,
|
||||
string.Equals(groupDto.OwnerUID, ApiController.UID, StringComparison.Ordinal),
|
||||
groupDto.GroupUserInfo.IsModerator()));
|
||||
UiSharedService.DrawWithID(groupDto.GID + entry.UID, () => entry.DrawPairedClient());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,12 +438,7 @@ internal sealed class GroupPanel
|
||||
ImGui.Separator();
|
||||
foreach (var entry in onlineUsers)
|
||||
{
|
||||
UiSharedService.DrawWithID(groupDto.GID + entry.UserData.UID, () => DrawSyncshellPairedClient(
|
||||
entry,
|
||||
entry.GroupPair.Single(g => GroupDataComparer.Instance.Equals(g.Key.Group, groupDto.Group)).Value,
|
||||
groupDto.OwnerUID,
|
||||
string.Equals(groupDto.OwnerUID, ApiController.UID, StringComparison.Ordinal),
|
||||
groupDto.GroupUserInfo.IsModerator()));
|
||||
UiSharedService.DrawWithID(groupDto.GID + entry.UID, () => entry.DrawPairedClient());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,12 +448,7 @@ internal sealed class GroupPanel
|
||||
ImGui.Separator();
|
||||
foreach (var entry in offlineUsers)
|
||||
{
|
||||
UiSharedService.DrawWithID(groupDto.GID + entry.UserData.UID, () => DrawSyncshellPairedClient(
|
||||
entry,
|
||||
entry.GroupPair.Single(g => GroupDataComparer.Instance.Equals(g.Key.Group, groupDto.Group)).Value,
|
||||
groupDto.OwnerUID,
|
||||
string.Equals(groupDto.OwnerUID, ApiController.UID, StringComparison.Ordinal),
|
||||
groupDto.GroupUserInfo.IsModerator()));
|
||||
UiSharedService.DrawWithID(groupDto.GID + entry.UID, () => entry.DrawPairedClient());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -724,337 +711,4 @@ internal sealed class GroupPanel
|
||||
}
|
||||
ImGui.EndChild();
|
||||
}
|
||||
|
||||
private void DrawSyncshellPairedClient(Pair pair, GroupPairFullInfoDto entry, string ownerUid, bool userIsOwner, bool userIsModerator)
|
||||
{
|
||||
var plusButtonSize = UiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus);
|
||||
var barButtonSize = UiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars);
|
||||
var entryUID = entry.UserAliasOrUID;
|
||||
var textSize = ImGui.CalcTextSize(entryUID);
|
||||
var originalY = ImGui.GetCursorPosY();
|
||||
var entryIsMod = entry.GroupPairStatusInfo.IsModerator();
|
||||
var entryIsOwner = string.Equals(pair.UserData.UID, ownerUid, StringComparison.Ordinal);
|
||||
var entryIsPinned = entry.GroupPairStatusInfo.IsPinned();
|
||||
var presenceIcon = pair.IsVisible ? FontAwesomeIcon.Eye : (pair.IsOnline ? FontAwesomeIcon.Link : FontAwesomeIcon.Unlink);
|
||||
var presenceColor = (pair.IsOnline || pair.IsVisible) ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed;
|
||||
var presenceText = entryUID + " is offline";
|
||||
|
||||
var soundsDisabled = entry.GroupUserPermissions.IsDisableSounds();
|
||||
var animDisabled = entry.GroupUserPermissions.IsDisableAnimations();
|
||||
var individualSoundsDisabled = (pair.UserPair?.OwnPermissions.IsDisableSounds() ?? false) || (pair.UserPair?.OtherPermissions.IsDisableSounds() ?? false);
|
||||
var individualAnimDisabled = (pair.UserPair?.OwnPermissions.IsDisableAnimations() ?? false) || (pair.UserPair?.OtherPermissions.IsDisableAnimations() ?? false);
|
||||
|
||||
var textPos = originalY + barButtonSize.Y / 2 - textSize.Y / 2;
|
||||
ImGui.SetCursorPosY(textPos);
|
||||
if (pair.IsPaused)
|
||||
{
|
||||
presenceIcon = FontAwesomeIcon.Question;
|
||||
presenceColor = ImGuiColors.DalamudGrey;
|
||||
presenceText = entryUID + " online status is unknown (paused)";
|
||||
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
UiSharedService.ColorText(FontAwesomeIcon.PauseCircle.ToIconString(), ImGuiColors.DalamudYellow);
|
||||
ImGui.PopFont();
|
||||
|
||||
UiSharedService.AttachToolTip("Pairing status with " + entryUID + " is paused");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
UiSharedService.ColorText(FontAwesomeIcon.Check.ToIconString(), ImGuiColors.ParsedGreen);
|
||||
ImGui.PopFont();
|
||||
|
||||
UiSharedService.AttachToolTip("You are paired with " + entryUID);
|
||||
}
|
||||
|
||||
if (pair.IsOnline && !pair.IsVisible) presenceText = entryUID + " is online";
|
||||
else if (pair.IsOnline && pair.IsVisible) presenceText = entryUID + " is visible: " + pair.PlayerName;
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosY(textPos);
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
UiSharedService.ColorText(presenceIcon.ToIconString(), presenceColor);
|
||||
ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip(presenceText);
|
||||
|
||||
if (entryIsOwner)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosY(textPos);
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
ImGui.TextUnformatted(FontAwesomeIcon.Crown.ToIconString());
|
||||
ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip("User is owner of this Syncshell");
|
||||
}
|
||||
else if (entryIsMod)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosY(textPos);
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
ImGui.TextUnformatted(FontAwesomeIcon.UserShield.ToIconString());
|
||||
ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip("User is moderator of this Syncshell");
|
||||
}
|
||||
else if (entryIsPinned)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosY(textPos);
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
ImGui.TextUnformatted(FontAwesomeIcon.Thumbtack.ToIconString());
|
||||
ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip("User is pinned in this Syncshell");
|
||||
}
|
||||
|
||||
var textIsUid = true;
|
||||
_mainUi.ShowUidForEntry.TryGetValue(entry.UID, out var showUidInsteadOfName);
|
||||
var playerText = _serverConfigurationManager.GetNoteForUid(entry.UID);
|
||||
if (showUidInsteadOfName || string.IsNullOrEmpty(playerText))
|
||||
{
|
||||
playerText = entryUID;
|
||||
}
|
||||
else
|
||||
{
|
||||
textIsUid = false;
|
||||
}
|
||||
|
||||
if (_configService.Current.ShowCharacterNameInsteadOfNotesForVisible && pair.IsVisible && !showUidInsteadOfName)
|
||||
{
|
||||
playerText = pair.PlayerName;
|
||||
textIsUid = false;
|
||||
}
|
||||
|
||||
bool plusButtonShown = !_pairManager.DirectPairs.Any(p => string.Equals(p.UserData.UID, entry.UID, StringComparison.Ordinal));
|
||||
|
||||
ImGui.SameLine();
|
||||
if (!string.Equals(_mainUi.EditNickEntry, entry.UID, StringComparison.Ordinal))
|
||||
{
|
||||
ImGui.SetCursorPosY(textPos);
|
||||
if (textIsUid) ImGui.PushFont(UiBuilder.MonoFont);
|
||||
ImGui.TextUnformatted(playerText);
|
||||
if (textIsUid) ImGui.PopFont();
|
||||
UiSharedService.AttachToolTip("Left click to switch between UID display and nick" + Environment.NewLine +
|
||||
"Right click to change nick for " + entryUID);
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
|
||||
{
|
||||
var prevState = textIsUid;
|
||||
if (_mainUi.ShowUidForEntry.ContainsKey(entry.UID))
|
||||
{
|
||||
prevState = _mainUi.ShowUidForEntry[entry.UID];
|
||||
}
|
||||
|
||||
_mainUi.ShowUidForEntry[entry.UID] = !prevState;
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_serverConfigurationManager.SetNoteForUid(_mainUi.EditNickEntry, _mainUi.EditUserComment);
|
||||
_mainUi.EditUserComment = _serverConfigurationManager.GetNoteForUid(entry.UID) ?? string.Empty;
|
||||
_mainUi.EditNickEntry = entry.UID;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
var buttonSizes = (plusButtonShown ? plusButtonSize.X : 0) + barButtonSize.X;
|
||||
var buttons = plusButtonShown ? 2 : 1;
|
||||
|
||||
ImGui.SetNextItemWidth(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetCursorPosX() - buttonSizes - ImGui.GetStyle().ItemSpacing.X * buttons);
|
||||
if (ImGui.InputTextWithHint("", "Nick/Notes", ref _mainUi.EditUserComment, 255, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
_serverConfigurationManager.SetNoteForUid(entry.UID, _mainUi.EditUserComment);
|
||||
_mainUi.EditNickEntry = string.Empty;
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_mainUi.EditNickEntry = string.Empty;
|
||||
}
|
||||
UiSharedService.AttachToolTip("Hit ENTER to save\nRight click to cancel");
|
||||
}
|
||||
|
||||
if (plusButtonShown)
|
||||
{
|
||||
var barWidth = userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)
|
||||
? barButtonSize.X + ImGui.GetStyle().ItemSpacing.X
|
||||
: 0;
|
||||
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - plusButtonSize.X - barWidth);
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
|
||||
{
|
||||
_ = ApiController.UserAddPair(new UserDto(entry.User));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Pair with " + entryUID + " individually");
|
||||
}
|
||||
|
||||
if (userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner))
|
||||
{
|
||||
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - barButtonSize.X);
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Bars))
|
||||
{
|
||||
ImGui.OpenPopup("Popup");
|
||||
}
|
||||
}
|
||||
|
||||
if (individualAnimDisabled || individualSoundsDisabled)
|
||||
{
|
||||
var infoIconPosDist = (plusButtonShown ? plusButtonSize.X + ImGui.GetStyle().ItemSpacing.X : 0)
|
||||
+ ((userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)) ? barButtonSize.X + ImGui.GetStyle().ItemSpacing.X : 0);
|
||||
var icon = FontAwesomeIcon.ExclamationTriangle;
|
||||
var iconwidth = UiSharedService.GetIconSize(icon);
|
||||
|
||||
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - infoIconPosDist - iconwidth.X);
|
||||
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow);
|
||||
UiSharedService.FontText(icon.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.PopStyleColor();
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.BeginTooltip();
|
||||
|
||||
ImGui.Text("Individual User permissions");
|
||||
|
||||
if (individualSoundsDisabled)
|
||||
{
|
||||
var userSoundsText = "Sound sync disabled with " + pair.UserData.AliasOrUID;
|
||||
UiSharedService.FontText(FontAwesomeIcon.VolumeOff.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text(userSoundsText);
|
||||
ImGui.NewLine();
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text("You: " + (pair.UserPair!.OwnPermissions.IsDisableSounds() ? "Disabled" : "Enabled") + ", They: " + (pair.UserPair!.OtherPermissions.IsDisableSounds() ? "Disabled" : "Enabled"));
|
||||
}
|
||||
|
||||
if (individualAnimDisabled)
|
||||
{
|
||||
var userAnimText = "Animation sync disabled with " + pair.UserData.AliasOrUID;
|
||||
UiSharedService.FontText(FontAwesomeIcon.Stop.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text(userAnimText);
|
||||
ImGui.NewLine();
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text("You: " + (pair.UserPair!.OwnPermissions.IsDisableAnimations() ? "Disabled" : "Enabled") + ", They: " + (pair.UserPair!.OtherPermissions.IsDisableAnimations() ? "Disabled" : "Enabled"));
|
||||
}
|
||||
|
||||
ImGui.EndTooltip();
|
||||
}
|
||||
}
|
||||
else if ((animDisabled || soundsDisabled))
|
||||
{
|
||||
var infoIconPosDist = (plusButtonShown ? plusButtonSize.X + ImGui.GetStyle().ItemSpacing.X : 0)
|
||||
+ ((userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)) ? barButtonSize.X + ImGui.GetStyle().ItemSpacing.X : 0);
|
||||
var icon = FontAwesomeIcon.InfoCircle;
|
||||
var iconwidth = UiSharedService.GetIconSize(icon);
|
||||
|
||||
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - infoIconPosDist - iconwidth.X);
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
|
||||
UiSharedService.FontText(icon.ToIconString(), UiBuilder.IconFont);
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.BeginTooltip();
|
||||
|
||||
ImGui.Text("Sycnshell User permissions");
|
||||
|
||||
if (soundsDisabled)
|
||||
{
|
||||
var userSoundsText = "Sound sync disabled by " + pair.UserData.AliasOrUID;
|
||||
UiSharedService.FontText(FontAwesomeIcon.VolumeOff.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text(userSoundsText);
|
||||
}
|
||||
|
||||
if (animDisabled)
|
||||
{
|
||||
var userAnimText = "Animation sync disabled by " + pair.UserData.AliasOrUID;
|
||||
UiSharedService.FontText(FontAwesomeIcon.Stop.ToIconString(), UiBuilder.IconFont);
|
||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Text(userAnimText);
|
||||
}
|
||||
|
||||
ImGui.EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
if (!plusButtonShown && !(userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)))
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.Dummy(barButtonSize with { X = 0 });
|
||||
}
|
||||
|
||||
if (ImGui.BeginPopup("Popup"))
|
||||
{
|
||||
if ((userIsModerator || userIsOwner) && !(entryIsMod || entryIsOwner))
|
||||
{
|
||||
var pinText = entryIsPinned ? "Unpin user" : "Pin user";
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Thumbtack, pinText))
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
var userInfo = entry.GroupPairStatusInfo ^ GroupUserInfo.IsPinned;
|
||||
_ = ApiController.GroupSetUserInfo(new GroupPairUserInfoDto(entry.Group, entry.User, userInfo));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Pin this user to the Syncshell. Pinned users will not be deleted in case of a manually initiated Syncshell clean");
|
||||
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Remove user") && UiSharedService.CtrlPressed())
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
_ = ApiController.GroupRemoveUser(entry);
|
||||
}
|
||||
|
||||
UiSharedService.AttachToolTip("Hold CTRL and click to remove user " + (entry.UserAliasOrUID) + " from Syncshell");
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.UserSlash, "Ban User"))
|
||||
{
|
||||
_showModalBanUser = true;
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
UiSharedService.AttachToolTip("Ban user from this Syncshell");
|
||||
}
|
||||
|
||||
if (userIsOwner)
|
||||
{
|
||||
string modText = entryIsMod ? "Demod user" : "Mod user";
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.UserShield, modText) && UiSharedService.CtrlPressed())
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
var userInfo = entry.GroupPairStatusInfo ^ GroupUserInfo.IsModerator;
|
||||
_ = ApiController.GroupSetUserInfo(new GroupPairUserInfoDto(entry.Group, entry.User, userInfo));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Hold CTRL to change the moderator status for " + (entry.UserAliasOrUID) + Environment.NewLine +
|
||||
"Moderators can kick, ban/unban, pin/unpin users and clear the Syncshell.");
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Crown, "Transfer Ownership") && UiSharedService.CtrlPressed() && UiSharedService.ShiftPressed())
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
_ = ApiController.GroupChangeOwnership(entry);
|
||||
}
|
||||
UiSharedService.AttachToolTip("Hold CTRL and SHIFT and click to transfer ownership of this Syncshell to " + (entry.UserAliasOrUID) + Environment.NewLine + "WARNING: This action is irreversible.");
|
||||
}
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
if (_showModalBanUser && !_banUserPopupOpen)
|
||||
{
|
||||
ImGui.OpenPopup("Ban User");
|
||||
_banUserPopupOpen = true;
|
||||
}
|
||||
|
||||
if (!_showModalBanUser) _banUserPopupOpen = false;
|
||||
|
||||
if (ImGui.BeginPopupModal("Ban User", ref _showModalBanUser, UiSharedService.PopupWindowFlags))
|
||||
{
|
||||
UiSharedService.TextWrapped("User " + (entry.UserAliasOrUID) + " will be banned and removed from this Syncshell.");
|
||||
ImGui.InputTextWithHint("##banreason", "Ban Reason", ref _banReason, 255);
|
||||
if (ImGui.Button("Ban User"))
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
var reason = _banReason;
|
||||
_ = ApiController.GroupBanUser(entry, reason);
|
||||
_banReason = string.Empty;
|
||||
}
|
||||
UiSharedService.TextWrapped("The reason will be displayed in the banlist. The current server-side alias if present (Vanity ID) will automatically be attached to the reason.");
|
||||
UiSharedService.SetScaledWindowSize(300);
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ using Dalamud.Interface.Components;
|
||||
using ImGuiNET;
|
||||
using MareSynchronos.API.Data.Extensions;
|
||||
using MareSynchronos.MareConfiguration;
|
||||
using MareSynchronos.PlayerData.Pairs;
|
||||
using MareSynchronos.UI.Handlers;
|
||||
using MareSynchronos.WebAPI;
|
||||
|
||||
@@ -12,58 +11,31 @@ namespace MareSynchronos.UI.Components;
|
||||
public class PairGroupsUi
|
||||
{
|
||||
private readonly ApiController _apiController;
|
||||
private readonly Action<Pair> _clientRenderFn;
|
||||
private readonly MareConfigService _mareConfig;
|
||||
private readonly SelectPairForGroupUi _selectGroupForPairUi;
|
||||
private readonly TagHandler _tagHandler;
|
||||
|
||||
public PairGroupsUi(MareConfigService mareConfig, TagHandler tagHandler, Action<Pair> clientRenderFn, ApiController apiController, SelectPairForGroupUi selectGroupForPairUi)
|
||||
public PairGroupsUi(MareConfigService mareConfig, TagHandler tagHandler, ApiController apiController, SelectPairForGroupUi selectGroupForPairUi)
|
||||
{
|
||||
_clientRenderFn = clientRenderFn;
|
||||
_mareConfig = mareConfig;
|
||||
_tagHandler = tagHandler;
|
||||
_apiController = apiController;
|
||||
_selectGroupForPairUi = selectGroupForPairUi;
|
||||
}
|
||||
|
||||
public void Draw(List<Pair> visibleUsers, List<Pair> onlineUsers, List<Pair> offlineUsers)
|
||||
public void Draw<T>(List<T> visibleUsers, List<T> onlineUsers, List<T> offlineUsers) where T : DrawPairBase
|
||||
{
|
||||
// Only render those tags that actually have pairs in them, otherwise
|
||||
// we can end up with a bunch of useless pair groups
|
||||
var tagsWithPairsInThem = _tagHandler.GetAllTagsSorted();
|
||||
var allUsers = visibleUsers.Concat(onlineUsers).Concat(offlineUsers).ToList();
|
||||
if (_mareConfig.Current.ShowVisibleUsersSeparately)
|
||||
if (typeof(T) == typeof(DrawUserPair))
|
||||
{
|
||||
UiSharedService.DrawWithID("$group-VisibleCustomTag", () => DrawCategory(TagHandler.CustomVisibleTag, visibleUsers, allUsers));
|
||||
DrawUserPairs(tagsWithPairsInThem, allUsers.Cast<DrawUserPair>().ToList(), visibleUsers.Cast<DrawUserPair>(), onlineUsers.Cast<DrawUserPair>(), offlineUsers.Cast<DrawUserPair>());
|
||||
}
|
||||
foreach (var tag in tagsWithPairsInThem)
|
||||
{
|
||||
if (_mareConfig.Current.ShowOfflineUsersSeparately)
|
||||
{
|
||||
UiSharedService.DrawWithID($"group-{tag}", () => DrawCategory(tag, onlineUsers, allUsers, visibleUsers));
|
||||
}
|
||||
else
|
||||
{
|
||||
UiSharedService.DrawWithID($"group-{tag}", () => DrawCategory(tag, onlineUsers.Concat(offlineUsers).ToList(), allUsers, visibleUsers));
|
||||
}
|
||||
}
|
||||
if (_mareConfig.Current.ShowOfflineUsersSeparately)
|
||||
{
|
||||
UiSharedService.DrawWithID($"group-OnlineCustomTag", () => DrawCategory(TagHandler.CustomOnlineTag,
|
||||
onlineUsers.Where(u => !_tagHandler.HasAnyTag(u.UserPair!)).ToList(), allUsers));
|
||||
UiSharedService.DrawWithID($"group-OfflineCustomTag", () => DrawCategory(TagHandler.CustomOfflineTag,
|
||||
offlineUsers.Where(u => u.UserPair!.OtherPermissions.IsPaired()).ToList(), allUsers));
|
||||
}
|
||||
else
|
||||
{
|
||||
UiSharedService.DrawWithID($"group-OnlineCustomTag", () => DrawCategory(TagHandler.CustomOnlineTag,
|
||||
onlineUsers.Concat(offlineUsers).Where(u => u.UserPair!.OtherPermissions.IsPaired() && !_tagHandler.HasAnyTag(u.UserPair!)).ToList(), allUsers));
|
||||
}
|
||||
UiSharedService.DrawWithID($"group-UnpairedCustomTag", () => DrawCategory(TagHandler.CustomUnpairedTag,
|
||||
offlineUsers.Where(u => !u.UserPair!.OtherPermissions.IsPaired()).ToList(), allUsers));
|
||||
}
|
||||
|
||||
private void DrawButtons(string tag, List<Pair> availablePairsInThisTag)
|
||||
private void DrawButtons(string tag, List<DrawUserPair> availablePairsInThisTag)
|
||||
{
|
||||
var allArePaused = availablePairsInThisTag.All(pair => pair.UserPair!.OwnPermissions.IsPaused());
|
||||
var pauseButton = allArePaused ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
|
||||
@@ -114,9 +86,9 @@ public class PairGroupsUi
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCategory(string tag, List<Pair> onlineUsers, List<Pair> allUsers, List<Pair>? visibleUsers = null)
|
||||
private void DrawCategory(string tag, IEnumerable<DrawPairBase> onlineUsers, IEnumerable<DrawPairBase> allUsers, IEnumerable<DrawPairBase>? visibleUsers = null)
|
||||
{
|
||||
List<Pair> usersInThisTag;
|
||||
IEnumerable<DrawPairBase> usersInThisTag;
|
||||
HashSet<string>? otherUidsTaggedWithTag = null;
|
||||
bool isSpecialTag = false;
|
||||
int visibleInThisTag = 0;
|
||||
@@ -129,16 +101,21 @@ public class PairGroupsUi
|
||||
{
|
||||
otherUidsTaggedWithTag = _tagHandler.GetOtherUidsForTag(tag);
|
||||
usersInThisTag = onlineUsers
|
||||
.Where(pair => otherUidsTaggedWithTag.Contains(pair.UserData.UID))
|
||||
.Where(pair => otherUidsTaggedWithTag.Contains(pair.UID))
|
||||
.ToList();
|
||||
visibleInThisTag = visibleUsers?.Count(p => otherUidsTaggedWithTag.Contains(p.UserData.UID)) ?? 0;
|
||||
visibleInThisTag = visibleUsers?.Count(p => otherUidsTaggedWithTag.Contains(p.UID)) ?? 0;
|
||||
}
|
||||
|
||||
if (isSpecialTag && !usersInThisTag.Any()) return;
|
||||
|
||||
DrawName(tag, isSpecialTag, visibleInThisTag, usersInThisTag.Count, otherUidsTaggedWithTag?.Count);
|
||||
DrawName(tag, isSpecialTag, visibleInThisTag, usersInThisTag.Count(), otherUidsTaggedWithTag?.Count);
|
||||
if (!isSpecialTag)
|
||||
UiSharedService.DrawWithID($"group-{tag}-buttons", () => DrawButtons(tag, allUsers.Where(p => otherUidsTaggedWithTag!.Contains(p.UserData.UID)).ToList()));
|
||||
{
|
||||
if (onlineUsers.Any() && onlineUsers.First() is DrawUserPair)
|
||||
{
|
||||
UiSharedService.DrawWithID($"group-{tag}-buttons", () => DrawButtons(tag, allUsers.Cast<DrawUserPair>().Where(p => otherUidsTaggedWithTag!.Contains(p.UID)).ToList()));
|
||||
}
|
||||
}
|
||||
|
||||
if (!_tagHandler.IsTagOpen(tag)) return;
|
||||
|
||||
@@ -201,31 +178,66 @@ public class PairGroupsUi
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPairs(string tag, List<Pair> availablePairsInThisCategory)
|
||||
private void DrawPairs(string tag, IEnumerable<DrawPairBase> availablePairsInThisCategory)
|
||||
{
|
||||
// These are all the OtherUIDs that are tagged with this tag
|
||||
availablePairsInThisCategory
|
||||
.ForEach(pair => UiSharedService.DrawWithID($"tag-{tag}-pair-${pair.UserData.UID}", () => _clientRenderFn(pair)));
|
||||
foreach (var pair in availablePairsInThisCategory)
|
||||
{
|
||||
UiSharedService.DrawWithID($"tag-{tag}-pair-${pair.UID}", () => pair.DrawPairedClient());
|
||||
}
|
||||
ImGui.Separator();
|
||||
}
|
||||
|
||||
private void PauseRemainingPairs(List<Pair> availablePairs)
|
||||
private void DrawUserPairs(List<string> tagsWithPairsInThem, List<DrawUserPair> allUsers, IEnumerable<DrawUserPair> visibleUsers, IEnumerable<DrawUserPair> onlineUsers, IEnumerable<DrawUserPair> offlineUsers)
|
||||
{
|
||||
if (_mareConfig.Current.ShowVisibleUsersSeparately)
|
||||
{
|
||||
UiSharedService.DrawWithID("$group-VisibleCustomTag", () => DrawCategory(TagHandler.CustomVisibleTag, visibleUsers, allUsers));
|
||||
}
|
||||
foreach (var tag in tagsWithPairsInThem)
|
||||
{
|
||||
if (_mareConfig.Current.ShowOfflineUsersSeparately)
|
||||
{
|
||||
UiSharedService.DrawWithID($"group-{tag}", () => DrawCategory(tag, onlineUsers, allUsers, visibleUsers));
|
||||
}
|
||||
else
|
||||
{
|
||||
UiSharedService.DrawWithID($"group-{tag}", () => DrawCategory(tag, onlineUsers.Concat(offlineUsers).ToList(), allUsers, visibleUsers));
|
||||
}
|
||||
}
|
||||
if (_mareConfig.Current.ShowOfflineUsersSeparately)
|
||||
{
|
||||
UiSharedService.DrawWithID($"group-OnlineCustomTag", () => DrawCategory(TagHandler.CustomOnlineTag,
|
||||
onlineUsers.Where(u => !_tagHandler.HasAnyTag(u.UID)).ToList(), allUsers));
|
||||
UiSharedService.DrawWithID($"group-OfflineCustomTag", () => DrawCategory(TagHandler.CustomOfflineTag,
|
||||
offlineUsers.Where(u => u.UserPair!.OtherPermissions.IsPaired()).ToList(), allUsers));
|
||||
}
|
||||
else
|
||||
{
|
||||
UiSharedService.DrawWithID($"group-OnlineCustomTag", () => DrawCategory(TagHandler.CustomOnlineTag,
|
||||
onlineUsers.Concat(offlineUsers).Where(u => u.UserPair!.OtherPermissions.IsPaired() && !_tagHandler.HasAnyTag(u.UID)).ToList(), allUsers));
|
||||
}
|
||||
UiSharedService.DrawWithID($"group-UnpairedCustomTag", () => DrawCategory(TagHandler.CustomUnpairedTag,
|
||||
offlineUsers.Where(u => !u.UserPair!.OtherPermissions.IsPaired()).ToList(), allUsers));
|
||||
}
|
||||
|
||||
private void PauseRemainingPairs(List<DrawUserPair> availablePairs)
|
||||
{
|
||||
foreach (var pairToPause in availablePairs.Where(pair => !pair.UserPair!.OwnPermissions.IsPaused()))
|
||||
{
|
||||
var perm = pairToPause.UserPair!.OwnPermissions;
|
||||
perm.SetPaused(paused: true);
|
||||
_ = _apiController.UserSetPairPermissions(new(pairToPause.UserData, perm));
|
||||
_ = _apiController.UserSetPairPermissions(new(new(pairToPause.UID), perm));
|
||||
}
|
||||
}
|
||||
|
||||
private void ResumeAllPairs(List<Pair> availablePairs)
|
||||
private void ResumeAllPairs(List<DrawUserPair> availablePairs)
|
||||
{
|
||||
foreach (var pairToPause in availablePairs)
|
||||
{
|
||||
var perm = pairToPause.UserPair!.OwnPermissions;
|
||||
perm.SetPaused(paused: false);
|
||||
_ = _apiController.UserSetPairPermissions(new(pairToPause.UserData, perm));
|
||||
_ = _apiController.UserSetPairPermissions(new(new(pairToPause.UID), perm));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace MareSynchronos.UI.Components;
|
||||
public class SelectGroupForPairUi
|
||||
{
|
||||
private readonly TagHandler _tagHandler;
|
||||
private readonly UidDisplayHandler _uidDisplayHandler;
|
||||
|
||||
/// <summary>
|
||||
/// The group UI is always open for a specific pair. This defines which pair the UI is open for.
|
||||
@@ -28,21 +29,22 @@ public class SelectGroupForPairUi
|
||||
/// </summary>
|
||||
private string _tagNameToAdd = "";
|
||||
|
||||
public SelectGroupForPairUi(TagHandler tagHandler)
|
||||
public SelectGroupForPairUi(TagHandler tagHandler, UidDisplayHandler uidDisplayHandler)
|
||||
{
|
||||
_show = false;
|
||||
_pair = null;
|
||||
_tagHandler = tagHandler;
|
||||
_uidDisplayHandler = uidDisplayHandler;
|
||||
}
|
||||
|
||||
public void Draw(Dictionary<string, bool> showUidForEntry)
|
||||
public void Draw()
|
||||
{
|
||||
if (_pair == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var name = PairName(showUidForEntry, _pair);
|
||||
var name = PairName(_pair);
|
||||
var popupName = $"Choose Groups for {name}";
|
||||
// Is the popup supposed to show but did not open yet? Open it
|
||||
if (_show)
|
||||
@@ -93,30 +95,19 @@ public class SelectGroupForPairUi
|
||||
_show = true;
|
||||
}
|
||||
|
||||
private static string PairName(Dictionary<string, bool> showUidForEntry, Pair pair)
|
||||
{
|
||||
showUidForEntry.TryGetValue(pair.UserData.UID, out var showUidInsteadOfName);
|
||||
var playerText = pair.GetNote();
|
||||
if (showUidInsteadOfName || string.IsNullOrEmpty(playerText))
|
||||
{
|
||||
playerText = pair.UserData.AliasOrUID;
|
||||
}
|
||||
return playerText;
|
||||
}
|
||||
|
||||
private void DrawGroupName(Pair pair, string name)
|
||||
{
|
||||
var hasTagBefore = _tagHandler.HasTag(pair.UserPair!, name);
|
||||
var hasTagBefore = _tagHandler.HasTag(pair.UserData.UID, name);
|
||||
var hasTag = hasTagBefore;
|
||||
if (ImGui.Checkbox(name, ref hasTag))
|
||||
{
|
||||
if (hasTag)
|
||||
{
|
||||
_tagHandler.AddTagToPairedUid(pair.UserPair!, name);
|
||||
_tagHandler.AddTagToPairedUid(pair.UserData.UID, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tagHandler.RemoveTagFromPairedUid(pair.UserPair!, name);
|
||||
_tagHandler.RemoveTagFromPairedUid(pair.UserData.UID, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,7 +119,7 @@ public class SelectGroupForPairUi
|
||||
_tagHandler.AddTag(_tagNameToAdd);
|
||||
if (_pair != null)
|
||||
{
|
||||
_tagHandler.AddTagToPairedUid(_pair.UserPair!, _tagNameToAdd);
|
||||
_tagHandler.AddTagToPairedUid(_pair.UserData.UID, _tagNameToAdd);
|
||||
}
|
||||
_tagNameToAdd = string.Empty;
|
||||
}
|
||||
@@ -137,4 +128,9 @@ public class SelectGroupForPairUi
|
||||
_tagNameToAdd = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private string PairName(Pair pair)
|
||||
{
|
||||
return _uidDisplayHandler.GetPlayerText(pair).text;
|
||||
}
|
||||
}
|
||||
@@ -9,18 +9,20 @@ namespace MareSynchronos.UI.Components;
|
||||
public class SelectPairForGroupUi
|
||||
{
|
||||
private readonly TagHandler _tagHandler;
|
||||
private readonly UidDisplayHandler _uidDisplayHandler;
|
||||
private string _filter = string.Empty;
|
||||
private bool _opened = false;
|
||||
private HashSet<string> _peopleInGroup = new(StringComparer.Ordinal);
|
||||
private bool _show = false;
|
||||
private string _tag = string.Empty;
|
||||
|
||||
public SelectPairForGroupUi(TagHandler tagHandler)
|
||||
public SelectPairForGroupUi(TagHandler tagHandler, UidDisplayHandler uidDisplayHandler)
|
||||
{
|
||||
_tagHandler = tagHandler;
|
||||
_uidDisplayHandler = uidDisplayHandler;
|
||||
}
|
||||
|
||||
public void Draw(List<Pair> pairs, Dictionary<string, bool> showUidForEntry)
|
||||
public void Draw(List<Pair> pairs)
|
||||
{
|
||||
var workHeight = ImGui.GetMainViewport().WorkSize.Y / ImGuiHelpers.GlobalScale;
|
||||
var minSize = new Vector2(300, workHeight < 400 ? workHeight : 400) * ImGuiHelpers.GlobalScale;
|
||||
@@ -47,21 +49,21 @@ public class SelectPairForGroupUi
|
||||
UiSharedService.FontText($"Select users for group {_tag}", UiBuilder.DefaultFont);
|
||||
ImGui.InputTextWithHint("##filter", "Filter", ref _filter, 255, ImGuiInputTextFlags.None);
|
||||
foreach (var item in pairs
|
||||
.Where(p => string.IsNullOrEmpty(_filter) || PairName(showUidForEntry, p).Contains(_filter, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderBy(p => PairName(showUidForEntry, p), StringComparer.OrdinalIgnoreCase)
|
||||
.Where(p => string.IsNullOrEmpty(_filter) || PairName(p).Contains(_filter, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderBy(p => PairName(p), StringComparer.OrdinalIgnoreCase)
|
||||
.ToList())
|
||||
{
|
||||
var isInGroup = _peopleInGroup.Contains(item.UserData.UID);
|
||||
if (ImGui.Checkbox(PairName(showUidForEntry, item), ref isInGroup))
|
||||
if (ImGui.Checkbox(PairName(item), ref isInGroup))
|
||||
{
|
||||
if (isInGroup)
|
||||
{
|
||||
_tagHandler.AddTagToPairedUid(item.UserPair!, _tag);
|
||||
_tagHandler.AddTagToPairedUid(item.UserData.UID, _tag);
|
||||
_peopleInGroup.Add(item.UserData.UID);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tagHandler.RemoveTagFromPairedUid(item.UserPair!, _tag);
|
||||
_tagHandler.RemoveTagFromPairedUid(item.UserData.UID, _tag);
|
||||
_peopleInGroup.Remove(item.UserData.UID);
|
||||
}
|
||||
}
|
||||
@@ -82,14 +84,8 @@ public class SelectPairForGroupUi
|
||||
_show = true;
|
||||
}
|
||||
|
||||
private static string PairName(Dictionary<string, bool> showUidForEntry, Pair pair)
|
||||
private string PairName(Pair pair)
|
||||
{
|
||||
showUidForEntry.TryGetValue(pair.UserData.UID, out var showUidInsteadOfName);
|
||||
var playerText = pair.GetNote();
|
||||
if (showUidInsteadOfName || string.IsNullOrEmpty(playerText))
|
||||
{
|
||||
playerText = pair.UserData.AliasOrUID;
|
||||
}
|
||||
return playerText;
|
||||
return _uidDisplayHandler.GetPlayerText(pair).text;
|
||||
}
|
||||
}
|
||||
187
MareSynchronos/UI/EditProfileUi.cs
Normal file
187
MareSynchronos/UI/EditProfileUi.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
using ImGuiNET;
|
||||
using ImGuiScene;
|
||||
using MareSynchronos.API.Data;
|
||||
using MareSynchronos.API.Data.Enum;
|
||||
using MareSynchronos.API.Dto.User;
|
||||
using MareSynchronos.Services;
|
||||
using MareSynchronos.Services.Mediator;
|
||||
using MareSynchronos.WebAPI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MareSynchronos.UI;
|
||||
|
||||
public class EditProfileUi : WindowMediatorSubscriberBase
|
||||
{
|
||||
private readonly ApiController _apiController;
|
||||
private readonly FileDialogManager _fileDialogManager;
|
||||
private readonly MareProfileManager _mareProfileManager;
|
||||
private readonly UiBuilder _uiBuilder;
|
||||
private readonly UiSharedService _uiSharedService;
|
||||
private string _descriptionText;
|
||||
private bool _loadedPrior = false;
|
||||
private TextureWrap? _pfpTextureWrap;
|
||||
private bool _showFileDialogError = false;
|
||||
private bool _wasOpen;
|
||||
|
||||
public EditProfileUi(ILogger<EditProfileUi> logger, MareMediator mediator,
|
||||
ApiController apiController, UiBuilder uiBuilder, UiSharedService uiSharedService,
|
||||
FileDialogManager fileDialogManager, MareProfileManager mareProfileManager) : base(logger, mediator, "Mare Synchronos Edit Profile###MareSynchronosEditProfileUI")
|
||||
{
|
||||
IsOpen = false;
|
||||
this.SizeConstraints = new()
|
||||
{
|
||||
MinimumSize = new(768, 512),
|
||||
MaximumSize = new(2000, 2000)
|
||||
};
|
||||
_apiController = apiController;
|
||||
_uiBuilder = uiBuilder;
|
||||
_uiSharedService = uiSharedService;
|
||||
_fileDialogManager = fileDialogManager;
|
||||
_mareProfileManager = mareProfileManager;
|
||||
|
||||
Mediator.Subscribe<GposeStartMessage>(this, (_) => { _wasOpen = IsOpen; IsOpen = false; });
|
||||
Mediator.Subscribe<GposeEndMessage>(this, (_) => IsOpen = _wasOpen);
|
||||
Mediator.Subscribe<DisconnectedMessage>(this, (_) => IsOpen = false);
|
||||
Mediator.Subscribe<ClearProfileDataMessage>(this, (msg) =>
|
||||
{
|
||||
if (string.Equals(msg.UserData.UID, _apiController.UID, StringComparison.Ordinal))
|
||||
{
|
||||
_pfpTextureWrap?.Dispose();
|
||||
_pfpTextureWrap = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
_uiSharedService.BigText("Current Profile");
|
||||
|
||||
var (loaded, profile) = _mareProfileManager.GetMareProfile(new API.Data.UserData(_apiController.UID));
|
||||
|
||||
if (!loaded)
|
||||
{
|
||||
_loadedPrior = false;
|
||||
_descriptionText = string.Empty;
|
||||
ImGui.TextUnformatted("Loading profile...");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (profile.IsFlagged)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped(profile.Description, ImGuiColors.DalamudRed);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_loadedPrior)
|
||||
{
|
||||
_descriptionText = profile.Description;
|
||||
_loadedPrior = true;
|
||||
_pfpTextureWrap?.Dispose();
|
||||
_pfpTextureWrap = _uiBuilder.LoadImage(Convert.FromBase64String(profile.Base64ProfilePicture));
|
||||
}
|
||||
}
|
||||
|
||||
if (_pfpTextureWrap != null)
|
||||
{
|
||||
ImGui.Image(_pfpTextureWrap.ImGuiHandle, new System.Numerics.Vector2(_pfpTextureWrap.Width, _pfpTextureWrap.Height));
|
||||
}
|
||||
|
||||
ImGui.SameLine(256);
|
||||
var posX = ImGui.GetCursorPosX();
|
||||
var spacing = ImGui.GetStyle().ItemSpacing.X;
|
||||
var width = UiSharedService.GetWindowContentRegionWidth() - posX + spacing;
|
||||
if (ImGui.BeginChildFrame(100, new System.Numerics.Vector2(width, 256)))
|
||||
{
|
||||
var nsfw = profile.IsNSFW;
|
||||
ImGui.BeginDisabled();
|
||||
ImGui.Checkbox("Is NSFW", ref nsfw);
|
||||
ImGui.EndDisabled();
|
||||
UiSharedService.TextWrapped("Description:" + Environment.NewLine + profile.Description);
|
||||
}
|
||||
ImGui.EndChildFrame();
|
||||
|
||||
ImGui.Separator();
|
||||
_uiSharedService.BigText("Notes and Rules for Profiles");
|
||||
|
||||
ImGui.TextWrapped($"- All users that are paired and unpaused with you will be able to see your profile picture and description.{Environment.NewLine}" +
|
||||
$"- Other users have the possibility to report your profile for breaking the rules.{Environment.NewLine}" +
|
||||
$"- !!! AVOID: anything as profile image that can be considered highly illegal or obscene (bestiality, anything that could be considered a sexual act with a minor (that includes Lalafells), etc.){Environment.NewLine}" +
|
||||
$"- !!! AVOID: slurs of any kind in the description that can be considered highly offensive{Environment.NewLine}" +
|
||||
$"- In case of valid reports from other users this can lead to disabling your profile forever or terminating your Mare account indefinitely.{Environment.NewLine}" +
|
||||
$"- Judgement of your profile validity from reports through staff is not up to debate and decisions to disable your profile/account permanent.{Environment.NewLine}" +
|
||||
$"- If your profile picture or profile description could be considered NSFW, enable the toggle below.");
|
||||
ImGui.Separator();
|
||||
_uiSharedService.BigText("Profile Settings");
|
||||
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.FileUpload, "Upload new profile image"))
|
||||
{
|
||||
_fileDialogManager.OpenFileDialog("Select new Profile picture", ".png", (success, file) =>
|
||||
{
|
||||
if (!success) return;
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var fileContent = File.ReadAllBytes(file);
|
||||
using MemoryStream ms = new(fileContent);
|
||||
var format = await Image.DetectFormatAsync(ms).ConfigureAwait(false);
|
||||
if (!format.FileExtensions.Contains("png", StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
_showFileDialogError = true;
|
||||
return;
|
||||
}
|
||||
using var image = Image.Load<Rgba32>(fileContent);
|
||||
|
||||
if (image.Width > 256 || image.Height > 256 || (fileContent.Length > 250 * 1024))
|
||||
{
|
||||
_showFileDialogError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_showFileDialogError = false;
|
||||
await _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), false, null, Convert.ToBase64String(fileContent), null))
|
||||
.ConfigureAwait(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
UiSharedService.AttachToolTip("Select and upload a new profile picture");
|
||||
ImGui.SameLine();
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear uploaded profile picture"))
|
||||
{
|
||||
_ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), false, null, "", null));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Clear your currently uploaded profile picture");
|
||||
if (_showFileDialogError)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("The profile picture must be a PNG file with a maximum height and width of 256px and 250KiB size", ImGuiColors.DalamudRed);
|
||||
}
|
||||
var isNsfw = profile.IsNSFW;
|
||||
if (ImGui.Checkbox("Profile is NSFW", ref isNsfw))
|
||||
{
|
||||
_ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), false, isNsfw, null, null));
|
||||
}
|
||||
UiSharedService.DrawHelpText("If your profile description or image can be considered NSFW, toggle this to ON");
|
||||
var widthTextBox = UiSharedService.GetWindowContentRegionWidth() - posX + spacing;
|
||||
ImGui.TextUnformatted($"Description {_descriptionText.Length}/750");
|
||||
ImGui.InputTextMultiline("##description", ref _descriptionText, 750, new System.Numerics.Vector2(widthTextBox, 200));
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Save, "Save Description"))
|
||||
{
|
||||
_ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), false, null, null, _descriptionText));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Sets your profile description text");
|
||||
ImGui.SameLine();
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear Description"))
|
||||
{
|
||||
_ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), false, null, null, ""));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Clears your profile description text");
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
_pfpTextureWrap?.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -43,12 +43,16 @@ public class GposeUi : WindowMediatorSubscriberBase
|
||||
{
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.FolderOpen, "Load MCDF"))
|
||||
{
|
||||
_fileDialogManager.OpenFileDialog("Pick MCDF file", ".mcdf", (success, path) =>
|
||||
_fileDialogManager.OpenFileDialog("Pick MCDF file", ".mcdf", (success, paths) =>
|
||||
{
|
||||
if (!success) return;
|
||||
if (paths.FirstOrDefault() is not string path) return;
|
||||
|
||||
_configService.Current.ExportFolder = Path.GetDirectoryName(path) ?? string.Empty;
|
||||
_configService.Save();
|
||||
|
||||
Task.Run(() => _mareCharaFileManager.LoadMareCharaFile(path));
|
||||
});
|
||||
}, 1, Directory.Exists(_configService.Current.ExportFolder) ? _configService.Current.ExportFolder : null);
|
||||
}
|
||||
UiSharedService.AttachToolTip("Applies it to the currently selected GPose actor");
|
||||
if (_mareCharaFileManager.LoadedCharaFile != null)
|
||||
|
||||
@@ -21,9 +21,9 @@ public class TagHandler
|
||||
_serverConfigurationManager.AddTag(tag);
|
||||
}
|
||||
|
||||
public void AddTagToPairedUid(UserPairDto pair, string tagName)
|
||||
public void AddTagToPairedUid(string uid, string tagName)
|
||||
{
|
||||
_serverConfigurationManager.AddTagForUid(pair.User.UID, tagName);
|
||||
_serverConfigurationManager.AddTagForUid(uid, tagName);
|
||||
}
|
||||
|
||||
public List<string> GetAllTagsSorted()
|
||||
@@ -38,14 +38,14 @@ public class TagHandler
|
||||
return _serverConfigurationManager.GetUidsForTag(tag);
|
||||
}
|
||||
|
||||
public bool HasAnyTag(UserPairDto pair)
|
||||
public bool HasAnyTag(string uid)
|
||||
{
|
||||
return _serverConfigurationManager.HasTags(pair.User.UID);
|
||||
return _serverConfigurationManager.HasTags(uid);
|
||||
}
|
||||
|
||||
public bool HasTag(UserPairDto pair, string tagName)
|
||||
public bool HasTag(string uid, string tagName)
|
||||
{
|
||||
return _serverConfigurationManager.ContainsTag(pair.User.UID, tagName);
|
||||
return _serverConfigurationManager.ContainsTag(uid, tagName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -64,9 +64,9 @@ public class TagHandler
|
||||
_serverConfigurationManager.RemoveTag(tag);
|
||||
}
|
||||
|
||||
public void RemoveTagFromPairedUid(UserPairDto pair, string tagName)
|
||||
public void RemoveTagFromPairedUid(string uid, string tagName)
|
||||
{
|
||||
_serverConfigurationManager.RemoveTagForUid(pair.User.UID, tagName);
|
||||
_serverConfigurationManager.RemoveTagForUid(uid, tagName);
|
||||
}
|
||||
|
||||
public void SetTagOpen(string tag, bool open)
|
||||
|
||||
250
MareSynchronos/UI/Handlers/UidDisplayHandler.cs
Normal file
250
MareSynchronos/UI/Handlers/UidDisplayHandler.cs
Normal file
@@ -0,0 +1,250 @@
|
||||
using Dalamud.Interface;
|
||||
using ImGuiNET;
|
||||
using MareSynchronos.PlayerData.Pairs;
|
||||
using MareSynchronos.Services.ServerConfiguration;
|
||||
using MareSynchronos.MareConfiguration;
|
||||
using Dalamud.Interface.Colors;
|
||||
using MareSynchronos.API.Data.Extensions;
|
||||
using ImGuiScene;
|
||||
using System.Numerics;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MareSynchronos.Services;
|
||||
|
||||
namespace MareSynchronos.UI.Handlers;
|
||||
|
||||
public class UidDisplayHandler
|
||||
{
|
||||
private readonly ILogger<UidDisplayHandler> _logger;
|
||||
private readonly MareConfigService _mareConfigService;
|
||||
private readonly MareProfileManager _mareProfileManager;
|
||||
private readonly PairManager _pairManager;
|
||||
private readonly ServerConfigurationManager _serverManager;
|
||||
private readonly Dictionary<string, bool> _showUidForEntry = new(StringComparer.Ordinal);
|
||||
private readonly UiBuilder _uiBuilder;
|
||||
private readonly UiSharedService _uiSharedService;
|
||||
private string _editNickEntry = string.Empty;
|
||||
private string _editUserComment = string.Empty;
|
||||
private string _lastMouseOverUid = string.Empty;
|
||||
private byte[] _lastProfilePicture = Array.Empty<byte>();
|
||||
private DateTime? _popupTime;
|
||||
private TextureWrap? _textureWrap;
|
||||
|
||||
public UidDisplayHandler(ILogger<UidDisplayHandler> logger, UiBuilder uiBuilder, MareProfileManager mareProfileManager,
|
||||
UiSharedService uiSharedService, PairManager pairManager, ServerConfigurationManager serverManager, MareConfigService mareConfigService)
|
||||
{
|
||||
_logger = logger;
|
||||
_uiBuilder = uiBuilder;
|
||||
_mareProfileManager = mareProfileManager;
|
||||
_uiSharedService = uiSharedService;
|
||||
_pairManager = pairManager;
|
||||
_serverManager = serverManager;
|
||||
_mareConfigService = mareConfigService;
|
||||
}
|
||||
|
||||
public void DrawPairText(string id, Pair pair, float textPosX, float originalY, Func<float> editBoxWidth)
|
||||
{
|
||||
ImGui.SameLine(textPosX);
|
||||
(bool textIsUid, string playerText) = GetPlayerText(pair);
|
||||
if (!string.Equals(_editNickEntry, pair.UserData.UID, StringComparison.Ordinal))
|
||||
{
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
if (textIsUid) ImGui.PushFont(UiBuilder.MonoFont);
|
||||
ImGui.TextUnformatted(playerText);
|
||||
if (textIsUid) ImGui.PopFont();
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
if (!string.Equals(_lastMouseOverUid, id))
|
||||
{
|
||||
_popupTime = DateTime.UtcNow.AddSeconds(_mareConfigService.Current.ProfileDelay);
|
||||
}
|
||||
|
||||
_lastMouseOverUid = id;
|
||||
|
||||
if (_popupTime > DateTime.UtcNow || !_mareConfigService.Current.ProfilesShow)
|
||||
{
|
||||
ImGui.SetTooltip("Left click to switch between UID display and nick" + Environment.NewLine + "Right click to change nick for " + pair.UserData.AliasOrUID);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var spacing = ImGui.GetStyle().ItemSpacing;
|
||||
|
||||
ImGui.SetNextWindowSizeConstraints(new Vector2(512 + spacing.X * 4, 256 + spacing.Y * 3), new Vector2(512 + spacing.X * 4, 512 + spacing.Y * 3));
|
||||
ImGui.BeginTooltip();
|
||||
|
||||
var mareProfile = _mareProfileManager.GetMareProfile(pair.UserData);
|
||||
|
||||
if (_textureWrap == null || !mareProfile.Profile.ImageData.Value.SequenceEqual(_lastProfilePicture))
|
||||
{
|
||||
_textureWrap?.Dispose();
|
||||
_lastProfilePicture = mareProfile.Profile.ImageData.Value;
|
||||
_textureWrap = _uiBuilder.LoadImage(_lastProfilePicture);
|
||||
}
|
||||
|
||||
var drawList = ImGui.GetWindowDrawList();
|
||||
var rect = drawList.GetClipRectMin();
|
||||
var rectMax = drawList.GetClipRectMax();
|
||||
|
||||
ImGui.Indent(256 + spacing.X * 2);
|
||||
if (_uiSharedService.UidFontBuilt) ImGui.PushFont(_uiSharedService.UidFont);
|
||||
UiSharedService.ColorText(pair.UserData.AliasOrUID, ImGuiColors.HealerGreen);
|
||||
if (_uiSharedService.UidFontBuilt) ImGui.PopFont();
|
||||
var pos = ImGui.GetCursorPos();
|
||||
var note = _serverManager.GetNoteForUid(pair.UserData.UID);
|
||||
if (!string.IsNullOrEmpty(note))
|
||||
{
|
||||
UiSharedService.ColorText(note, ImGuiColors.DalamudGrey);
|
||||
}
|
||||
string status = pair.IsVisible ? "Visible" : (pair.IsOnline ? "Online" : "Offline");
|
||||
UiSharedService.ColorText(status, (pair.IsVisible || pair.IsOnline) ? ImGuiColors.HealerGreen : ImGuiColors.DalamudRed);
|
||||
if (pair.IsVisible)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted($"({pair.PlayerName})");
|
||||
}
|
||||
if (pair.UserPair != null)
|
||||
{
|
||||
ImGui.TextUnformatted("Directly paired");
|
||||
if (pair.UserPair.OwnPermissions.IsPaused())
|
||||
{
|
||||
ImGui.SameLine();
|
||||
UiSharedService.ColorText("You: paused", ImGuiColors.DalamudYellow);
|
||||
}
|
||||
if (pair.UserPair.OtherPermissions.IsPaused())
|
||||
{
|
||||
ImGui.SameLine();
|
||||
UiSharedService.ColorText("They: paused", ImGuiColors.DalamudYellow);
|
||||
}
|
||||
}
|
||||
if (pair.GroupPair.Any())
|
||||
{
|
||||
ImGui.TextUnformatted("Paired through Syncshells:");
|
||||
foreach (var groupPair in pair.GroupPair)
|
||||
{
|
||||
ImGui.TextUnformatted("- " + groupPair.Key.GroupAliasOrGID);
|
||||
}
|
||||
}
|
||||
|
||||
var posDone = ImGui.GetCursorPos();
|
||||
UiSharedService.TextWrapped(mareProfile.Profile.Description);
|
||||
ImGui.Unindent();
|
||||
|
||||
var sepColor = ImGui.GetStyle().Colors[(int)ImGuiCol.Separator];
|
||||
|
||||
bool tallerThanWide = _textureWrap.Height >= _textureWrap.Width;
|
||||
var stretchFactor = tallerThanWide ? 256f / _textureWrap.Height : 256f / _textureWrap.Width;
|
||||
var newWidth = _textureWrap.Width * stretchFactor;
|
||||
var newHeight = _textureWrap.Height * stretchFactor;
|
||||
var remainingWidth = (256f - newWidth) / 2f;
|
||||
var remainingHeight = (256f - newHeight) / 2f;
|
||||
drawList.AddImage(_textureWrap.ImGuiHandle, new Vector2(rect.X + spacing.X + remainingWidth, rect.Y + spacing.Y + remainingHeight),
|
||||
new Vector2(rect.X + spacing.X + remainingWidth + newWidth, rect.Y + spacing.Y + remainingHeight + newHeight));
|
||||
|
||||
drawList.AddLine(new Vector2(rect.X + 256 + spacing.X * 2, rect.Y + pos.Y - spacing.Y),
|
||||
new Vector2(rectMax.X - spacing.X, rect.Y + pos.Y - spacing.Y),
|
||||
UiSharedService.Color((byte)(sepColor.X * 255), (byte)(sepColor.Y * 255), (byte)(sepColor.Z * 255), (byte)(sepColor.W * 255)));
|
||||
drawList.AddLine(new Vector2(rect.X + 256 + spacing.X * 2, rect.Y + posDone.Y - spacing.Y),
|
||||
new Vector2(rectMax.X - spacing.X, rect.Y + posDone.Y - spacing.Y),
|
||||
UiSharedService.Color((byte)(sepColor.X * 255), (byte)(sepColor.Y * 255), (byte)(sepColor.Z * 255), (byte)(sepColor.W * 255)));
|
||||
|
||||
ImGui.EndTooltip();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning("Error during draw tooltip", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.Equals(_lastMouseOverUid, id))
|
||||
{
|
||||
_lastProfilePicture = Array.Empty<byte>();
|
||||
_lastMouseOverUid = string.Empty;
|
||||
_textureWrap?.Dispose();
|
||||
_textureWrap = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
|
||||
{
|
||||
var prevState = textIsUid;
|
||||
if (_showUidForEntry.ContainsKey(pair.UserData.UID))
|
||||
{
|
||||
prevState = _showUidForEntry[pair.UserData.UID];
|
||||
}
|
||||
_showUidForEntry[pair.UserData.UID] = !prevState;
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
var nickEntryPair = _pairManager.DirectPairs.Find(p => string.Equals(p.UserData.UID, _editNickEntry, StringComparison.Ordinal));
|
||||
nickEntryPair?.SetNote(_editUserComment);
|
||||
_editUserComment = pair.GetNote() ?? string.Empty;
|
||||
_editNickEntry = pair.UserData.UID;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.SetCursorPosY(originalY);
|
||||
|
||||
ImGui.SetNextItemWidth(editBoxWidth.Invoke());
|
||||
if (ImGui.InputTextWithHint("", "Nick/Notes", ref _editUserComment, 255, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
_serverManager.SetNoteForUid(pair.UserData.UID, _editUserComment);
|
||||
_serverManager.SaveNotes();
|
||||
_editNickEntry = string.Empty;
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_editNickEntry = string.Empty;
|
||||
}
|
||||
UiSharedService.AttachToolTip("Hit ENTER to save\nRight click to cancel");
|
||||
}
|
||||
}
|
||||
|
||||
public (bool isUid, string text) GetPlayerText(Pair pair)
|
||||
{
|
||||
var textIsUid = true;
|
||||
bool showUidInsteadOfName = ShowUidInsteadOfName(pair);
|
||||
string? playerText = _serverManager.GetNoteForUid(pair.UserData.UID);
|
||||
if (!showUidInsteadOfName && playerText != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(playerText))
|
||||
{
|
||||
playerText = pair.UserData.AliasOrUID;
|
||||
}
|
||||
else
|
||||
{
|
||||
textIsUid = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
playerText = pair.UserData.AliasOrUID;
|
||||
}
|
||||
|
||||
if (_mareConfigService.Current.ShowCharacterNameInsteadOfNotesForVisible && pair.IsVisible && !showUidInsteadOfName)
|
||||
{
|
||||
playerText = pair.PlayerName;
|
||||
textIsUid = false;
|
||||
}
|
||||
|
||||
return (textIsUid, playerText!);
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
_editNickEntry = string.Empty;
|
||||
_editUserComment = string.Empty;
|
||||
}
|
||||
|
||||
private bool ShowUidInsteadOfName(Pair pair)
|
||||
{
|
||||
_showUidForEntry.TryGetValue(pair.UserData.UID, out var showUidInsteadOfName);
|
||||
|
||||
return showUidInsteadOfName;
|
||||
}
|
||||
}
|
||||
@@ -362,10 +362,16 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
ImGui.InputTextWithHint("Export Descriptor", "This description will be shown on loading the data", ref _exportDescription, 255);
|
||||
if (UiSharedService.IconTextButton(FontAwesomeIcon.Save, "Export Character as MCDF"))
|
||||
{
|
||||
_uiShared.FileDialogManager.SaveFileDialog("Export Character to file", ".mcdf", "export.mcdf", ".mcdf", (success, path) =>
|
||||
string defaultFileName = string.IsNullOrEmpty(_exportDescription)
|
||||
? "export.mcdf"
|
||||
: string.Join('_', $"{_exportDescription}.mcdf".Split(Path.GetInvalidFileNameChars()));
|
||||
_uiShared.FileDialogManager.SaveFileDialog("Export Character to file", ".mcdf", defaultFileName, ".mcdf", (success, path) =>
|
||||
{
|
||||
if (!success) return;
|
||||
|
||||
_configService.Current.ExportFolder = Path.GetDirectoryName(path) ?? string.Empty;
|
||||
_configService.Save();
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
@@ -378,7 +384,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
_logger.LogCritical(ex, "Error saving data");
|
||||
}
|
||||
});
|
||||
});
|
||||
}, Directory.Exists(_configService.Current.ExportFolder) ? _configService.Current.ExportFolder : null);
|
||||
}
|
||||
UiSharedService.ColorTextWrapped("Note: For best results make sure you have everything you want to be shared as well as the correct character appearance" +
|
||||
" equipped and redraw your character before exporting.", ImGuiColors.DalamudYellow);
|
||||
@@ -484,9 +490,11 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
ImGui.Separator();
|
||||
UiSharedService.FontText("UI", _uiShared.UidFont);
|
||||
var showNameInsteadOfNotes = _configService.Current.ShowCharacterNameInsteadOfNotesForVisible;
|
||||
var reverseUserSort = _configService.Current.ReverseUserSort;
|
||||
var showVisibleSeparate = _configService.Current.ShowVisibleUsersSeparately;
|
||||
var showOfflineSeparate = _configService.Current.ShowOfflineUsersSeparately;
|
||||
var showProfiles = _configService.Current.ProfilesShow;
|
||||
var showNsfwProfiles = _configService.Current.ProfilesAllowNsfw;
|
||||
var profileDelay = _configService.Current.ProfileDelay;
|
||||
|
||||
if (ImGui.Checkbox("Show separate Visible group", ref showVisibleSeparate))
|
||||
{
|
||||
@@ -509,12 +517,30 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
UiSharedService.DrawHelpText("This will show the character name instead of custom set note when a character is visible");
|
||||
|
||||
if (ImGui.Checkbox("Reverse user sort", ref reverseUserSort))
|
||||
if (ImGui.Checkbox("Show Mare Profiles on Hover", ref showProfiles))
|
||||
{
|
||||
_configService.Current.ReverseUserSort = reverseUserSort;
|
||||
Mediator.Publish(new ClearProfileDataMessage());
|
||||
_configService.Current.ProfilesShow = showProfiles;
|
||||
_configService.Save();
|
||||
}
|
||||
UiSharedService.DrawHelpText("This reverses the user sort from A->Z to Z->A");
|
||||
UiSharedService.DrawHelpText("This will show the configured user profile after a set delay");
|
||||
ImGui.Indent();
|
||||
if (!showProfiles) ImGui.BeginDisabled();
|
||||
if (ImGui.Checkbox("Show profiles marked as NSFW", ref showNsfwProfiles))
|
||||
{
|
||||
Mediator.Publish(new ClearProfileDataMessage());
|
||||
_configService.Current.ProfilesAllowNsfw = showNsfwProfiles;
|
||||
_configService.Save();
|
||||
}
|
||||
UiSharedService.DrawHelpText("Will show profiles that have the NSFW tag enabled");
|
||||
if (ImGui.SliderFloat("Hover Delay", ref profileDelay, 1, 10))
|
||||
{
|
||||
_configService.Current.ProfileDelay = profileDelay;
|
||||
_configService.Save();
|
||||
}
|
||||
UiSharedService.DrawHelpText("Delay until the profile should be displayed");
|
||||
if (!showProfiles) ImGui.EndDisabled();
|
||||
ImGui.Unindent();
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
|
||||
@@ -161,13 +161,13 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
||||
|
||||
public static uint Color(Vector4 color)
|
||||
{
|
||||
uint ret = (byte)(color.W);
|
||||
uint ret = (byte)(color.W * 255);
|
||||
ret <<= 8;
|
||||
ret += (byte)(color.X);
|
||||
ret += (byte)(color.Z * 255);
|
||||
ret <<= 8;
|
||||
ret += (byte)(color.Y);
|
||||
ret += (byte)(color.Y * 255);
|
||||
ret <<= 8;
|
||||
ret += (byte)(color.Z);
|
||||
ret += (byte)(color.X * 255);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -452,6 +452,13 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
||||
return true;
|
||||
}
|
||||
|
||||
public void BigText(string text)
|
||||
{
|
||||
if (UidFontBuilt) ImGui.PushFont(UidFont);
|
||||
ImGui.TextUnformatted(text);
|
||||
if (UidFontBuilt) ImGui.PopFont();
|
||||
}
|
||||
|
||||
public void DrawCacheDirectorySetting()
|
||||
{
|
||||
ColorTextWrapped("Note: The storage folder should be somewhere close to root (i.e. C:\\MareStorage) in a new empty folder. DO NOT point this to your game folder. DO NOT point this to your Penumbra folder.", ImGuiColors.DalamudYellow);
|
||||
|
||||
@@ -242,7 +242,13 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase
|
||||
fi.LastWriteTime = RandomDayInThePast().Invoke();
|
||||
try
|
||||
{
|
||||
_ = _fileDbManager.CreateCacheEntry(filePath);
|
||||
var entry = _fileDbManager.CreateCacheEntry(filePath);
|
||||
if (!string.Equals(entry?.Hash, file.Hash, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.LogError("Hash mismatch after extracting, got {hash}, expected {expectedHash}, deleting file", entry?.Hash, file.Hash);
|
||||
File.Delete(filePath);
|
||||
_fileDbManager.RemoveHash(entry);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -49,6 +49,12 @@ public partial class ApiController
|
||||
return await _mareHub!.InvokeAsync<List<UserPairDto>>(nameof(UserGetPairedClients)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<UserProfileDto> UserGetProfile(UserDto dto)
|
||||
{
|
||||
if (!IsConnected) return new UserProfileDto(dto.User, false, null, null, null);
|
||||
return await _mareHub!.InvokeAsync<UserProfileDto>(nameof(UserGetProfile), dto).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task UserPushData(UserCharaDataMessageDto dto)
|
||||
{
|
||||
try
|
||||
@@ -67,11 +73,23 @@ public partial class ApiController
|
||||
await _mareHub!.SendAsync(nameof(UserRemovePair), userDto).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task UserReportProfile(UserProfileReportDto userDto)
|
||||
{
|
||||
if (!IsConnected) return;
|
||||
await _mareHub!.SendAsync(nameof(UserReportProfile), userDto).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task UserSetPairPermissions(UserPermissionsDto userPermissions)
|
||||
{
|
||||
await _mareHub!.SendAsync(nameof(UserSetPairPermissions), userPermissions).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task UserSetProfile(UserProfileDto userDescription)
|
||||
{
|
||||
if (!IsConnected) return;
|
||||
await _mareHub!.InvokeAsync(nameof(UserSetProfile), userDescription).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task PushCharacterDataInternal(CharacterData character, List<UserData> visibleCharacters)
|
||||
{
|
||||
Logger.LogInformation("Pushing character data for {hash} to {charas}", character.DataHash.Value, string.Join(", ", visibleCharacters.Select(c => c.AliasOrUID)));
|
||||
|
||||
@@ -162,6 +162,13 @@ public partial class ApiController
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task Client_UserUpdateProfile(UserDto dto)
|
||||
{
|
||||
Logger.LogDebug("Client_UserUpdateProfile: {dto}", dto);
|
||||
ExecuteSafely(() => Mediator.Publish(new ClearProfileDataMessage(dto.User)));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task Client_UserUpdateSelfPairPermissions(UserPermissionsDto dto)
|
||||
{
|
||||
Logger.LogDebug("Client_UserUpdateSelfPairPermissions: {dto}", dto);
|
||||
@@ -277,6 +284,12 @@ public partial class ApiController
|
||||
_mareHub!.On(nameof(Client_UserUpdateOtherPairPermissions), act);
|
||||
}
|
||||
|
||||
public void OnUserUpdateProfile(Action<UserDto> act)
|
||||
{
|
||||
if (_initialized) return;
|
||||
_mareHub!.On(nameof(Client_UserUpdateProfile), act);
|
||||
}
|
||||
|
||||
public void OnUserUpdateSelfPairPermissions(Action<UserPermissionsDto> act)
|
||||
{
|
||||
if (_initialized) return;
|
||||
|
||||
@@ -244,6 +244,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
|
||||
OnUserUpdateOtherPairPermissions(dto => Client_UserUpdateOtherPairPermissions(dto));
|
||||
OnUserUpdateSelfPairPermissions(dto => Client_UserUpdateSelfPairPermissions(dto));
|
||||
OnUserReceiveUploadStatus(dto => Client_UserReceiveUploadStatus(dto));
|
||||
OnUserUpdateProfile(dto => Client_UserUpdateProfile(dto));
|
||||
|
||||
OnGroupChangePermissions((dto) => Client_GroupChangePermissions(dto));
|
||||
OnGroupDelete((dto) => Client_GroupDelete(dto));
|
||||
|
||||
Reference in New Issue
Block a user