add downloads UI, fix some bugs on disconnect

This commit is contained in:
Stanley Dimant
2022-06-24 15:43:39 +02:00
parent 6ee159f716
commit 9b8145fddd
9 changed files with 216 additions and 50 deletions

View File

@@ -47,6 +47,9 @@ namespace MareSynchronos
public Dictionary<string, string> UidComments { get; set; } = new(); public Dictionary<string, string> UidComments { get; set; } = new();
public bool UseCustomService { get; set; } = false; public bool UseCustomService { get; set; } = false;
public int Version { get; set; } = 0; public int Version { get; set; } = 0;
public bool ShowTransferWindow { get; set; } = true;
// the below exist just to make saving less cumbersome // the below exist just to make saving less cumbersome
public void Initialize(DalamudPluginInterface pluginInterface) public void Initialize(DalamudPluginInterface pluginInterface)
{ {

View File

@@ -1,8 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dalamud.Game; using Dalamud.Game;
using Dalamud.Game.ClientState; using Dalamud.Game.ClientState;
@@ -14,7 +12,6 @@ using MareSynchronos.FileCacheDB;
using MareSynchronos.Models; using MareSynchronos.Models;
using MareSynchronos.Utils; using MareSynchronos.Utils;
using MareSynchronos.WebAPI; using MareSynchronos.WebAPI;
using Microsoft.EntityFrameworkCore;
namespace MareSynchronos.Managers; namespace MareSynchronos.Managers;
@@ -63,6 +60,8 @@ public class CharacterCacheManager : IDisposable
{ {
RestoreCharacter(character); RestoreCharacter(character);
} }
_onlineCachedPlayers.Clear();
} }
public void Initialize() public void Initialize()
@@ -74,6 +73,7 @@ public class CharacterCacheManager : IDisposable
_apiController.UnpairedFromOther += ApiControllerOnUnpairedFromOther; _apiController.UnpairedFromOther += ApiControllerOnUnpairedFromOther;
_framework.Update += FrameworkOnUpdate; _framework.Update += FrameworkOnUpdate;
} }
public async Task UpdatePlayersFromService(Dictionary<string, int> playerJobIds) public async Task UpdatePlayersFromService(Dictionary<string, int> playerJobIds)
{ {
await _apiController.GetCharacterData(playerJobIds); await _apiController.GetCharacterData(playerJobIds);

View File

@@ -12,7 +12,7 @@ using MareSynchronos.Utils;
namespace MareSynchronos.Managers namespace MareSynchronos.Managers
{ {
internal class FileCacheManager : IDisposable public class FileCacheManager : IDisposable
{ {
private readonly FileCacheFactory _fileCacheFactory; private readonly FileCacheFactory _fileCacheFactory;
private readonly IpcManager _ipcManager; private readonly IpcManager _ipcManager;

View File

@@ -24,7 +24,7 @@ namespace MareSynchronos
private readonly CommandManager _commandManager; private readonly CommandManager _commandManager;
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly FileCacheManager _fileCacheManager; private readonly FileCacheManager _fileCacheManager;
private readonly IntroUI _introUi; private readonly IntroUi _introUi;
private readonly IpcManager _ipcManager; private readonly IpcManager _ipcManager;
private readonly ObjectTable _objectTable; private readonly ObjectTable _objectTable;
private readonly DalamudPluginInterface _pluginInterface; private readonly DalamudPluginInterface _pluginInterface;
@@ -34,6 +34,7 @@ namespace MareSynchronos
private readonly DalamudUtil _dalamudUtil; private readonly DalamudUtil _dalamudUtil;
private readonly CharacterCacheManager _characterCacheManager; private readonly CharacterCacheManager _characterCacheManager;
private readonly IPlayerWatcher _playerWatcher; private readonly IPlayerWatcher _playerWatcher;
private readonly DownloadUi _downloadUi;
public Plugin(DalamudPluginInterface pluginInterface, CommandManager commandManager, public Plugin(DalamudPluginInterface pluginInterface, CommandManager commandManager,
Framework framework, ObjectTable objectTable, ClientState clientState) Framework framework, ObjectTable objectTable, ClientState clientState)
@@ -58,16 +59,17 @@ namespace MareSynchronos
_playerWatcher.Enable(); _playerWatcher.Enable();
var uiSharedComponent = var uiSharedComponent =
new UIShared(_ipcManager, _apiController, _fileCacheManager, _configuration); new UiShared(_ipcManager, _apiController, _fileCacheManager, _configuration);
_pluginUi = new PluginUi(_windowSystem, uiSharedComponent, _configuration, _apiController); _pluginUi = new PluginUi(_windowSystem, uiSharedComponent, _configuration, _apiController);
_introUi = new IntroUI(_windowSystem, uiSharedComponent, _configuration, _fileCacheManager); _introUi = new IntroUi(_windowSystem, uiSharedComponent, _configuration, _fileCacheManager);
_introUi.FinishedRegistration += (_, _) => _introUi.FinishedRegistration += (_, _) =>
{ {
_introUi.IsOpen = false; _introUi.IsOpen = false;
_pluginUi.IsOpen = true; _pluginUi.IsOpen = true;
ReLaunchCharacterManager(); ReLaunchCharacterManager();
}; };
_downloadUi = new DownloadUi(_windowSystem, _configuration, _apiController);
new FileCacheContext().Dispose(); // make sure db is initialized I guess new FileCacheContext().Dispose(); // make sure db is initialized I guess
@@ -91,6 +93,7 @@ namespace MareSynchronos
_pluginUi?.Dispose(); _pluginUi?.Dispose();
_introUi?.Dispose(); _introUi?.Dispose();
_downloadUi?.Dispose();
_fileCacheManager?.Dispose(); _fileCacheManager?.Dispose();
_ipcManager?.Dispose(); _ipcManager?.Dispose();

View File

@@ -0,0 +1,88 @@
using System;
using System.Linq;
using System.Numerics;
using Dalamud.Interface.Windowing;
using ImGuiNET;
using MareSynchronos.Utils;
using MareSynchronos.WebAPI;
namespace MareSynchronos.UI;
public class DownloadUi : Window, IDisposable
{
private readonly WindowSystem _windowSystem;
private readonly Configuration _pluginConfiguration;
private readonly ApiController _apiController;
public void Dispose()
{
Logger.Debug("Disposing " + nameof(DownloadUi));
_windowSystem.RemoveWindow(this);
}
public DownloadUi(WindowSystem windowSystem, Configuration pluginConfiguration, ApiController apiController) : base("Mare Synchronos Downloads")
{
Logger.Debug("Creating " + nameof(DownloadUi));
_windowSystem = windowSystem;
_pluginConfiguration = pluginConfiguration;
_apiController = apiController;
SizeConstraints = new WindowSizeConstraints()
{
MaximumSize = new(300, 90),
MinimumSize = new(300, 90)
};
Flags = ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoBackground;
windowSystem.AddWindow(this);
IsOpen = true;
}
public override void Draw()
{
if (!_pluginConfiguration.ShowTransferWindow) return;
if (!_apiController.IsDownloading && !_apiController.IsUploading) return;
var drawList = ImGui.GetWindowDrawList();
var yDistance = 20;
var xDistance = 20;
var basePosition = ImGui.GetWindowPos() + ImGui.GetWindowContentRegionMin();
if (_apiController.IsUploading)
{
var doneUploads = _apiController.CurrentUploads.Count(c => c.Value.Item1 == c.Value.Item2);
var totalUploads = _apiController.CurrentUploads.Keys.Count;
var totalUploaded = _apiController.CurrentUploads.Sum(c => c.Value.Item1);
var totalToUpload = _apiController.CurrentUploads.Sum(c => c.Value.Item2);
UiShared.DrawOutlinedFont(drawList, "▲",
new Vector2(basePosition.X + 0, basePosition.Y + (int)(yDistance * 0.5)),
UiShared.Color(255, 255, 255, 255), UiShared.Color(0, 0, 0, 255), 2);
UiShared.DrawOutlinedFont(drawList, $"Uploading {doneUploads}/{totalUploads}",
new Vector2(basePosition.X + xDistance, basePosition.Y + yDistance * 0),
UiShared.Color(255, 255, 255, 255), UiShared.Color(0, 0, 0, 255), 2);
UiShared.DrawOutlinedFont(drawList, $"{UiShared.ByteToString(totalUploaded)}/{UiShared.ByteToString(totalToUpload)}",
new Vector2(basePosition.X + xDistance, basePosition.Y + yDistance * 1),
UiShared.Color(255, 255, 255, 255), UiShared.Color(0, 0, 0, 255), 2);
}
if (_apiController.IsDownloading)
{
var multBase = _apiController.IsDownloading ? 0 : 2;
var doneDownloads = _apiController.CurrentDownloads.Count(c => c.Value.Item1 == c.Value.Item2);
var totalDownloads = _apiController.CurrentDownloads.Keys.Count;
var totalDownloaded = _apiController.CurrentDownloads.Sum(c => c.Value.Item1);
var totalToDownload = _apiController.CurrentDownloads.Sum(c => c.Value.Item2);
UiShared.DrawOutlinedFont(drawList, "▼",
new Vector2(basePosition.X + 0, basePosition.Y + (int)(yDistance * multBase + (yDistance * 0.5))),
UiShared.Color(255, 255, 255, 255), UiShared.Color(0, 0, 0, 255), 2);
UiShared.DrawOutlinedFont(drawList, $"Downloading {doneDownloads}/{totalDownloads}",
new Vector2(basePosition.X + xDistance, basePosition.Y + yDistance * multBase),
UiShared.Color(255, 255, 255, 255), UiShared.Color(0, 0, 0, 255), 2);
UiShared.DrawOutlinedFont(drawList, $"{UiShared.ByteToString(totalDownloaded)}/{UiShared.ByteToString(totalToDownload)}",
new Vector2(basePosition.X + xDistance, basePosition.Y + yDistance * (1 + multBase)),
UiShared.Color(255, 255, 255, 255), UiShared.Color(0, 0, 0, 255), 2);
}
}
}

View File

@@ -7,9 +7,9 @@ using MareSynchronos.Utils;
namespace MareSynchronos.UI namespace MareSynchronos.UI
{ {
internal class IntroUI : Window, IDisposable internal class IntroUi : Window, IDisposable
{ {
private readonly UIShared _uiShared; private readonly UiShared _uiShared;
private readonly Configuration _pluginConfiguration; private readonly Configuration _pluginConfiguration;
private readonly FileCacheManager _fileCacheManager; private readonly FileCacheManager _fileCacheManager;
private readonly WindowSystem _windowSystem; private readonly WindowSystem _windowSystem;
@@ -19,14 +19,16 @@ namespace MareSynchronos.UI
public void Dispose() public void Dispose()
{ {
Logger.Debug("Disposing " + nameof(IntroUI)); Logger.Debug("Disposing " + nameof(IntroUi));
_windowSystem.RemoveWindow(this); _windowSystem.RemoveWindow(this);
} }
public IntroUI(WindowSystem windowSystem, UIShared uiShared, Configuration pluginConfiguration, public IntroUi(WindowSystem windowSystem, UiShared uiShared, Configuration pluginConfiguration,
FileCacheManager fileCacheManager) : base("Mare Synchronos Setup") FileCacheManager fileCacheManager) : base("Mare Synchronos Setup")
{ {
Logger.Debug("Creating " + nameof(IntroUi));
_uiShared = uiShared; _uiShared = uiShared;
_pluginConfiguration = pluginConfiguration; _pluginConfiguration = pluginConfiguration;
_fileCacheManager = fileCacheManager; _fileCacheManager = fileCacheManager;
@@ -54,12 +56,12 @@ namespace MareSynchronos.UI
ImGui.Text("Welcome to Mare Synchronos!"); ImGui.Text("Welcome to Mare Synchronos!");
ImGui.SetWindowFontScale(1.0f); ImGui.SetWindowFontScale(1.0f);
ImGui.Separator(); ImGui.Separator();
UIShared.TextWrapped("Mare Synchronos is a plugin that will replicate your full current character state including all Penumbra mods to other paired Mare Synchronos users. " + UiShared.TextWrapped("Mare Synchronos is a plugin that will replicate your full current character state including all Penumbra mods to other paired Mare Synchronos users. " +
"Note that you will have to have Penumbra as well as Glamourer installed to use this plugin."); "Note that you will have to have Penumbra as well as Glamourer installed to use this plugin.");
UIShared.TextWrapped("We will have to setup a few things first before you can start using this plugin. Click on next to continue."); UiShared.TextWrapped("We will have to setup a few things first before you can start using this plugin. Click on next to continue.");
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow); ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow);
UIShared.TextWrapped("Note: Any modifications you have applied through anything but Penumbra cannot be shared and your character state on other clients " + UiShared.TextWrapped("Note: Any modifications you have applied through anything but Penumbra cannot be shared and your character state on other clients " +
"might look broken because of this. If you want to use this plugin you will have to move your mods to Penumbra."); "might look broken because of this. If you want to use this plugin you will have to move your mods to Penumbra.");
ImGui.PopStyleColor(); ImGui.PopStyleColor();
if (!_uiShared.DrawOtherPluginState()) return; if (!_uiShared.DrawOtherPluginState()) return;
@@ -82,25 +84,25 @@ namespace MareSynchronos.UI
ImGui.TextColored(ImGuiColors.DalamudRed, readThis); ImGui.TextColored(ImGuiColors.DalamudRed, readThis);
ImGui.SetWindowFontScale(1.0f); ImGui.SetWindowFontScale(1.0f);
ImGui.Separator(); ImGui.Separator();
UIShared.TextWrapped("All of the mod files currently active on your character as well as your current character state will be uploaded to the service you registered yourself at automatically. " + UiShared.TextWrapped("All of the mod files currently active on your character as well as your current character state will be uploaded to the service you registered yourself at automatically. " +
"The plugin will exclusively upload the necessary mod files and not the whole mod."); "The plugin will exclusively upload the necessary mod files and not the whole mod.");
UIShared.TextWrapped("If you are on a data capped internet connection, higher fees due to data usage depending on the amount of downloaded and uploaded mod files might occur. " + UiShared.TextWrapped("If you are on a data capped internet connection, higher fees due to data usage depending on the amount of downloaded and uploaded mod files might occur. " +
"Mod files will be compressed on up- and download to save on bandwidth usage. Due to varying up- and download speeds, changes in characters might not be visible immediately. " + "Mod files will be compressed on up- and download to save on bandwidth usage. Due to varying up- and download speeds, changes in characters might not be visible immediately. " +
"Files present on the service that already represent your active mod files will not be uploaded again."); "Files present on the service that already represent your active mod files will not be uploaded again.");
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed); ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
UIShared.TextWrapped("The mod files you are uploading are confidential and will not be distributed to parties other than the ones who are requesting the exact same mod files. " + UiShared.TextWrapped("The mod files you are uploading are confidential and will not be distributed to parties other than the ones who are requesting the exact same mod files. " +
"Please think about who you are going to pair since it is unavoidable that they will receive and locally cache the necessary mod files that you have currently in use. " + "Please think about who you are going to pair since it is unavoidable that they will receive and locally cache the necessary mod files that you have currently in use. " +
"Locally cached mod files will have arbitrary file names to discourage attempts at replicating the original mod."); "Locally cached mod files will have arbitrary file names to discourage attempts at replicating the original mod.");
ImGui.PopStyleColor(); ImGui.PopStyleColor();
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow); ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow);
UIShared.TextWrapped("The plugin creator tried their best to keep you secure. However, there is no guarantee for 100% security. Do not blindly pair your client with everyone."); UiShared.TextWrapped("The plugin creator tried their best to keep you secure. However, there is no guarantee for 100% security. Do not blindly pair your client with everyone.");
ImGui.PopStyleColor(); ImGui.PopStyleColor();
UIShared.TextWrapped("Mod files that are saved on the service will remain on the service as long as there are requests for the files from clients. " + UiShared.TextWrapped("Mod files that are saved on the service will remain on the service as long as there are requests for the files from clients. " +
"After a period of not being used, the mod files will be automatically deleted. " + "After a period of not being used, the mod files will be automatically deleted. " +
"You will also be able to wipe all the files you have personally uploaded on request. " + "You will also be able to wipe all the files you have personally uploaded on request. " +
"The service holds no information about which mod files belong to which mod."); "The service holds no information about which mod files belong to which mod.");
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed); ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
UIShared.TextWrapped("This service is provided as-is. In case of abuse, contact darkarchon#4313 on Discord or join the Mare Synchronos Discord. " + UiShared.TextWrapped("This service is provided as-is. In case of abuse, contact darkarchon#4313 on Discord or join the Mare Synchronos Discord. " +
"To accept those conditions hold CTRL while clicking 'I agree'"); "To accept those conditions hold CTRL while clicking 'I agree'");
ImGui.PopStyleColor(); ImGui.PopStyleColor();
ImGui.Separator(); ImGui.Separator();
@@ -120,12 +122,12 @@ namespace MareSynchronos.UI
ImGui.Text("File Cache Setup"); ImGui.Text("File Cache Setup");
ImGui.SetWindowFontScale(1.0f); ImGui.SetWindowFontScale(1.0f);
ImGui.Separator(); ImGui.Separator();
UIShared.TextWrapped("To not unnecessary download files already present on your computer, Mare Synchronos will have to scan your Penumbra mod directory. " + UiShared.TextWrapped("To not unnecessary download files already present on your computer, Mare Synchronos will have to scan your Penumbra mod directory. " +
"Additionally, a local cache folder must be set where Mare Synchronos will download its local file cache to. " + "Additionally, a local cache folder must be set where Mare Synchronos will download its local file cache to. " +
"Once the Cache Folder is set and the scan complete, this page will automatically forward to registration at a service."); "Once the Cache Folder is set and the scan complete, this page will automatically forward to registration at a service.");
UIShared.TextWrapped("Note: The initial scan, depending on the amount of mods you have, might take a while. Please wait until it is completed."); UiShared.TextWrapped("Note: The initial scan, depending on the amount of mods you have, might take a while. Please wait until it is completed.");
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow); ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow);
UIShared.TextWrapped("Warning: once past this step you should not delete the FileCache.db of Mare Synchronos in the Plugin Configurations folder of Dalamud. " + UiShared.TextWrapped("Warning: once past this step you should not delete the FileCache.db of Mare Synchronos in the Plugin Configurations folder of Dalamud. " +
"Otherwise on the next launch a full re-scan of the file cache database will be initiated."); "Otherwise on the next launch a full re-scan of the file cache database will be initiated.");
ImGui.PopStyleColor(); ImGui.PopStyleColor();
_uiShared.DrawCacheDirectorySetting(); _uiShared.DrawCacheDirectorySetting();
@@ -133,7 +135,7 @@ namespace MareSynchronos.UI
if (!_fileCacheManager.IsScanRunning) if (!_fileCacheManager.IsScanRunning)
{ {
UIShared.TextWrapped("You can adjust how many parallel threads will be used for scanning. Mind that ultimately it will depend on the amount of mods, your disk speed and your CPU. " + UiShared.TextWrapped("You can adjust how many parallel threads will be used for scanning. Mind that ultimately it will depend on the amount of mods, your disk speed and your CPU. " +
"More is not necessarily better, the default of 10 should be fine for most cases."); "More is not necessarily better, the default of 10 should be fine for most cases.");
_uiShared.DrawParallelScansSetting(); _uiShared.DrawParallelScansSetting();
@@ -157,18 +159,18 @@ namespace MareSynchronos.UI
if (_pluginConfiguration.ClientSecret.ContainsKey(_pluginConfiguration.ApiUri)) if (_pluginConfiguration.ClientSecret.ContainsKey(_pluginConfiguration.ApiUri))
{ {
ImGui.Separator(); ImGui.Separator();
UIShared.TextWrapped(_pluginConfiguration.ClientSecret[_pluginConfiguration.ApiUri]); UiShared.TextWrapped(_pluginConfiguration.ClientSecret[_pluginConfiguration.ApiUri]);
ImGui.Separator(); ImGui.Separator();
if (ImGui.Button("Copy secret key to clipboard")) if (ImGui.Button("Copy secret key to clipboard"))
{ {
ImGui.SetClipboardText(_pluginConfiguration.ClientSecret[_pluginConfiguration.ApiUri]); ImGui.SetClipboardText(_pluginConfiguration.ClientSecret[_pluginConfiguration.ApiUri]);
} }
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow); ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow);
UIShared.TextWrapped("This is the only time you will be able to see this key in the UI. You can copy it to make a backup somewhere."); UiShared.TextWrapped("This is the only time you will be able to see this key in the UI. You can copy it to make a backup somewhere.");
ImGui.PopStyleColor(); ImGui.PopStyleColor();
ImGui.Separator(); ImGui.Separator();
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.ParsedGreen); ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.ParsedGreen);
UIShared.TextWrapped("You are now ready to go. Press Finish to finalize the settings and open the Mare Synchronos main UI."); UiShared.TextWrapped("You are now ready to go. Press Finish to finalize the settings and open the Mare Synchronos main UI.");
ImGui.PopStyleColor(); ImGui.PopStyleColor();
ImGui.Separator(); ImGui.Separator();
if (ImGui.Button("Finish##finishIntro")) if (ImGui.Button("Finish##finishIntro"))
@@ -179,13 +181,13 @@ namespace MareSynchronos.UI
} }
else else
{ {
UIShared.TextWrapped("You will now have to register at a service. You can use the provided central service or pick a custom one. " + UiShared.TextWrapped("You will now have to register at a service. You can use the provided central service or pick a custom one. " +
"There is no support for custom services from the plugin creator. Use at your own risk."); "There is no support for custom services from the plugin creator. Use at your own risk.");
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed); ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
UIShared.TextWrapped("On registration on a service the plugin will create and save a secret key to your plugin configuration. " + UiShared.TextWrapped("On registration on a service the plugin will create and save a secret key to your plugin configuration. " +
"Make a backup of your secret key. In case of loss, it cannot be restored. The secret key is your identification to the service " + "Make a backup of your secret key. In case of loss, it cannot be restored. The secret key is your identification to the service " +
"to verify who you are. It is directly tied to the UID you will be receiving. In case of loss, you will have to re-register an account."); "to verify who you are. It is directly tied to the UID you will be receiving. In case of loss, you will have to re-register an account.");
UIShared.TextWrapped("Do not ever, under any circumstances, share your secret key to anyone! Likewise do not share your Mare Synchronos plugin configuration to anyone!"); UiShared.TextWrapped("Do not ever, under any circumstances, share your secret key to anyone! Likewise do not share your Mare Synchronos plugin configuration to anyone!");
ImGui.PopStyleColor(); ImGui.PopStyleColor();
_uiShared.DrawServiceSelection(); _uiShared.DrawServiceSelection();
} }

View File

@@ -5,21 +5,23 @@ using ImGuiNET;
using MareSynchronos.WebAPI; using MareSynchronos.WebAPI;
using System; using System;
using System.Linq; using System.Linq;
using MareSynchronos.Managers; using System.Threading.Tasks;
using MareSynchronos.Utils; using MareSynchronos.Utils;
namespace MareSynchronos.UI namespace MareSynchronos.UI
{ {
class PluginUi : Window, IDisposable public class PluginUi : Window, IDisposable
{ {
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly WindowSystem _windowSystem; private readonly WindowSystem _windowSystem;
private readonly ApiController _apiController; private readonly ApiController _apiController;
private readonly UIShared _uiShared; private readonly UiShared _uiShared;
public PluginUi(WindowSystem windowSystem, public PluginUi(WindowSystem windowSystem,
UIShared uiShared, Configuration configuration, ApiController apiController) : base("Mare Synchronos Settings", ImGuiWindowFlags.None) UiShared uiShared, Configuration configuration, ApiController apiController) : base("Mare Synchronos Settings", ImGuiWindowFlags.None)
{ {
Logger.Debug("Creating " + nameof(PluginUi));
SizeConstraints = new WindowSizeConstraints() SizeConstraints = new WindowSizeConstraints()
{ {
MinimumSize = new(800, 400), MinimumSize = new(800, 400),
@@ -85,6 +87,7 @@ namespace MareSynchronos.UI
DrawPairedClientsContent(); DrawPairedClientsContent();
DrawFileCacheSettings(); DrawFileCacheSettings();
DrawCurrentTransfers(); DrawCurrentTransfers();
DrawAdministration();
} }
else else
{ {
@@ -93,16 +96,36 @@ namespace MareSynchronos.UI
} }
} }
private void DrawAdministration()
{
if (ImGui.TreeNode(
$"User Administration"))
{
if (ImGui.Button("Delete all my files"))
{
Task.Run(() => _apiController.DeleteAllMyFiles());
}
ImGui.TreePop();
}
}
private void DrawCurrentTransfers() private void DrawCurrentTransfers()
{ {
if (ImGui.TreeNode( if (ImGui.TreeNode(
$"Current Transfers")) $"Current Transfers"))
{ {
bool showTransferWindow = _configuration.ShowTransferWindow;
if (ImGui.Checkbox("Show separate Transfer window while transfers are active", ref showTransferWindow))
{
_configuration.ShowTransferWindow = showTransferWindow;
_configuration.Save();
}
if (ImGui.BeginTable("TransfersTable", 2)) if (ImGui.BeginTable("TransfersTable", 2))
{ {
ImGui.TableSetupColumn( ImGui.TableSetupColumn(
$"Uploads ({UIShared.ByteToKiB(_apiController.CurrentUploads.Sum(a => a.Value.Item1))} / {UIShared.ByteToKiB(_apiController.CurrentUploads.Sum(a => a.Value.Item2))})"); $"Uploads ({UiShared.ByteToString(_apiController.CurrentUploads.Sum(a => a.Value.Item1))} / {UiShared.ByteToString(_apiController.CurrentUploads.Sum(a => a.Value.Item2))})");
ImGui.TableSetupColumn($"Downloads ({UIShared.ByteToKiB(_apiController.CurrentDownloads.Sum(a => a.Value.Item1))} / {UIShared.ByteToKiB(_apiController.CurrentDownloads.Sum(a => a.Value.Item2))})"); ImGui.TableSetupColumn($"Downloads ({UiShared.ByteToString(_apiController.CurrentDownloads.Sum(a => a.Value.Item1))} / {UiShared.ByteToString(_apiController.CurrentDownloads.Sum(a => a.Value.Item2))})");
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
@@ -115,14 +138,14 @@ namespace MareSynchronos.UI
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
foreach (var hash in _apiController.CurrentUploads.Keys) foreach (var hash in _apiController.CurrentUploads.Keys)
{ {
var color = UIShared.UploadColor(_apiController.CurrentUploads[hash]); var color = UiShared.UploadColor(_apiController.CurrentUploads[hash]);
ImGui.PushStyleColor(ImGuiCol.Text, color); ImGui.PushStyleColor(ImGuiCol.Text, color);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Text(hash); ImGui.Text(hash);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Text(UIShared.ByteToKiB(_apiController.CurrentUploads[hash].Item1)); ImGui.Text(UiShared.ByteToString(_apiController.CurrentUploads[hash].Item1));
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Text(UIShared.ByteToKiB(_apiController.CurrentUploads[hash].Item2)); ImGui.Text(UiShared.ByteToString(_apiController.CurrentUploads[hash].Item2));
ImGui.PopStyleColor(); ImGui.PopStyleColor();
ImGui.TableNextRow(); ImGui.TableNextRow();
} }
@@ -139,14 +162,14 @@ namespace MareSynchronos.UI
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
foreach (var hash in _apiController.CurrentDownloads.Keys) foreach (var hash in _apiController.CurrentDownloads.Keys)
{ {
var color = UIShared.UploadColor(_apiController.CurrentDownloads[hash]); var color = UiShared.UploadColor(_apiController.CurrentDownloads[hash]);
ImGui.PushStyleColor(ImGuiCol.Text, color); ImGui.PushStyleColor(ImGuiCol.Text, color);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Text(hash); ImGui.Text(hash);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Text(UIShared.ByteToKiB(_apiController.CurrentDownloads[hash].Item1)); ImGui.Text(UiShared.ByteToString(_apiController.CurrentDownloads[hash].Item1));
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Text(UIShared.ByteToKiB(_apiController.CurrentDownloads[hash].Item2)); ImGui.Text(UiShared.ByteToString(_apiController.CurrentDownloads[hash].Item2));
ImGui.PopStyleColor(); ImGui.PopStyleColor();
ImGui.TableNextRow(); ImGui.TableNextRow();
} }
@@ -199,13 +222,13 @@ namespace MareSynchronos.UI
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.TextColored( ImGui.TextColored(
UIShared.GetBoolColor(item.IsSynced && !item.IsPausedFromOthers && !item.IsPaused), UiShared.GetBoolColor(item.IsSynced && !item.IsPausedFromOthers && !item.IsPaused),
item.OtherUID); item.OtherUID);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
string pairString = !item.IsSynced string pairString = !item.IsSynced
? "Has not added you" ? "Has not added you"
: ((item.IsPaused || item.IsPausedFromOthers) ? "Unpaired" : "Paired"); : ((item.IsPaused || item.IsPausedFromOthers) ? "Unpaired" : "Paired");
ImGui.TextColored(UIShared.GetBoolColor(item.IsSynced && !item.IsPaused && !item.IsPausedFromOthers), pairString); ImGui.TextColored(UiShared.GetBoolColor(item.IsSynced && !item.IsPaused && !item.IsPausedFromOthers), pairString);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
string charComment = _configuration.UidComments.ContainsKey(item.OtherUID) ? _configuration.UidComments[item.OtherUID] : string.Empty; string charComment = _configuration.UidComments.ContainsKey(item.OtherUID) ? _configuration.UidComments[item.OtherUID] : string.Empty;
ImGui.SetNextItemWidth(400); ImGui.SetNextItemWidth(400);

View File

@@ -9,14 +9,14 @@ using MareSynchronos.WebAPI;
namespace MareSynchronos.UI namespace MareSynchronos.UI
{ {
internal class UIShared public class UiShared
{ {
private readonly IpcManager _ipcManager; private readonly IpcManager _ipcManager;
private readonly ApiController _apiController; private readonly ApiController _apiController;
private readonly FileCacheManager _fileCacheManager; private readonly FileCacheManager _fileCacheManager;
private readonly Configuration _pluginConfiguration; private readonly Configuration _pluginConfiguration;
public UIShared(IpcManager ipcManager, ApiController apiController, FileCacheManager fileCacheManager, Configuration pluginConfiguration) public UiShared(IpcManager ipcManager, ApiController apiController, FileCacheManager fileCacheManager, Configuration pluginConfiguration)
{ {
_ipcManager = ipcManager; _ipcManager = ipcManager;
_apiController = apiController; _apiController = apiController;
@@ -87,7 +87,45 @@ namespace MareSynchronos.UI
public static Vector4 UploadColor((long, long) data) => data.Item1 == 0 ? ImGuiColors.DalamudGrey : public static Vector4 UploadColor((long, long) data) => data.Item1 == 0 ? ImGuiColors.DalamudGrey :
data.Item1 == data.Item2 ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudYellow; data.Item1 == data.Item2 ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudYellow;
public static string ByteToKiB(long bytes) => (bytes / 1024.0).ToString("0.00") + " KiB"; public static uint Color(byte r, byte g, byte b, byte a)
{ uint ret = a; ret <<= 8; ret += b; ret <<= 8; ret += g; ret <<= 8; ret += r; return ret; }
public static void DrawOutlinedFont(ImDrawListPtr drawList, string text, Vector2 textPos, uint fontColor, uint outlineColor, int thickness)
{
drawList.AddText(textPos with { Y = textPos.Y - thickness },
outlineColor, text);
drawList.AddText(textPos with { X = textPos.X - thickness },
outlineColor, text);
drawList.AddText(textPos with { Y = textPos.Y + thickness },
outlineColor, text);
drawList.AddText(textPos with { X = textPos.X + thickness },
outlineColor, text);
drawList.AddText(new Vector2(textPos.X - thickness, textPos.Y - thickness),
outlineColor, text);
drawList.AddText(new Vector2(textPos.X + thickness, textPos.Y + thickness),
outlineColor, text);
drawList.AddText(new Vector2(textPos.X - thickness, textPos.Y + thickness),
outlineColor, text);
drawList.AddText(new Vector2(textPos.X + thickness, textPos.Y - thickness),
outlineColor, text);
drawList.AddText(textPos, fontColor, text);
drawList.AddText(textPos, fontColor, text);
}
public static string ByteToString(long bytes)
{
double output = bytes;
var suffix = new[] { "B", "KiB", "MiB", "GiB" };
var suffixIdx = 0;
while (output / 1024.0 > 1024)
{
output /= 1024.0;
suffixIdx++;
}
return output.ToString("0.00") + " " + suffix[suffixIdx];
}
private int _serverSelectionIndex = 0; private int _serverSelectionIndex = 0;

View File

@@ -119,8 +119,10 @@ namespace MareSynchronos.WebAPI
CurrentDownloads[file.Hash] = (0, fileSize); CurrentDownloads[file.Hash] = (0, fileSize);
} }
List<string> downloadedHashes = new();
foreach (var file in fileReplacementDto.Where(f => CurrentDownloads[f.Hash].Item2 > 0)) foreach (var file in fileReplacementDto.Where(f => CurrentDownloads[f.Hash].Item2 > 0))
{ {
if (downloadedHashes.Contains(file.Hash)) continue;
var hash = file.Hash; var hash = file.Hash;
var data = await DownloadFile(hash); var data = await DownloadFile(hash);
var extractedFile = LZ4Codec.Unwrap(data); var extractedFile = LZ4Codec.Unwrap(data);
@@ -128,6 +130,7 @@ namespace MareSynchronos.WebAPI
var filePath = Path.Combine(_pluginConfiguration.CacheFolder, file.Hash + "." + ext); var filePath = Path.Combine(_pluginConfiguration.CacheFolder, file.Hash + "." + ext);
await File.WriteAllBytesAsync(filePath, extractedFile); await File.WriteAllBytesAsync(filePath, extractedFile);
Logger.Debug("File downloaded to " + filePath); Logger.Debug("File downloaded to " + filePath);
downloadedHashes.Add(hash);
} }
CurrentDownloads.Clear(); CurrentDownloads.Clear();
@@ -311,6 +314,11 @@ namespace MareSynchronos.WebAPI
long fileSize = await _fileHub!.InvokeAsync<long>("GetFileSize", hash); long fileSize = await _fileHub!.InvokeAsync<long>("GetFileSize", hash);
} }
public async Task DeleteAllMyFiles()
{
await _fileHub!.SendAsync("DeleteAllFiles");
}
private async Task DisposeHubConnections() private async Task DisposeHubConnections()
{ {
if (_fileHub != null) if (_fileHub != null)
@@ -430,6 +438,7 @@ namespace MareSynchronos.WebAPI
UnpairedFromOther?.Invoke(characterIdentifier, EventArgs.Empty); UnpairedFromOther?.Invoke(characterIdentifier, EventArgs.Empty);
} }
} }
private async Task UploadFile(byte[] compressedFile, string fileHash, CancellationToken uploadToken) private async Task UploadFile(byte[] compressedFile, string fileHash, CancellationToken uploadToken)
{ {
if (uploadToken.IsCancellationRequested) return; if (uploadToken.IsCancellationRequested) return;