"Amélioration de l'UI AutoDetect Syncshell : ajout de paramètres récurrents, plages horaires et gestion des fuseaux horaires. Refactorisation des méthodes de dessin et introduction de boutons centrés pour une meilleure ergonomie. Mise à jour des fichiers de configuration et du projet avec des optimisations diverses."

This commit is contained in:
2025-11-02 00:26:11 +01:00
parent 620ebf9195
commit 7a391e6253
9 changed files with 312 additions and 20 deletions

3
.gitignore vendored
View File

@@ -3,6 +3,7 @@
## ##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
.idea .idea
qodana.yaml
# User-specific files # User-specific files
*.rsuser *.rsuser
*.suo *.suo
@@ -13,6 +14,8 @@
MareSynchronos/.DS_Store MareSynchronos/.DS_Store
*.zip *.zip
UmbraServer_extracted/ UmbraServer_extracted/
NuGet.config
Directory.Build.props
# User-specific files (MonoDevelop/Xamarin Studio) # User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs *.userprefs

Submodule MareAPI updated: deb911cb0a...f75f16fb13

View File

@@ -50,6 +50,8 @@
<PropertyGroup> <PropertyGroup>
<SourceRevisionId>build$([System.DateTime]::UtcNow.ToString("yyyy-MM-ddTHH:mm:ss:fffZ"))</SourceRevisionId> <SourceRevisionId>build$([System.DateTime]::UtcNow.ToString("yyyy-MM-ddTHH:mm:ss:fffZ"))</SourceRevisionId>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<DisablePackageVulnerabilityAnalysis>true</DisablePackageVulnerabilityAnalysis>
<NoWarn>$(NoWarn);NU1900</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -73,6 +73,13 @@ public sealed class SyncshellDiscoveryService : IHostedService, IMediatorSubscri
} }
public async Task<bool> SetVisibilityAsync(string gid, bool visible, CancellationToken ct) public async Task<bool> SetVisibilityAsync(string gid, bool visible, CancellationToken ct)
{
return await SetVisibilityAsync(gid, visible, null, null, null, null, null, ct).ConfigureAwait(false);
}
public async Task<bool> SetVisibilityAsync(string gid, bool visible, int? displayDurationHours,
int[]? activeWeekdays, TimeSpan? timeStartLocal, TimeSpan? timeEndLocal, string? timeZone,
CancellationToken ct)
{ {
try try
{ {
@@ -80,6 +87,11 @@ public sealed class SyncshellDiscoveryService : IHostedService, IMediatorSubscri
{ {
GID = gid, GID = gid,
AutoDetectVisible = visible, AutoDetectVisible = visible,
DisplayDurationHours = displayDurationHours,
ActiveWeekdays = activeWeekdays,
TimeStartLocal = timeStartLocal.HasValue ? new DateTime(timeStartLocal.Value.Ticks).ToString("HH:mm") : null,
TimeEndLocal = timeEndLocal.HasValue ? new DateTime(timeEndLocal.Value.Ticks).ToString("HH:mm") : null,
TimeZone = timeZone,
}; };
var success = await _apiController.SyncshellDiscoverySetVisibility(request).ConfigureAwait(false); var success = await _apiController.SyncshellDiscoverySetVisibility(request).ConfigureAwait(false);
if (!success) return false; if (!success) return false;

View File

@@ -79,6 +79,8 @@ public class DrawGroupPair : DrawPairBase
width += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X + spacing; width += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X + spacing;
} }
width += spacing * 1.2f;
return width; return width;
} }
@@ -215,6 +217,7 @@ public class DrawGroupPair : DrawPairBase
var pauseIcon = _fullInfoDto.GroupUserPermissions.IsPaused() ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause; var pauseIcon = _fullInfoDto.GroupUserPermissions.IsPaused() ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
var pauseButtonWidth = _uiSharedService.GetIconButtonSize(pauseIcon).X; var pauseButtonWidth = _uiSharedService.GetIconButtonSize(pauseIcon).X;
var barButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars).X; var barButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars).X;
var rightEdgeGap = spacing * 1.2f;
float totalWidth = 0f; float totalWidth = 0f;
void Accumulate(bool condition, float width) void Accumulate(bool condition, float width)
@@ -242,7 +245,7 @@ public class DrawGroupPair : DrawPairBase
float cardPaddingX = UiSharedService.GetCardContentPaddingX(); float cardPaddingX = UiSharedService.GetCardContentPaddingX();
float rightMargin = cardPaddingX + 6f * ImGuiHelpers.GlobalScale; float rightMargin = cardPaddingX + 6f * ImGuiHelpers.GlobalScale;
float baseX = MathF.Max(ImGui.GetCursorPosX(), float baseX = MathF.Max(ImGui.GetCursorPosX(),
ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - rightMargin - totalWidth); ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - rightMargin - rightEdgeGap - totalWidth);
float currentX = baseX; float currentX = baseX;
ImGui.SameLine(); ImGui.SameLine();
@@ -266,6 +269,16 @@ public class DrawGroupPair : DrawPairBase
if (showInfo && infoIconWidth > 0f) if (showInfo && infoIconWidth > 0f)
{ {
bool centerWarning = permIcon == FontAwesomeIcon.ExclamationTriangle && showPause && showBars && !showShared && !showPlus;
if (centerWarning)
{
float barsClusterWidth = showBars ? (barButtonWidth + spacing * 0.5f) : 0f;
float leftAreaWidth = MathF.Max(totalWidth - pauseButtonWidth - barsClusterWidth, 0f);
float warningX = baseX + MathF.Max((leftAreaWidth - infoIconWidth) / 2f, 0f);
currentX = warningX;
ImGui.SetCursorPosX(currentX);
}
ImGui.SetCursorPosY(textPosY); ImGui.SetCursorPosY(textPosY);
if (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled) if (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled)
{ {
@@ -359,7 +372,7 @@ public class DrawGroupPair : DrawPairBase
{ {
ImGui.SetCursorPosY(originalY); ImGui.SetCursorPosY(originalY);
if (_uiSharedService.IconButton(FontAwesomeIcon.Plus)) if (_uiSharedService.IconPlusButtonCentered())
{ {
var targetUid = _pair.UserData.UID; var targetUid = _pair.UserData.UID;
if (!string.IsNullOrEmpty(targetUid)) if (!string.IsNullOrEmpty(targetUid))
@@ -376,7 +389,7 @@ public class DrawGroupPair : DrawPairBase
{ {
float gapToBars = showBars ? spacing * 0.5f : spacing; float gapToBars = showBars ? spacing * 0.5f : spacing;
ImGui.SetCursorPosY(originalY); ImGui.SetCursorPosY(originalY);
if (_uiSharedService.IconButton(pauseIcon)) if (pauseIcon == FontAwesomeIcon.Pause ? _uiSharedService.IconPauseButtonCentered() : _uiSharedService.IconButtonCentered(pauseIcon))
{ {
var newPermissions = _fullInfoDto.GroupUserPermissions ^ GroupUserPermissions.Paused; var newPermissions = _fullInfoDto.GroupUserPermissions ^ GroupUserPermissions.Paused;
_fullInfoDto.GroupUserPermissions = newPermissions; _fullInfoDto.GroupUserPermissions = newPermissions;
@@ -391,7 +404,7 @@ public class DrawGroupPair : DrawPairBase
if (showBars) if (showBars)
{ {
ImGui.SetCursorPosY(originalY); ImGui.SetCursorPosY(originalY);
if (_uiSharedService.IconButton(FontAwesomeIcon.Bars)) if (_uiSharedService.IconButtonCentered(FontAwesomeIcon.Bars))
{ {
ImGui.OpenPopup("Syncshell Flyout Menu"); ImGui.OpenPopup("Syncshell Flyout Menu");
} }

View File

@@ -42,8 +42,8 @@ public abstract class DrawPairBase
var menuButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars); var menuButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars);
float pauseClusterWidth = Math.Max(pauseButtonSize.X, playButtonSize.X); float pauseClusterWidth = Math.Max(pauseButtonSize.X, playButtonSize.X);
float pauseClusterHeight = Math.Max(pauseButtonSize.Y, playButtonSize.Y); float pauseClusterHeight = Math.Max(Math.Max(pauseButtonSize.Y, playButtonSize.Y), ImGui.GetFrameHeight());
float reservedSpacing = style.ItemSpacing.X * 2.4f; float reservedSpacing = style.ItemSpacing.X * 1.6f;
float rightButtonWidth = float rightButtonWidth =
menuButtonSize.X + menuButtonSize.X +
pauseClusterWidth + pauseClusterWidth +
@@ -84,11 +84,15 @@ public abstract class DrawPairBase
ImGui.SetCursorPos(new Vector2(rowStartCursor.X + padding.X, iconTop)); ImGui.SetCursorPos(new Vector2(rowStartCursor.X + padding.X, iconTop));
DrawLeftSide(iconTop, iconTop); DrawLeftSide(iconTop, iconTop);
ImGui.SameLine();
ImGui.SetCursorPosY(textTop); float leftReserved = GetLeftSideReservedWidth();
var posX = ImGui.GetCursorPosX(); float nameStartX = rowStartCursor.X + padding.X + leftReserved;
var rightSide = DrawRightSide(buttonTop, buttonTop); var rightSide = DrawRightSide(buttonTop, buttonTop);
DrawName(textTop + padding.Y * 0.15f, posX, rightSide);
ImGui.SameLine(nameStartX);
ImGui.SetCursorPosY(textTop);
DrawName(textTop + padding.Y * 0.15f, nameStartX, rightSide);
ImGui.SetCursorPos(new Vector2(rowStartCursor.X, rowStartCursor.Y + totalHeight)); ImGui.SetCursorPos(new Vector2(rowStartCursor.X, rowStartCursor.Y + totalHeight));
ImGui.SetCursorPosX(rowStartCursor.X); ImGui.SetCursorPosX(rowStartCursor.X);
@@ -100,6 +104,8 @@ public abstract class DrawPairBase
protected virtual float GetRightSideExtraWidth() => 0f; protected virtual float GetRightSideExtraWidth() => 0f;
protected virtual float GetLeftSideReservedWidth() => UiSharedService.GetIconSize(FontAwesomeIcon.Moon).X * 2f + ImGui.GetStyle().ItemSpacing.X * 1.5f;
private void DrawName(float originalY, float leftSide, float rightSide) private void DrawName(float originalY, float leftSide, float rightSide)
{ {
_displayHandler.DrawPairText(_id, _pair, leftSide, originalY, () => rightSide - leftSide); _displayHandler.DrawPairText(_id, _pair, leftSide, originalY, () => rightSide - leftSide);

View File

@@ -60,9 +60,29 @@ public class DrawUserPair : DrawPairBase
width += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X + spacingX * 0.5f; width += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X + spacingX * 0.5f;
} }
width += spacingX * 1.2f;
return width; return width;
} }
protected override float GetLeftSideReservedWidth()
{
var style = ImGui.GetStyle();
float spacing = style.ItemSpacing.X;
float iconW = UiSharedService.GetIconSize(FontAwesomeIcon.Moon).X;
int icons = 1;
if (!(_pair.UserPair!.OwnPermissions.IsPaired() && _pair.UserPair!.OtherPermissions.IsPaired()))
icons++;
else if (_pair.UserPair!.OwnPermissions.IsPaused() || _pair.UserPair!.OtherPermissions.IsPaused())
icons++;
if (_pair.IsOnline && _pair.IsVisible)
icons++;
float iconsTotal = icons * iconW + Math.Max(0, icons - 1) * spacing;
float cushion = spacing * 0.6f;
return iconsTotal + cushion;
}
protected override void DrawLeftSide(float textPosY, float originalY) protected override void DrawLeftSide(float textPosY, float originalY)
{ {
var online = _pair.IsOnline; var online = _pair.IsOnline;
@@ -133,7 +153,8 @@ public class DrawUserPair : DrawPairBase
var entryUID = _pair.UserData.AliasOrUID; var entryUID = _pair.UserData.AliasOrUID;
var spacingX = ImGui.GetStyle().ItemSpacing.X; var spacingX = ImGui.GetStyle().ItemSpacing.X;
var edgePadding = UiSharedService.GetCardContentPaddingX() + 6f * ImGuiHelpers.GlobalScale; var edgePadding = UiSharedService.GetCardContentPaddingX() + 6f * ImGuiHelpers.GlobalScale;
var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - edgePadding; var rightEdgeGap = spacingX * 1.2f;
var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - edgePadding - rightEdgeGap;
var rightSidePos = windowEndX - barButtonSize.X; var rightSidePos = windowEndX - barButtonSize.X;
// Flyout Menu // Flyout Menu
@@ -150,13 +171,12 @@ public class DrawUserPair : DrawPairBase
ImGui.EndPopup(); ImGui.EndPopup();
} }
// Pause (mutual pairs only)
if (_pair.UserPair!.OwnPermissions.IsPaired() && _pair.UserPair!.OtherPermissions.IsPaired()) if (_pair.UserPair!.OwnPermissions.IsPaired() && _pair.UserPair!.OtherPermissions.IsPaired())
{ {
rightSidePos -= pauseIconSize.X + spacingX; rightSidePos -= pauseIconSize.X + spacingX;
ImGui.SameLine(rightSidePos); ImGui.SameLine(rightSidePos);
ImGui.SetCursorPosY(originalY); ImGui.SetCursorPosY(originalY);
if (_uiSharedService.IconButton(pauseIcon)) if (pauseIcon == FontAwesomeIcon.Pause ? _uiSharedService.IconPauseButtonCentered() : _uiSharedService.IconButtonCentered(pauseIcon))
{ {
var perm = _pair.UserPair!.OwnPermissions; var perm = _pair.UserPair!.OwnPermissions;
perm.SetPaused(!perm.IsPaused()); perm.SetPaused(!perm.IsPaused());

View File

@@ -42,6 +42,16 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
private bool _autoDetectPasswordDisabled; private bool _autoDetectPasswordDisabled;
private string? _autoDetectMessage; private string? _autoDetectMessage;
private bool _autoDetectDesiredVisibility;
private int _adDurationHours = 2;
private bool _adRecurring = false;
private readonly bool[] _adWeekdays = new bool[7];
private int _adStartHour = 21;
private int _adStartMinute = 0;
private int _adEndHour = 23;
private int _adEndMinute = 0;
private const string AutoDetectTimeZone = "Europe/Paris";
public SyncshellAdminUI(ILogger<SyncshellAdminUI> logger, MareMediator mediator, ApiController apiController, public SyncshellAdminUI(ILogger<SyncshellAdminUI> logger, MareMediator mediator, ApiController apiController,
UiSharedService uiSharedService, PairManager pairManager, SyncshellDiscoveryService syncshellDiscoveryService, UiSharedService uiSharedService, PairManager pairManager, SyncshellDiscoveryService syncshellDiscoveryService,
GroupFullInfoDto groupFullInfo, PerformanceCollectorService performanceCollectorService) GroupFullInfoDto groupFullInfo, PerformanceCollectorService performanceCollectorService)
@@ -58,6 +68,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
_multiInvites = 30; _multiInvites = 30;
_pwChangeSuccess = true; _pwChangeSuccess = true;
_autoDetectVisible = groupFullInfo.AutoDetectVisible; _autoDetectVisible = groupFullInfo.AutoDetectVisible;
_autoDetectDesiredVisibility = _autoDetectVisible;
_autoDetectPasswordDisabled = groupFullInfo.PasswordTemporarilyDisabled; _autoDetectPasswordDisabled = groupFullInfo.PasswordTemporarilyDisabled;
Mediator.Subscribe<SyncshellAutoDetectStateChanged>(this, OnSyncshellAutoDetectStateChanged); Mediator.Subscribe<SyncshellAutoDetectStateChanged>(this, OnSyncshellAutoDetectStateChanged);
IsOpen = true; IsOpen = true;
@@ -89,6 +100,9 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
ImGui.Separator(); ImGui.Separator();
var perm = GroupFullInfo.GroupPermissions; var perm = GroupFullInfo.GroupPermissions;
using var tabColor = ImRaii.PushColor(ImGuiCol.Tab, UiSharedService.AccentColor);
using var tabHoverColor = ImRaii.PushColor(ImGuiCol.TabHovered, UiSharedService.AccentHoverColor);
using var tabActiveColor = ImRaii.PushColor(ImGuiCol.TabActive, UiSharedService.AccentActiveColor);
using var tabbar = ImRaii.TabBar("syncshell_tab_" + GroupFullInfo.GID); using var tabbar = ImRaii.TabBar("syncshell_tab_" + GroupFullInfo.GID);
if (tabbar) if (tabbar)
@@ -498,28 +512,95 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
UiSharedService.ColorTextWrapped(_autoDetectMessage!, ImGuiColors.DalamudYellow); UiSharedService.ColorTextWrapped(_autoDetectMessage!, ImGuiColors.DalamudYellow);
} }
bool desiredVisibility = _autoDetectVisible;
using (ImRaii.Disabled(_autoDetectToggleInFlight || _autoDetectStateLoading)) using (ImRaii.Disabled(_autoDetectToggleInFlight || _autoDetectStateLoading))
{ {
if (ImGui.Checkbox("Afficher cette Syncshell dans l'AutoDetect", ref desiredVisibility)) if (ImGui.Checkbox("Afficher cette Syncshell dans l'AutoDetect", ref _autoDetectDesiredVisibility))
{ {
_ = ToggleAutoDetectAsync(desiredVisibility); // Only change local desired state; sending is done via the validate button
} }
} }
_uiSharedService.DrawHelpText("Quand cette option est activée, le mot de passe devient inactif tant que la visibilité est maintenue."); _uiSharedService.DrawHelpText("Quand cette option est activée, le mot de passe devient inactif tant que la visibilité est maintenue.");
if (_autoDetectDesiredVisibility)
{
ImGuiHelpers.ScaledDummy(4);
ImGui.TextUnformatted("Options d'affichage AutoDetect");
ImGui.Separator();
// Recurring toggle first
ImGui.Checkbox("Affichage récurrent", ref _adRecurring);
_uiSharedService.DrawHelpText("Si activé, vous pouvez choisir les jours et une plage horaire récurrents. Si désactivé, seule la durée sera prise en compte.");
// Duration in hours (only when NOT recurring)
if (!_adRecurring)
{
ImGuiHelpers.ScaledDummy(4);
int duration = _adDurationHours;
ImGui.PushItemWidth(120 * ImGuiHelpers.GlobalScale);
if (ImGui.InputInt("Durée (heures)", ref duration))
{
_adDurationHours = Math.Clamp(duration, 1, 240);
}
ImGui.PopItemWidth();
_uiSharedService.DrawHelpText("Combien de temps la Syncshell doit rester visible, en heures.");
}
ImGuiHelpers.ScaledDummy(4);
if (_adRecurring)
{
ImGuiHelpers.ScaledDummy(4);
ImGui.TextUnformatted("Jours de la semaine actifs :");
string[] daysFr = new[] { "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim" };
for (int i = 0; i < 7; i++)
{
ImGui.SameLine(i == 0 ? 0 : 0);
bool v = _adWeekdays[i];
if (ImGui.Checkbox($"##adwd{i}", ref v)) _adWeekdays[i] = v;
ImGui.SameLine();
ImGui.TextUnformatted(daysFr[i]);
if (i < 6) ImGui.SameLine();
}
ImGui.NewLine();
_uiSharedService.DrawHelpText("Sélectionnez les jours où l'affichage est autorisé (ex: jeudi et dimanche).");
ImGuiHelpers.ScaledDummy(4);
ImGui.TextUnformatted("Plage horaire (heure locale Europe/Paris) :");
ImGui.PushItemWidth(60 * ImGuiHelpers.GlobalScale);
ImGui.InputInt("Début heure", ref _adStartHour); ImGui.SameLine();
ImGui.InputInt("min", ref _adStartMinute);
_adStartHour = Math.Clamp(_adStartHour, 0, 23);
_adStartMinute = Math.Clamp(_adStartMinute, 0, 59);
ImGui.SameLine();
ImGui.TextUnformatted("→"); ImGui.SameLine();
ImGui.InputInt("Fin heure", ref _adEndHour); ImGui.SameLine();
ImGui.InputInt("min ", ref _adEndMinute);
_adEndHour = Math.Clamp(_adEndHour, 0, 23);
_adEndMinute = Math.Clamp(_adEndMinute, 0, 59);
ImGui.PopItemWidth();
_uiSharedService.DrawHelpText("Exemple : de 21h00 à 23h00. Le fuseau utilisé est Europe/Paris (avec changements été/hiver).");
}
}
if (_autoDetectPasswordDisabled && _autoDetectVisible) if (_autoDetectPasswordDisabled && _autoDetectVisible)
{ {
UiSharedService.ColorTextWrapped("Le mot de passe est actuellement désactivé pendant la visibilité AutoDetect.", ImGuiColors.DalamudYellow); UiSharedService.ColorTextWrapped("Le mot de passe est actuellement désactivé pendant la visibilité AutoDetect.", ImGuiColors.DalamudYellow);
} }
ImGuiHelpers.ScaledDummy(6); ImGuiHelpers.ScaledDummy(6);
using (ImRaii.Disabled(_autoDetectToggleInFlight || _autoDetectStateLoading))
{
if (ImGui.Button("Valider et envoyer"))
{
_ = SubmitAutoDetectAsync();
}
ImGui.SameLine();
if (ImGui.Button("Recharger l'état")) if (ImGui.Button("Recharger l'état"))
{ {
_autoDetectStateLoading = true; _autoDetectStateLoading = true;
_ = EnsureAutoDetectStateAsync(true); _ = EnsureAutoDetectStateAsync(true);
} }
} }
}
private async Task EnsureAutoDetectStateAsync(bool force = false) private async Task EnsureAutoDetectStateAsync(bool force = false)
{ {
@@ -580,6 +661,67 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
} }
} }
private async Task SubmitAutoDetectAsync()
{
if (_autoDetectToggleInFlight)
{
return;
}
_autoDetectToggleInFlight = true;
_autoDetectMessage = null;
try
{
// Duration always used when visible
int? duration = _autoDetectDesiredVisibility ? _adDurationHours : null;
// Scheduling fields only if recurring is enabled
int[]? weekdaysArr = null;
TimeSpan? start = null;
TimeSpan? end = null;
string? tz = null;
if (_autoDetectDesiredVisibility && _adRecurring)
{
List<int> weekdays = new();
for (int i = 0; i < 7; i++) if (_adWeekdays[i]) weekdays.Add(i);
weekdaysArr = weekdays.Count > 0 ? weekdays.ToArray() : Array.Empty<int>();
start = new TimeSpan(_adStartHour, _adStartMinute, 0);
end = new TimeSpan(_adEndHour, _adEndMinute, 0);
tz = AutoDetectTimeZone;
}
var ok = await _syncshellDiscoveryService.SetVisibilityAsync(
GroupFullInfo.GID,
_autoDetectDesiredVisibility,
duration,
weekdaysArr,
start,
end,
tz,
CancellationToken.None).ConfigureAwait(false);
if (!ok)
{
_autoDetectMessage = "Impossible d'envoyer les paramètres AutoDetect.";
return;
}
await EnsureAutoDetectStateAsync(true).ConfigureAwait(false);
_autoDetectMessage = _autoDetectDesiredVisibility
? "Paramètres AutoDetect envoyés. La Syncshell sera visible selon le planning défini."
: "La Syncshell n'est plus visible dans AutoDetect.";
}
catch (Exception ex)
{
_autoDetectMessage = $"Erreur lors de l'envoi des paramètres AutoDetect : {ex.Message}";
}
finally
{
_autoDetectToggleInFlight = false;
}
}
private void ApplyAutoDetectState(bool visible, bool passwordDisabled, bool fromServer) private void ApplyAutoDetectState(bool visible, bool passwordDisabled, bool fromServer)
{ {
_autoDetectVisible = visible; _autoDetectVisible = visible;

View File

@@ -542,6 +542,100 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
return result; return result;
} }
public bool IconButtonCentered(FontAwesomeIcon icon, float? height = null, float xOffset = 0f, float yOffset = 0f, bool square = false)
{
string text = icon.ToIconString();
ImGui.PushID($"centered-{text}");
Vector2 glyphSize;
using (IconFont.Push())
glyphSize = ImGui.CalcTextSize(text);
ImDrawListPtr drawList = ImGui.GetWindowDrawList();
Vector2 cursorScreenPos = ImGui.GetCursorScreenPos();
float frameHeight = height ?? ImGui.GetFrameHeight();
float buttonWidth = square ? frameHeight : glyphSize.X + ImGui.GetStyle().FramePadding.X * 2f;
using var hoverColor = ImRaii.PushColor(ImGuiCol.ButtonHovered, AccentHoverColor);
using var activeColor = ImRaii.PushColor(ImGuiCol.ButtonActive, AccentActiveColor);
bool clicked = ImGui.Button(string.Empty, new Vector2(buttonWidth, frameHeight));
Vector2 pos = new Vector2(
cursorScreenPos.X + (buttonWidth - glyphSize.X) / 2f + xOffset,
cursorScreenPos.Y + frameHeight / 2f - glyphSize.Y / 2f + yOffset);
using (IconFont.Push())
drawList.AddText(pos, ImGui.GetColorU32(ImGuiCol.Text), text);
ImGui.PopID();
return clicked;
}
public bool IconPauseButtonCentered(float? height = null)
{
ImGui.PushID("centered-pause-custom");
Vector2 glyphSize;
using (IconFont.Push())
glyphSize = ImGui.CalcTextSize(FontAwesomeIcon.Pause.ToIconString());
float frameHeight = height ?? ImGui.GetFrameHeight();
float buttonWidth = glyphSize.X + ImGui.GetStyle().FramePadding.X * 2f;
using var hoverColor = ImRaii.PushColor(ImGuiCol.ButtonHovered, AccentHoverColor);
using var activeColor = ImRaii.PushColor(ImGuiCol.ButtonActive, AccentActiveColor);
var drawList = ImGui.GetWindowDrawList();
var buttonTopLeft = ImGui.GetCursorScreenPos();
bool clicked = ImGui.Button(string.Empty, new Vector2(buttonWidth, frameHeight));
var textColor = ImGui.GetColorU32(ImGuiCol.Text);
float h = frameHeight * 0.55f; // bar height
float w = MathF.Max(1f, frameHeight * 0.16f); // bar width
float gap = MathF.Max(1f, w * 0.9f); // gap between bars
float total = 2f * w + gap;
float startX = buttonTopLeft.X + (buttonWidth - total) / 2f;
float startY = buttonTopLeft.Y + (frameHeight - h) / 2f;
float rounding = w * 0.35f;
drawList.AddRectFilled(new Vector2(startX, startY), new Vector2(startX + w, startY + h), textColor, rounding);
float rightX = startX + w + gap;
drawList.AddRectFilled(new Vector2(rightX, startY), new Vector2(rightX + w, startY + h), textColor, rounding);
ImGui.PopID();
return clicked;
}
public bool IconPlusButtonCentered(float? height = null)
{
ImGui.PushID("centered-plus-custom");
Vector2 glyphSize;
using (IconFont.Push())
glyphSize = ImGui.CalcTextSize(FontAwesomeIcon.Plus.ToIconString());
float frameHeight = height ?? ImGui.GetFrameHeight();
float buttonWidth = glyphSize.X + ImGui.GetStyle().FramePadding.X * 2f;
using var hoverColor = ImRaii.PushColor(ImGuiCol.ButtonHovered, AccentHoverColor);
using var activeColor = ImRaii.PushColor(ImGuiCol.ButtonActive, AccentActiveColor);
var drawList = ImGui.GetWindowDrawList();
var buttonTopLeft = ImGui.GetCursorScreenPos();
bool clicked = ImGui.Button(string.Empty, new Vector2(buttonWidth, frameHeight));
var color = ImGui.GetColorU32(ImGuiCol.Text);
float armThickness = MathF.Max(1f, frameHeight * 0.14f);
float crossSize = frameHeight * 0.55f; // total length of vertical/horizontal arms
float startX = buttonTopLeft.X + (buttonWidth - crossSize) / 2f;
float startY = buttonTopLeft.Y + (frameHeight - crossSize) / 2f;
float endX = startX + crossSize;
float endY = startY + crossSize;
float r = armThickness * 0.35f;
float hY1 = startY + (crossSize - armThickness) / 2f;
drawList.AddRectFilled(new Vector2(startX, hY1), new Vector2(endX, hY1 + armThickness), color, r);
float vX1 = startX + (crossSize - armThickness) / 2f;
drawList.AddRectFilled(new Vector2(vX1, startY), new Vector2(vX1 + armThickness, endY), color, r);
ImGui.PopID();
return clicked;
}
private bool IconTextButtonInternal(FontAwesomeIcon icon, string text, Vector4? defaultColor = null, float? width = null, bool useAccentHover = true) private bool IconTextButtonInternal(FontAwesomeIcon icon, string text, Vector4? defaultColor = null, float? width = null, bool useAccentHover = true)
{ {
int colorsPushed = 0; int colorsPushed = 0;