Préparation traduction en => fr Part1

This commit is contained in:
2025-09-21 11:27:23 +02:00
parent 17aa6e247c
commit fe731ff670
23 changed files with 1815 additions and 676 deletions

View File

@@ -1,6 +1,14 @@
{ {
"Language.DisplayName.French": "French", "Language.DisplayName.French": "French",
"Language.DisplayName.English": "English", "Language.DisplayName.English": "English",
"Settings.Plugins.MandatoryHeading": "Mandatory Plugins",
"Settings.Plugins.MandatoryLabel": "Mandatory Plugins:",
"Settings.Plugins.OptionalHeading": "Optional Addons",
"Settings.Plugins.OptionalLabel": "Optional Addons:",
"Settings.Plugins.OptionalDescription": "These addons are not required for basic operation, but without them you may not see others as intended.",
"Settings.Plugins.Tooltip.Available": "{0} is available and up to date.",
"Settings.Plugins.Tooltip.Unavailable": "{0} is unavailable or not up to date.",
"Settings.Plugins.WarningMandatoryMissing": "You need to install both Penumbra and Glamourer and keep them up to date to use Umbra.",
"Settings.General.LocalizationHeading": "Localization", "Settings.General.LocalizationHeading": "Localization",
"Settings.General.Language": "Language", "Settings.General.Language": "Language",
"Settings.General.Language.Description": "Select the plugin language. Any missing translations will be shown in English.", "Settings.General.Language.Description": "Select the plugin language. Any missing translations will be shown in English.",
@@ -16,6 +24,7 @@
"Settings.Transfers.Blocked.Description": "Files that you attempted to upload or download that were forbidden to be transferred by their creators will appear here. If you see file paths from your drive here, then those files were not allowed to be uploaded. If you see hashes, those files were not allowed to be downloaded. Ask your paired friend to send you the mod in question through other means or acquire the mod yourself.", "Settings.Transfers.Blocked.Description": "Files that you attempted to upload or download that were forbidden to be transferred by their creators will appear here. If you see file paths from your drive here, then those files were not allowed to be uploaded. If you see hashes, those files were not allowed to be downloaded. Ask your paired friend to send you the mod in question through other means or acquire the mod yourself.",
"Settings.Transfers.Blocked.Column.Hash": "Hash/Filename", "Settings.Transfers.Blocked.Column.Hash": "Hash/Filename",
"Settings.Transfers.Blocked.Column.ForbiddenBy": "Forbidden by", "Settings.Transfers.Blocked.Column.ForbiddenBy": "Forbidden by",
"Settings.Transfers.Blocked.Tab": "Blocked Transfers",
"Settings.Transfers.Heading": "Transfer Settings", "Settings.Transfers.Heading": "Transfer Settings",
"Settings.Transfers.GlobalLimit.Label": "Global Download Speed Limit", "Settings.Transfers.GlobalLimit.Label": "Global Download Speed Limit",
"Settings.Transfers.GlobalLimit.Unit.BytePerSec": "Byte/s", "Settings.Transfers.GlobalLimit.Unit.BytePerSec": "Byte/s",
@@ -46,6 +55,81 @@
"Settings.Transfers.UI.ShowUploading.Description": "This will render an 'Uploading' text at the feet of the player that is in progress of uploading data.", "Settings.Transfers.UI.ShowUploading.Description": "This will render an 'Uploading' text at the feet of the player that is in progress of uploading data.",
"Settings.Transfers.UI.ShowUploadingBigText": "Large font for 'Uploading' text", "Settings.Transfers.UI.ShowUploadingBigText": "Large font for 'Uploading' text",
"Settings.Transfers.UI.ShowUploadingBigText.Description": "This will render an 'Uploading' text in a larger font.", "Settings.Transfers.UI.ShowUploadingBigText.Description": "This will render an 'Uploading' text in a larger font.",
"Settings.Transfers.Current.Heading": "Current Transfers",
"Settings.Transfers.Current.Tab": "Transfers",
"Settings.Transfers.Current.Uploads": "Uploads",
"Settings.Transfers.Current.Uploads.Column.File": "File",
"Settings.Transfers.Current.Uploads.Column.Uploaded": "Uploaded",
"Settings.Transfers.Current.Uploads.Column.Size": "Size",
"Settings.Transfers.Current.Downloads": "Downloads",
"Settings.Transfers.Current.Downloads.Column.User": "User",
"Settings.Transfers.Current.Downloads.Column.Server": "Server",
"Settings.Transfers.Current.Downloads.Column.Files": "Files",
"Settings.Transfers.Current.Downloads.Column.Download": "Download",
"Settings.Storage.Heading": "Storage",
"Settings.Storage.Description": "Umbra stores downloaded files from paired people permanently. This is to improve loading performance and requiring less downloads. The storage governs itself by clearing data beyond the set storage size. Please set the storage size accordingly. It is not necessary to manually clear the storage.",
"Settings.Service.ActionsHeading": "Service Actions",
"Settings.Service.Actions.DeleteAccount": "Delete account",
"Settings.Service.Actions.DeleteAccountPopup": "Delete your account?",
"Settings.Service.Actions.DeleteAccount.Description": "Completely deletes your currently connected account.",
"Settings.Service.Actions.DeleteAccount.Popup.Body1": "Your account and all associated files and data on the service will be deleted.",
"Settings.Service.Actions.DeleteAccount.Popup.Body2": "Your UID will be removed from all pairing lists.",
"Settings.Service.Actions.DeleteAccount.Popup.Confirm": "Are you sure you want to continue?",
"Settings.Service.Actions.DeleteAccount.Popup.Cancel": "Cancel",
"Settings.Service.SettingsHeading": "Service & Character Settings",
"Settings.Service.ReconnectWarning": "For any changes to be applied to the current service you need to reconnect to the service.",
"Settings.Service.Tabs.CharacterAssignments": "Character Assignments",
"Settings.Service.Tabs.SecretKey": "Secret Key Management",
"Settings.Service.Tabs.ServiceSettings": "Service Settings",
"Settings.Service.Character.Assignments.Description": "Characters listed here will connect with the specified secret key.",
"Settings.Service.Character.Assignments.TooltipCurrent": "Current character",
"Settings.Service.Character.Assignments.DeleteTooltip": "Delete character assignment",
"Settings.Service.Character.Assignments.AddCurrent": "Add current character",
"Settings.Service.Character.Assignments.NoKeys": "You need to add a Secret Key first before adding Characters.",
"Settings.Service.SecretKey.DisplayName": "Secret Key Display Name",
"Settings.Service.SecretKey.Value": "Secret Key",
"Settings.Service.SecretKey.AssignCurrent": "Assign current character",
"Settings.Service.SecretKey.AssignTooltip": "Use this secret key for {0} @ {1}",
"Settings.Service.SecretKey.Delete": "Delete Secret Key",
"Settings.Service.SecretKey.DeleteTooltip": "Hold CTRL to delete this secret key entry",
"Settings.Service.SecretKey.InUse": "This key is currently assigned to a character and cannot be edited or deleted.",
"Settings.Service.SecretKey.Add": "Add new Secret Key",
"Settings.Service.SecretKey.NewFriendlyName": "New Secret Key",
"Settings.Service.SecretKey.RegisterAccount": "Register a new Umbra account",
"Settings.Service.SecretKey.RegisterFailed": "An unknown error occured. Please try again later.",
"Settings.Service.SecretKey.RegisterSuccess": "New account registered.\nPlease keep a copy of your secret key in case you need to reset your plugins, or to use it on another PC.",
"Settings.Service.SecretKey.RegisteredFriendlyName": "{0} (registered {1})",
"Settings.Service.SecretKey.Registering": "Sending request...",
"Settings.Service.ServiceTab.Uri": "Service URI",
"Settings.Service.ServiceTab.UriReadOnlyHint": "You cannot edit the URI of the main service.",
"Settings.Service.ServiceTab.Name": "Service Name",
"Settings.Service.ServiceTab.NameReadOnlyHint": "You cannot edit the name of the main service.",
"Settings.Service.ServiceTab.Delete": "Delete Service",
"Settings.Service.ServiceTab.DeleteHint": "Hold CTRL to delete this service",
"Settings.Advanced.Heading": "Advanced",
"Settings.Advanced.Tab": "Advanced",
"Settings.Advanced.Api.Enable": "Enable Umbra Sync API",
"Settings.Advanced.Api.Description": "Enables handling of the Umbra Sync API. This currently includes:\n\n - MCDF loading support for other plugins\n - Blocking Moodles applications to paired users\n\nIf the Umbra Sync plugin is loaded while this option is enabled, control of its API will be relinquished.",
"Settings.Advanced.Api.Status.Active": "Umbra API active!",
"Settings.Advanced.Api.Status.Disabled": "Umbra API inactive: Option is disabled",
"Settings.Advanced.Api.Status.PluginLoaded": "Umbra API inactive: Umbra plugin is loaded",
"Settings.Advanced.Api.Status.Unknown": "Umbra API inactive: Unknown reason",
"Settings.Advanced.EventViewer.LogToDisk": "Log Event Viewer data to disk",
"Settings.Advanced.EventViewer.Open": "Open Event Viewer",
"Settings.Advanced.HoldCombat": "Hold application during combat",
"Settings.Advanced.SerializedApplications": "Serialized player applications",
"Settings.Advanced.SerializedApplications.Description": "Experimental - May reduce issues in crowded areas",
"Settings.Advanced.DebugHeading": "Debug",
"Settings.Advanced.Debug.LastCreatedTree": "Last created character data",
"Settings.Advanced.Debug.CopyButton": "[DEBUG] Copy Last created Character Data to clipboard",
"Settings.Advanced.Debug.CopyError": "ERROR: No created character data, cannot copy.",
"Settings.Advanced.Debug.CopyTooltip": "Use this when reporting mods being rejected from the server.",
"Settings.Advanced.LogLevel": "Log Level",
"Settings.Advanced.Performance.LogCounters": "Log Performance Counters",
"Settings.Advanced.Performance.LogCounters.Description": "Enabling this can incur a (slight) performance impact. Enabling this for extended periods of time is not recommended.",
"Settings.Advanced.Performance.PrintStats": "Print Performance Stats to /xllog",
"Settings.Advanced.Performance.PrintStatsRecent": "Print Performance Stats (last 60s) to /xllog",
"Settings.Advanced.ActiveBlocks": "Active Character Blocks",
"Settings.UI.Heading": "UI", "Settings.UI.Heading": "UI",
"Settings.UI.EnableRightClick": "Enable Game Right Click Menu Entries", "Settings.UI.EnableRightClick": "Enable Game Right Click Menu Entries",
"Settings.UI.EnableRightClick.Description": "This will add Umbra related right click menu entries in the game UI on paired players.", "Settings.UI.EnableRightClick.Description": "This will add Umbra related right click menu entries in the game UI on paired players.",
@@ -92,5 +176,404 @@
"Settings.Notifications.IndividualPairsOnly": "Notify only for individual pairs", "Settings.Notifications.IndividualPairsOnly": "Notify only for individual pairs",
"Settings.Notifications.IndividualPairsOnly.Description": "Enabling this will only show online notifications (type: Info) for individual pairs.", "Settings.Notifications.IndividualPairsOnly.Description": "Enabling this will only show online notifications (type: Info) for individual pairs.",
"Settings.Notifications.NamedPairsOnly": "Notify only for named pairs", "Settings.Notifications.NamedPairsOnly": "Notify only for named pairs",
"Settings.Notifications.NamedPairsOnly.Description": "Enabling this will only show online notifications (type: Info) for pairs where you have set an individual note." "Settings.Notifications.NamedPairsOnly.Description": "Enabling this will only show online notifications (type: Info) for pairs where you have set an individual note.",
"Compact.Version.UnsupportedTitle": "UNSUPPORTED VERSION",
"Compact.Version.Outdated": "Your UmbraSync installation is out of date, the current version is {0}.{1}.{2}. It is highly recommended to keep UmbraSync up to date. Open /xlplugins and update the plugin.",
"Compact.Toggle.IndividualPairs": "Individual pairs",
"Compact.Toggle.Syncshells": "Syncshells",
"Compact.AddUser.ModalTitle": "Set Notes for New User",
"Compact.AddUser.Description": "You have successfully added {0}. Set a local note for the user in the field below:",
"Compact.AddUser.NoteHint": "Note for {0}",
"Compact.AddUser.Save": "Save Note",
"Compact.AddCharacter.Button": "Add current character with secret key",
"Compact.AddCharacter.SecretKeyLabel": "Secret Key",
"Compact.AddCharacter.NoKeys": "No secret keys are configured for the current server.",
"Compact.AddPair.Hint": "Other player's UID/Alias",
"Compact.AddPair.Tooltip": "Pair with {0}",
"Compact.AddPair.Tooltip.DefaultUser": "other user",
"Compact.Filter.Hint": "Filter for UID/notes",
"Compact.Filter.ToggleTooltip": "Hold Control to {0} pairing with {1} out of {2} displayed users.",
"Compact.Filter.ToggleTooltip.Resume": "resume",
"Compact.Filter.ToggleTooltip.Pause": "pause",
"Compact.Filter.CooldownTooltip": "Next execution is available at {0} seconds",
"Compact.Nearby.Title": "Nearby ({0})",
"Compact.Nearby.Button": "Nearby",
"Compact.Nearby.None": "No nearby players detected.",
"Compact.Nearby.Tooltip.AlreadyPaired": "Already paired on Umbra",
"Compact.Nearby.Tooltip.RequestsDisabled": "Pair requests are disabled for this player",
"Compact.Nearby.Tooltip.SendInvite": "Send Umbra invitation",
"Compact.Nearby.Tooltip.CannotInvite": "Unable to invite this player",
"Compact.Nearby.Incoming": "Incoming requests",
"Compact.Nearby.Incoming.Entry": "{0} [{1}]",
"Compact.Nearby.Incoming.Accept": "Accept and add as pair",
"Compact.Nearby.Incoming.Dismiss": "Dismiss request",
"Compact.Header.SettingsTooltip": "Open the UmbraSync settings",
"Compact.Header.CopyUid": "Copy your UID to clipboard",
"Compact.ServerStatus.UsersOnline": "Users Online",
"Compact.ServerStatus.Shard": "Shard: {0}",
"Compact.ServerStatus.NotConnected": "Not connected to any server",
"Compact.ServerStatus.EditProfile": "Edit your Profile",
"Compact.ServerStatus.Disconnect": "Disconnect from {0}",
"Compact.ServerStatus.Connect": "Connect to {0}",
"Compact.ServerError.Connecting": "Attempting to connect to the server.",
"Compact.ServerError.Reconnecting": "Connection to server interrupted, attempting to reconnect to the server.",
"Compact.ServerError.Disconnected": "You are currently disconnected from the sync server.",
"Compact.ServerError.Disconnecting": "Disconnecting from the server",
"Compact.ServerError.Unauthorized": "Server Response: {0}",
"Compact.ServerError.Offline": "Your selected sync server is currently offline.",
"Compact.ServerError.VersionMismatch": "Your plugin or the server you are connecting to is out of date. Please update your plugin now. If you already did so, contact the server provider to update their server to the latest version.",
"Compact.ServerError.RateLimited": "You are rate limited for (re)connecting too often. Disconnect, wait 10 minutes and try again.",
"Compact.ServerError.NoSecretKey": "You have no secret key set for this current character. Use the button below or open the settings and set a secret key for the current character. You can reuse the same secret key for multiple characters.",
"Compact.ServerError.MultiChara": "Your Character Configuration has multiple characters configured with same name and world. You will not be able to connect until you fix this issue. Remove the duplicates from the configuration in Settings -> Service Settings -> Character Management and reconnect manually after.",
"Compact.Transfers.CharacterAnalysis": "Character Analysis",
"Compact.Transfers.CharacterDataHub": "Character Data Hub",
"Compact.UidText.Reconnecting": "Reconnecting",
"Compact.UidText.Connecting": "Connecting",
"Compact.UidText.Disconnected": "Disconnected",
"Compact.UidText.Disconnecting": "Disconnecting",
"Compact.UidText.Unauthorized": "Unauthorized",
"Compact.UidText.VersionMismatch": "Version mismatch",
"Compact.UidText.Offline": "Unavailable",
"Compact.UidText.RateLimited": "Rate Limited",
"Compact.UidText.NoSecretKey": "No Secret Key",
"Compact.UidText.MultiChara": "Duplicate Characters",
"UserPair.Status.Online": "User is online",
"UserPair.Status.Offline": "User is offline",
"UserPair.Tooltip.NotAddedBack": "{0} has not added you back",
"UserPair.Tooltip.Paused": "Pairing with {0} is paused",
"UserPair.Tooltip.Visible": "{0} is visible: {1}\nClick to target this player",
"UserPair.Tooltip.Visible.LastPrefix": "(Last) ",
"UserPair.Tooltip.Visible.ModsInfo": "Mods Info",
"UserPair.Tooltip.Visible.FilesSize": "Files Size: {0}",
"UserPair.Tooltip.Visible.Vram": "Approx. VRAM Usage: {0}",
"UserPair.Tooltip.Visible.Tris": "Triangle Count (excl. Vanilla): {0}",
"UserPair.Tooltip.Pause": "Pause pairing with {0}",
"UserPair.Tooltip.Resume": "Resume pairing with {0}",
"UserPair.Tooltip.Permission.Header": "Individual user permissions",
"UserPair.Tooltip.Permission.Sound": "Sound sync disabled with {0}",
"UserPair.Tooltip.Permission.Animation": "Animation sync disabled with {0}",
"UserPair.Tooltip.Permission.Vfx": "VFX sync disabled with {0}",
"UserPair.Tooltip.Permission.Status": "You: {0}, They: {1}",
"UserPair.Tooltip.Permission.State.Disabled": "Disabled",
"UserPair.Tooltip.Permission.State.Enabled": "Enabled",
"UserPair.Tooltip.SharedData": "This user has shared {0} Character Data Sets with you.",
"UserPair.Tooltip.SharedData.OpenHub": "Click to open the Character Data Hub and show the entries.",
"UserPair.Menu.Target": "Target player",
"UserPair.Menu.OpenProfile": "Open Profile",
"UserPair.Menu.OpenProfile.Tooltip": "Opens the profile for this user in a new window",
"UserPair.Menu.OpenAnalysis": "Open Analysis",
"UserPair.Menu.ReloadData": "Reload last data",
"UserPair.Menu.ReloadData.Tooltip": "This reapplies the last received character data to this character",
"UserPair.Menu.CyclePause": "Cycle pause state",
"UserPair.Menu.PairGroups": "Pair Groups",
"UserPair.Menu.PairGroups.Tooltip": "Choose pair groups for {0}",
"UserPair.Menu.EnableSoundSync": "Enable sound sync",
"UserPair.Menu.DisableSoundSync": "Disable sound sync",
"UserPair.Menu.EnableAnimationSync": "Enable animation sync",
"UserPair.Menu.DisableAnimationSync": "Disable animation sync",
"UserPair.Menu.EnableVfxSync": "Enable VFX sync",
"UserPair.Menu.DisableVfxSync": "Disable VFX sync",
"UserPair.Menu.Unpair": "Unpair Permanently",
"UserPair.Menu.Unpair.Tooltip": "Hold CTRL and click to unpair permanently from {0}",
"Popup.Generic.Close": "Close",
"Popup.BanUser.Description": "User {0} will be banned and removed from this Syncshell.",
"Popup.BanUser.ReasonHint": "Ban Reason",
"Popup.BanUser.Button": "Ban User",
"Popup.BanUser.ReasonNote": "The reason will be displayed in the banlist. The current server-side alias if present (Vanity ID) will automatically be attached to the reason.",
"Popup.Report.Title": "Report {0} Profile",
"Popup.Report.Note": "Note: Sending a report will disable the offending profile globally.\nThe report will be sent to the team of your currently connected server.\nDepending on the severity of the offense the users profile or account can be permanently disabled or banned.",
"Popup.Report.Warning": "Report spam and wrong reports will not be tolerated and can lead to permanent account suspension.",
"Popup.Report.Scope": "This is not for reporting misbehavior but solely for the actual profile. Reports that are not solely for the profile will be ignored.",
"Popup.Report.Button": "Send Report",
"PairGroups.Popup.Title": "Choose Groups for {0}",
"PairGroups.Popup.SelectPrompt": "Select the groups you want {0} to be in.",
"PairGroups.Popup.CreatePrompt": "Create a new group for {0}.",
"PairGroups.Popup.NewGroupHint": "New Group",
"PairGroups.SelectPairs.Title": "Choose Users for Group {0}",
"PairGroups.SelectPairs.SelectPrompt": "Select users for group {0}",
"PairGroups.SelectPairs.FilterHint": "Filter",
"UidDisplay.Tooltip": "Left click to switch between UID display and nick\nRight click to change nick for {0}\nMiddle Mouse Button to open their profile in a separate window",
"UidDisplay.EditNotes.Hint": "Nick/Notes",
"DataAnalysis.WindowTitle": "Character Data Analysis",
"DataAnalysis.Bc7.ModalTitle": "BC7 Conversion in Progress",
"DataAnalysis.Bc7.Status": "BC7 Conversion in progress: {0}/{1}",
"DataAnalysis.Bc7.CurrentFile": "Current file: {0}",
"DataAnalysis.Bc7.Cancel": "Cancel conversion",
"DataAnalysis.Description": "This window shows you all files and their sizes that are currently in use through your character and associated entities",
"DataAnalysis.Analyzing": "Analyzing {0}/{1}",
"DataAnalysis.Button.CancelAnalysis": "Cancel analysis",
"DataAnalysis.Analyze.MissingNotice": "Some entries in the analysis have file size not determined yet, press the button below to analyze your current data",
"DataAnalysis.Button.StartMissing": "Start analysis (missing entries)",
"DataAnalysis.Button.StartAll": "Start analysis (recalculate all entries)",
"DataAnalysis.TotalFiles": "Total files:",
"DataAnalysis.Tooltip.FileSummary": "{0}: {1} files, size: {2}, compressed: {3}",
"DataAnalysis.TotalSizeActual": "Total size (actual):",
"DataAnalysis.TotalSizeDownload": "Total size (download size):",
"DataAnalysis.Tooltip.CalculateDownloadSize": "Click \"Start analysis\" to calculate download size",
"DataAnalysis.TotalTriangles": "Total modded model triangles: {0}",
"DataAnalysis.FilesFor": "Files for {0}",
"DataAnalysis.Object.SizeActual": "{0} size (actual):",
"DataAnalysis.Object.SizeDownload": "{0} size (download size):",
"DataAnalysis.Object.Vram": "{0} VRAM usage:",
"DataAnalysis.Object.Triangles": "{0} modded model triangles: {1}",
"DataAnalysis.FileGroup.Count": "{0} files",
"DataAnalysis.FileGroup.SizeActual": "{0} files size (actual):",
"DataAnalysis.FileGroup.SizeDownload": "{0} files size (download size):",
"DataAnalysis.Bc7.EnableMode": "Enable BC7 Conversion Mode",
"DataAnalysis.Bc7.WarningTitle": "WARNING BC7 CONVERSION:",
"DataAnalysis.Bc7.WarningIrreversible": "Converting textures to BC7 is irreversible!",
"DataAnalysis.Bc7.WarningDetails": "- Converting textures to BC7 will reduce their size (compressed and uncompressed) drastically. It is recommended to be used for large (4k+) textures.\n- Some textures, especially ones utilizing colorsets, might not be suited for BC7 conversion and might produce visual artifacts.\n- Before converting textures, make sure to have the original files of the mod you are converting so you can reimport it in case of issues.\n- Conversion will convert all found texture duplicates (entries with more than 1 file path) automatically.\n- Converting textures to BC7 is a very expensive operation and, depending on the amount of textures to convert, will take a while to complete.",
"DataAnalysis.Bc7.StartConversion": "Start conversion of {0} texture(s)",
"DataAnalysis.Table.Hash": "Hash",
"DataAnalysis.Table.Filepaths": "Filepaths",
"DataAnalysis.Table.Gamepaths": "Gamepaths",
"DataAnalysis.Table.FileSize": "File Size",
"DataAnalysis.Table.DownloadSize": "Download Size",
"DataAnalysis.Table.Format": "Format",
"DataAnalysis.Table.ConvertToBc7": "Convert to BC7",
"DataAnalysis.Table.Triangles": "Triangles",
"DataAnalysis.SelectedFile": "Selected file:",
"DataAnalysis.LocalFilePath": "Local file path:",
"DataAnalysis.MoreCount": "(and {0} more)",
"DataAnalysis.GamePath": "Used by game path:",
"DownloadUi.WindowTitle": "Umbra Downloads",
"DownloadUi.UploadStatus": "Compressing+Uploading {0}/{1}",
"DownloadUi.DownloadStatus": "{0} [W:{1}/Q:{2}/P:{3}/D:{4}]",
"DownloadUi.UploadingLabel": "Uploading",
"EventViewer.WindowTitle": "Event Viewer",
"EventViewer.Button.Unfreeze": "Unfreeze View",
"EventViewer.Button.Freeze": "Freeze View",
"EventViewer.Tooltip.NewEvents": "New events are available. Click to resume updating.",
"EventViewer.FilterLabel": "Filter lines",
"EventViewer.Button.OpenLog": "Open EventLog folder",
"EventViewer.Column.Time": "Time",
"EventViewer.Column.Source": "Source",
"EventViewer.Column.Uid": "UID",
"EventViewer.Column.Character": "Character",
"EventViewer.Column.Event": "Event",
"EventViewer.Severity.Informational": "Informational",
"EventViewer.Severity.Warning": "Warning",
"EventViewer.Severity.Error": "Error",
"EventViewer.NoValue": "--",
"DtrEntry.EntryName": "Umbra",
"DtrEntry.Tooltip.Connected": "Umbra: Connected",
"DtrEntry.Tooltip.Disconnected": "Umbra: Not Connected",
"PermissionWindow.Title": "Permissions for {0}",
"PermissionWindow.Pause.Label": "Pause Sync",
"PermissionWindow.Pause.HelpMain": "Pausing will completely cease any sync with this user.",
"PermissionWindow.Pause.HelpNote": "Note: this is bidirectional, either user pausing will cease sync completely.",
"PermissionWindow.OtherPaused.True": "{0} has paused you",
"PermissionWindow.OtherPaused.False": "{0} has not paused you",
"PermissionWindow.Sounds.Label": "Disable Sounds",
"PermissionWindow.Sounds.HelpMain": "Disabling sounds will remove all sounds synced with this user on both sides.",
"PermissionWindow.Sounds.HelpNote": "Note: this is bidirectional, either user disabling sound sync will stop sound sync on both sides.",
"PermissionWindow.OtherSoundDisabled.True": "{0} has disabled sound sync with you",
"PermissionWindow.OtherSoundDisabled.False": "{0} has not disabled sound sync with you",
"PermissionWindow.Animations.Label": "Disable Animations",
"PermissionWindow.Animations.HelpMain": "Disabling sounds will remove all animations synced with this user on both sides.",
"PermissionWindow.Animations.HelpNote": "Note: this is bidirectional, either user disabling animation sync will stop animation sync on both sides.",
"PermissionWindow.OtherAnimationDisabled.True": "{0} has disabled animation sync with you",
"PermissionWindow.OtherAnimationDisabled.False": "{0} has not disabled animation sync with you",
"PermissionWindow.Vfx.Label": "Disable VFX",
"PermissionWindow.Vfx.HelpMain": "Disabling sounds will remove all VFX synced with this user on both sides.",
"PermissionWindow.Vfx.HelpNote": "Note: this is bidirectional, either user disabling VFX sync will stop VFX sync on both sides.",
"PermissionWindow.OtherVfxDisabled.True": "{0} has disabled VFX sync with you",
"PermissionWindow.OtherVfxDisabled.False": "{0} has not disabled VFX sync with you",
"PermissionWindow.Button.Save": "Save",
"PermissionWindow.Tooltip.Save": "Save and apply all changes",
"PermissionWindow.Button.Revert": "Revert",
"PermissionWindow.Tooltip.Revert": "Revert all changes",
"PermissionWindow.Button.Reset": "Reset to Default",
"PermissionWindow.Tooltip.Reset": "This will set all permissions to their default setting",
"EditProfile.WindowTitle": "Umbra Edit Profile",
"EditProfile.CurrentProfile": "Current Profile (as saved on server)",
"EditProfile.Button.UploadPicture": "Upload new profile picture",
"EditProfile.Dialog.PictureTitle": "Select new Profile picture",
"EditProfile.Tooltip.UploadPicture": "Select and upload a new profile picture",
"EditProfile.Button.ClearPicture": "Clear uploaded profile picture",
"EditProfile.Tooltip.ClearPicture": "Clear your currently uploaded profile picture",
"EditProfile.Error.PictureTooLarge": "The profile picture must be a PNG file with a maximum height and width of 256px and 250KiB size",
"EditProfile.Checkbox.Nsfw": "Profile is NSFW",
"EditProfile.Help.Nsfw": "If your profile description or image can be considered NSFW, toggle this to ON",
"EditProfile.DescriptionCounter": "Description {0}/1500",
"EditProfile.PreviewLabel": "Preview (approximate)",
"EditProfile.Button.SaveDescription": "Save Description",
"EditProfile.Tooltip.SaveDescription": "Sets your profile description text",
"EditProfile.Button.ClearDescription": "Clear Description",
"EditProfile.Tooltip.ClearDescription": "Clears your profile description text",
"Intro.Welcome.Title": "Welcome to Umbra",
"Intro.Welcome.Paragraph1": "Umbra is a plugin that will replicate your full current character state including all Penumbra mods to other paired users. Note that you will have to have Penumbra as well as Glamourer installed to use this plugin.",
"Intro.Welcome.Paragraph2": "We will have to setup a few things first before you can start using this plugin. Click on next to continue.",
"Intro.Welcome.Note": "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 or others players mods might not apply on your end altogether. If you want to use this plugin you will have to move your mods to Penumbra.",
"Intro.Welcome.Next": "Next",
"Intro.Agreement.Title": "Agreement of Usage of Service",
"Intro.Agreement.Callout": "READ THIS CAREFULLY",
"Intro.Agreement.Timeout": "'I agree' button will be available in {0}s",
"Intro.Agreement.Paragraph1": "To use Umbra, you must be over the age of 18, or 21 in some jurisdictions.",
"Intro.Agreement.Paragraph2": "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.",
"Intro.Agreement.Paragraph3": "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. Files present on the service that already represent your active mod files will not be uploaded again.",
"Intro.Agreement.Paragraph4": "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. Locally cached mod files will have arbitrary file names to discourage attempts at replicating the original mod.",
"Intro.Agreement.Paragraph5": "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.",
"Intro.Agreement.Paragraph6": "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.",
"Intro.Agreement.Paragraph7": "Accounts that are inactive for ninety (90) days will be deleted for privacy reasons.",
"Intro.Agreement.Paragraph8": "Umbra is operated from servers located in the European Union. You agree not to upload any content to the service that violates EU law; and more specifically, German law.",
"Intro.Agreement.Paragraph9": "You may delete your account at any time from within the Settings panel of the plugin. Any mods unique to you will then be removed from the server within 14 days.",
"Intro.Agreement.Paragraph10": "This service is provided as-is.",
"Intro.Agreement.Accept": "I agree",
"Intro.Storage.Title": "File Storage Setup",
"Intro.Storage.Description": "To not unnecessarily download files already present on your computer, Umbra will have to scan your Penumbra mod directory. Additionally, a local storage folder must be set where Umbra will download other character files to. Once the storage folder is set and the scan complete, this page will automatically forward to registration at a service.",
"Intro.Storage.ScanNote": "Note: The initial scan, depending on the amount of mods you have, might take a while. Please wait until it is completed.",
"Intro.Storage.Warning.FileCache": "Warning: once past this step you should not delete the FileCache.csv of Umbra in the Plugin Configurations folder of Dalamud. Otherwise on the next launch a full re-scan of the file cache database will be initiated.",
"Intro.Storage.Warning.ScanHang": "Warning: if the scan is hanging and does nothing for a long time, chances are high your Penumbra folder is not set up properly.",
"Intro.Storage.NoPenumbra": "You do not have a valid Penumbra path set. Open Penumbra and set up a valid path for the mod directory.",
"Intro.Storage.StartScan": "Start Scan",
"Intro.Storage.UseCompactor": "Use File Compactor",
"Intro.Storage.CompactorDescription": "The File Compactor can save a tremendous amount of space on the hard disk for downloads through Umbra. It will incur a minor CPU penalty on download but can speed up loading of other characters. It is recommended to keep it enabled. You can change this setting later anytime in the Umbra settings.",
"Intro.Registration.Title": "Service Registration",
"Intro.Registration.Description": "To be able to use Umbra you will have to register an account.",
"Intro.Registration.Support": "Refer to the instructions at the location you obtained this plugin for more information or support.",
"Intro.Registration.NewAccountInfo": "If you have not used Umbra before, click below to register a new account.",
"Intro.Registration.RegisterButton": "Register a new Umbra account",
"Intro.Registration.SendingRequest": "Sending request...",
"Intro.Registration.Success": "New account registered.\nPlease keep a copy of your secret key in case you need to reset your plugins, or to use it on another PC.",
"Intro.Registration.UnknownError": "An unknown error occured. Please try again later.",
"Intro.Registration.SecretKeyLabel": "Enter Secret Key",
"Intro.Registration.SecretKeyLabelRegistered": "Secret Key",
"Intro.Registration.SecretKeyInstructions": "If you already have a registered account, you can enter its secret key below to use it instead.",
"Intro.Registration.SecretKeyLength": "Your secret key must be exactly 64 characters long.",
"Intro.Registration.SecretKeyCharacters": "Your secret key can only contain ABCDEF and the numbers 0-9.",
"Intro.Registration.SaveAndConnect": "Save and Connect",
"Intro.Registration.SavedKeyRegistered": "(registered {0})",
"Intro.Registration.SavedKeySetup": "Secret Key added on Setup ({0})",
"Intro.ConnectionStatus.Connected": "Connected",
"AutoDetect.Disabled": "Nearby detection is disabled. Enable it in Settings to start detecting nearby Umbra users.",
"AutoDetect.MaxDistance": "Max distance (m)",
"AutoDetect.Table.Name": "Name",
"AutoDetect.Table.World": "World",
"AutoDetect.Table.Distance": "Distance",
"AutoDetect.Table.Status": "Status",
"AutoDetect.Table.Action": "Action",
"AutoDetect.World.Unknown": "-",
"AutoDetect.Distance.Unknown": "-",
"AutoDetect.Distance.Format": "{0:0.0} m",
"AutoDetect.Status.Paired": "Paired",
"AutoDetect.Status.RequestsDisabled": "Requests disabled",
"AutoDetect.Status.OnUmbra": "On Umbra",
"AutoDetect.Action.AlreadySynced": "Already sync",
"AutoDetect.Action.RequestsDisabled": "Requests disabled",
"AutoDetect.Action.SendRequest": "Send request",
"PairGroups.ResumeAll": "Resume pairing with all pairs in {0}",
"PairGroups.PauseAll": "Pause pairing with all pairs in {0}",
"PairGroups.Menu.Title": "Group Flyout Menu",
"PairGroups.Menu.AddPeople": "Add people to {0}",
"PairGroups.Menu.AddPeople.Tooltip": "Add more users to Group {0}",
"PairGroups.Menu.Delete": "Delete {0}",
"PairGroups.Menu.Delete.Tooltip": "Delete Group {0} (Will not delete the pairs)\nHold CTRL to delete",
"PairGroups.Tag.Unpaired": "Unpaired",
"PairGroups.Tag.Offline": "Offline",
"PairGroups.Tag.Online": "Online",
"PairGroups.Tag.Contacts": "Contacts",
"PairGroups.Tag.Visible": "Visible",
"PairGroups.Header.WithCounts": "{0} ({1}/{2}/{3} Pairs)",
"PairGroups.Header.Special": "{0} ({1} Pairs)",
"PairGroups.Tooltip.Title": "Group {0}",
"PairGroups.Tooltip.Visible": "{0} Pairs visible",
"PairGroups.Tooltip.Online": "{0} Pairs online/paused",
"PairGroups.Tooltip.Total": "{0} Pairs total",
"GroupPanel.Join.InputHint": "Syncshell GID/Alias (leave empty to create)",
"GroupPanel.Join.PasswordPopup": "Enter Syncshell Password",
"GroupPanel.Create.PopupTitle": "Create Syncshell",
"GroupPanel.Create.Tooltip": "Create Syncshell",
"GroupPanel.Create.TooMany": "You cannot create more than {0} Syncshells",
"GroupPanel.Join.Tooltip": "Join Syncshell {0}",
"GroupPanel.Join.TooMany": "You cannot join more than {0} Syncshells",
"GroupPanel.Join.Warning": "Before joining any Syncshells please be aware that you will be automatically paired with everyone in the Syncshell.",
"GroupPanel.Join.EnterPassword": "Enter the password for Syncshell {0}:",
"GroupPanel.Join.PasswordHint": "{0} Password",
"GroupPanel.Join.Error": "An error occured during joining of this Syncshell: you either have joined the maximum amount of Syncshells ({0}), it does not exist, the password you entered is wrong, you already joined the Syncshell, the Syncshell is full ({1} users) or the Syncshell has closed invites.",
"GroupPanel.Join.Button": "Join {0}",
"GroupPanel.Create.ChooseType": "Choisissez le type de Syncshell \u00e0 cr\u00e9er.",
"GroupPanel.Create.Permanent": "Permanente",
"GroupPanel.Create.Temporary": "Temporaire",
"GroupPanel.Create.AliasPrompt": "Donnez un nom \u00e0 votre Syncshell (optionnel) puis cr\u00e9ez-la.",
"GroupPanel.Create.AliasHint": "Nom du Syncshell",
"GroupPanel.Create.TempMaxDuration": "Dur\u00e9e maximale d'une Syncshell temporaire : 7 jours.",
"GroupPanel.Create.TempExpires": "Expiration le {0:g} (heure locale).",
"GroupPanel.Create.Instruction": "Appuyez sur le bouton ci-dessous pour cr\u00e9er une nouvelle Syncshell.",
"GroupPanel.Create.Button": "Create Syncshell",
"GroupPanel.Create.Error.NameInUse": "Le nom de la Syncshell est d\u00e9j\u00e0 utilis\u00e9.",
"GroupPanel.Create.Result.Name": "Syncshell Name: {0}",
"GroupPanel.Create.Result.Id": "Syncshell ID: {0}",
"GroupPanel.Create.Result.Password": "Syncshell Password: {0}",
"GroupPanel.Create.Result.ChangeLater": "You can change the Syncshell password later at any time.",
"GroupPanel.Create.Result.TempExpires": "Cette Syncshell expirera le {0:g} (heure locale).",
"GroupPanel.Create.Error.Generic": "You are already owner of the maximum amount of Syncshells (3) or joined the maximum amount of Syncshells (6). Relinquish ownership of your own Syncshells to someone else or leave existing Syncshells.",
"GroupPanel.CommentHint": "Comment/Notes",
"GroupPanel.CommentTooltip": "Hit ENTER to save\\nRight click to cancel",
"GroupPanel.Banlist.Title": "Manage Banlist for {0}",
"GroupPanel.Banlist.Refresh": "Refresh Banlist from Server",
"GroupPanel.Banlist.Column.Uid": "UID",
"GroupPanel.Banlist.Column.Alias": "Alias",
"GroupPanel.Banlist.Column.By": "By",
"GroupPanel.Banlist.Column.Date": "Date",
"GroupPanel.Banlist.Column.Reason": "Reason",
"GroupPanel.Banlist.Column.Actions": "Actions",
"GroupPanel.Banlist.Unban": "Unban",
"GroupPanel.Password.Title": "Change Syncshell Password",
"GroupPanel.Password.Description": "Enter the new Syncshell password for Syncshell {0} here.",
"GroupPanel.Password.Warning": "This action is irreversible",
"GroupPanel.Password.Hint": "New password for {0}",
"GroupPanel.Password.Button": "Change password",
"GroupPanel.Password.Error.TooShort": "The selected password is too short. It must be at least 10 characters.",
"GroupPanel.Invites.Title": "Create Bulk One-Time Invites",
"GroupPanel.Invites.Description": "This allows you to create up to 100 one-time invites at once for the Syncshell {0}.\\nThe invites are valid for 24h after creation and will automatically expire.",
"GroupPanel.Invites.CreateButton": "Create invites",
"GroupPanel.Invites.Result": "A total of {0} invites have been created.",
"GroupPanel.Invites.Copy": "Copy invites to clipboard",
"GroupPanel.List.Visible": "Visible",
"GroupPanel.List.Online": "Online",
"GroupPanel.List.Offline": "Offline/Unknown",
"GroupPanel.List.OfflineOmitted": "{0} offline users omitted from display.",
"GroupPanel.Permissions.Header": "Syncshell permissions",
"GroupPanel.Permissions.InvitesDisabled": "Syncshell is closed for joining",
"GroupPanel.Permissions.SoundDisabledOwner": "Sound sync disabled through owner",
"GroupPanel.Permissions.AnimationDisabledOwner": "Animation sync disabled through owner",
"GroupPanel.Permissions.VfxDisabledOwner": "VFX sync disabled through owner",
"GroupPanel.Permissions.OwnHeader": "Your permissions",
"GroupPanel.Permissions.SoundDisabledSelf": "Sound sync disabled through you",
"GroupPanel.Permissions.AnimationDisabledSelf": "Animation sync disabled through you",
"GroupPanel.Permissions.VfxDisabledSelf": "VFX sync disabled through you",
"GroupPanel.Permissions.NotePriority": "Note that syncshell permissions for disabling take precedence over your own set permissions",
"GroupPanel.PauseToggle.Tooltip": "{0} pairing with all users in this Syncshell",
"GroupPanel.PauseToggle.Resume": "Resume",
"GroupPanel.PauseToggle.Pause": "Pause",
"GroupPanel.Popup.Leave": "Leave Syncshell",
"GroupPanel.Popup.LeaveTooltip": "Hold CTRL and click to leave this Syncshell{0}",
"GroupPanel.Popup.LeaveWarning": "WARNING: This action is irreversible\\nLeaving an owned Syncshell will transfer the ownership to a random person in the Syncshell.",
"GroupPanel.Popup.CopyId": "Copy ID",
"GroupPanel.Popup.CopyIdTooltip": "Copy Syncshell ID to Clipboard",
"GroupPanel.Popup.CopyNotes": "Copy Notes",
"GroupPanel.Popup.CopyNotesTooltip": "Copies all your notes for all users in this Syncshell to the clipboard.\\nThey can be imported via Settings -> General -> Notes -> Import notes from clipboard",
"GroupPanel.Popup.EnableSound": "Enable sound sync",
"GroupPanel.Popup.DisableSound": "Disable sound sync",
"GroupPanel.Popup.SoundTooltip": "Sets your allowance for sound synchronization for users of this syncshell.\\nDisabling the synchronization will stop applying sound modifications for users of this syncshell.\\nNote: this setting can be forcefully overridden to 'disabled' through the syncshell owner.\\nNote: this setting does not apply to individual pairs that are also in the syncshell.",
"GroupPanel.Popup.EnableAnimations": "Enable animations sync",
"GroupPanel.Popup.DisableAnimations": "Disable animations sync",
"GroupPanel.Popup.AnimTooltip": "Sets your allowance for animations synchronization for users of this syncshell.\\nDisabling the synchronization will stop applying animations modifications for users of this syncshell.\\nNote: this setting might also affect sound synchronization\\nNote: this setting can be forcefully overridden to 'disabled' through the syncshell owner.\\nNote: this setting does not apply to individual pairs that are also in the syncshell.",
"GroupPanel.Popup.EnableVfx": "Enable VFX sync",
"GroupPanel.Popup.DisableVfx": "Disable VFX sync",
"GroupPanel.Popup.VfxTooltip": "Sets your allowance for VFX synchronization for users of this syncshell.\\nDisabling the synchronization will stop applying VFX modifications for users of this syncshell.\\nNote: this setting might also affect animation synchronization to some degree\\nNote: this setting can be forcefully overridden to 'disabled' through the syncshell owner.\\nNote: this setting does not apply to individual pairs that are also in the syncshell.",
"GroupPanel.Syncshell.OwnerTooltip": "You are the owner of Syncshell {0}",
"GroupPanel.Syncshell.ModeratorTooltip": "You are a moderator of Syncshell {0}",
"GroupPanel.Syncshell.MemberCount": "{0}/{1}",
"GroupPanel.Syncshell.MemberCountTooltip": "Membres connect\u00e9s / membres totaux\\nCapacit\u00e9 maximale : {0}\\nSyncshell ID: {1}",
"GroupPanel.Syncshell.NameTooltip": "Left click to switch between GID display and comment\\nRight click to change comment for {0}\\n\\nUsers: {1}, Owner: {2}",
"GroupPanel.Syncshell.TempTag": "(Temp)",
"GroupPanel.Syncshell.TempExpires": "Expire le {0:g}",
"GroupPanel.Syncshell.TempTooltip": "Syncshell temporaire",
"GroupPanel.Create.Duration.SingleDay": "24h",
"GroupPanel.Create.Duration.Days": "{0}j",
"GroupPanel.Create.Duration.Hours": "{0}h",
"GroupPanel.Invites.AmountLabel": "Amount",
"GroupPanel.Popup.OpenAdmin": "Open Admin Panel"
} }

View File

@@ -1,6 +1,14 @@
{ {
"Language.DisplayName.French": "Français", "Language.DisplayName.French": "Français",
"Language.DisplayName.English": "Anglais", "Language.DisplayName.English": "Anglais",
"Settings.Plugins.MandatoryHeading": "",
"Settings.Plugins.MandatoryLabel": "",
"Settings.Plugins.OptionalHeading": "",
"Settings.Plugins.OptionalLabel": "",
"Settings.Plugins.OptionalDescription": "",
"Settings.Plugins.Tooltip.Available": "",
"Settings.Plugins.Tooltip.Unavailable": "",
"Settings.Plugins.WarningMandatoryMissing": "",
"Settings.General.LocalizationHeading": "Langue du plugin", "Settings.General.LocalizationHeading": "Langue du plugin",
"Settings.General.Language": "Langue", "Settings.General.Language": "Langue",
"Settings.General.Language.Description": "Sélectionnez la langue du plugin. Les traductions manquantes seront affichées en anglais.", "Settings.General.Language.Description": "Sélectionnez la langue du plugin. Les traductions manquantes seront affichées en anglais.",
@@ -16,6 +24,7 @@
"Settings.Transfers.Blocked.Description": "", "Settings.Transfers.Blocked.Description": "",
"Settings.Transfers.Blocked.Column.Hash": "", "Settings.Transfers.Blocked.Column.Hash": "",
"Settings.Transfers.Blocked.Column.ForbiddenBy": "", "Settings.Transfers.Blocked.Column.ForbiddenBy": "",
"Settings.Transfers.Blocked.Tab": "",
"Settings.Transfers.Heading": "", "Settings.Transfers.Heading": "",
"Settings.Transfers.GlobalLimit.Label": "", "Settings.Transfers.GlobalLimit.Label": "",
"Settings.Transfers.GlobalLimit.Unit.BytePerSec": "", "Settings.Transfers.GlobalLimit.Unit.BytePerSec": "",
@@ -46,6 +55,81 @@
"Settings.Transfers.UI.ShowUploading.Description": "", "Settings.Transfers.UI.ShowUploading.Description": "",
"Settings.Transfers.UI.ShowUploadingBigText": "", "Settings.Transfers.UI.ShowUploadingBigText": "",
"Settings.Transfers.UI.ShowUploadingBigText.Description": "", "Settings.Transfers.UI.ShowUploadingBigText.Description": "",
"Settings.Transfers.Current.Heading": "",
"Settings.Transfers.Current.Tab": "",
"Settings.Transfers.Current.Uploads": "",
"Settings.Transfers.Current.Uploads.Column.File": "",
"Settings.Transfers.Current.Uploads.Column.Uploaded": "",
"Settings.Transfers.Current.Uploads.Column.Size": "",
"Settings.Transfers.Current.Downloads": "",
"Settings.Transfers.Current.Downloads.Column.User": "",
"Settings.Transfers.Current.Downloads.Column.Server": "",
"Settings.Transfers.Current.Downloads.Column.Files": "",
"Settings.Transfers.Current.Downloads.Column.Download": "",
"Settings.Storage.Heading": "",
"Settings.Storage.Description": "",
"Settings.Service.ActionsHeading": "",
"Settings.Service.Actions.DeleteAccount": "",
"Settings.Service.Actions.DeleteAccountPopup": "",
"Settings.Service.Actions.DeleteAccount.Description": "",
"Settings.Service.Actions.DeleteAccount.Popup.Body1": "",
"Settings.Service.Actions.DeleteAccount.Popup.Body2": "",
"Settings.Service.Actions.DeleteAccount.Popup.Confirm": "",
"Settings.Service.Actions.DeleteAccount.Popup.Cancel": "",
"Settings.Service.SettingsHeading": "",
"Settings.Service.ReconnectWarning": "",
"Settings.Service.Tabs.CharacterAssignments": "",
"Settings.Service.Tabs.SecretKey": "",
"Settings.Service.Tabs.ServiceSettings": "",
"Settings.Service.Character.Assignments.Description": "",
"Settings.Service.Character.Assignments.TooltipCurrent": "",
"Settings.Service.Character.Assignments.DeleteTooltip": "",
"Settings.Service.Character.Assignments.AddCurrent": "",
"Settings.Service.Character.Assignments.NoKeys": "",
"Settings.Service.SecretKey.DisplayName": "",
"Settings.Service.SecretKey.Value": "",
"Settings.Service.SecretKey.AssignCurrent": "",
"Settings.Service.SecretKey.AssignTooltip": "",
"Settings.Service.SecretKey.Delete": "",
"Settings.Service.SecretKey.DeleteTooltip": "",
"Settings.Service.SecretKey.InUse": "",
"Settings.Service.SecretKey.Add": "",
"Settings.Service.SecretKey.NewFriendlyName": "",
"Settings.Service.SecretKey.RegisterAccount": "",
"Settings.Service.SecretKey.RegisterFailed": "",
"Settings.Service.SecretKey.RegisterSuccess": "",
"Settings.Service.SecretKey.RegisteredFriendlyName": "",
"Settings.Service.SecretKey.Registering": "",
"Settings.Service.ServiceTab.Uri": "",
"Settings.Service.ServiceTab.UriReadOnlyHint": "",
"Settings.Service.ServiceTab.Name": "",
"Settings.Service.ServiceTab.NameReadOnlyHint": "",
"Settings.Service.ServiceTab.Delete": "",
"Settings.Service.ServiceTab.DeleteHint": "",
"Settings.Advanced.Heading": "",
"Settings.Advanced.Tab": "",
"Settings.Advanced.Api.Enable": "",
"Settings.Advanced.Api.Description": "",
"Settings.Advanced.Api.Status.Active": "",
"Settings.Advanced.Api.Status.Disabled": "",
"Settings.Advanced.Api.Status.PluginLoaded": "",
"Settings.Advanced.Api.Status.Unknown": "",
"Settings.Advanced.EventViewer.LogToDisk": "",
"Settings.Advanced.EventViewer.Open": "",
"Settings.Advanced.HoldCombat": "",
"Settings.Advanced.SerializedApplications": "",
"Settings.Advanced.SerializedApplications.Description": "",
"Settings.Advanced.DebugHeading": "",
"Settings.Advanced.Debug.LastCreatedTree": "",
"Settings.Advanced.Debug.CopyButton": "",
"Settings.Advanced.Debug.CopyError": "",
"Settings.Advanced.Debug.CopyTooltip": "",
"Settings.Advanced.LogLevel": "",
"Settings.Advanced.Performance.LogCounters": "",
"Settings.Advanced.Performance.LogCounters.Description": "",
"Settings.Advanced.Performance.PrintStats": "",
"Settings.Advanced.Performance.PrintStatsRecent": "",
"Settings.Advanced.ActiveBlocks": "",
"Settings.UI.Heading": "", "Settings.UI.Heading": "",
"Settings.UI.EnableRightClick": "", "Settings.UI.EnableRightClick": "",
"Settings.UI.EnableRightClick.Description": "", "Settings.UI.EnableRightClick.Description": "",
@@ -92,5 +176,404 @@
"Settings.Notifications.IndividualPairsOnly": "", "Settings.Notifications.IndividualPairsOnly": "",
"Settings.Notifications.IndividualPairsOnly.Description": "", "Settings.Notifications.IndividualPairsOnly.Description": "",
"Settings.Notifications.NamedPairsOnly": "", "Settings.Notifications.NamedPairsOnly": "",
"Settings.Notifications.NamedPairsOnly.Description": "" "Settings.Notifications.NamedPairsOnly.Description": "",
"Compact.Version.UnsupportedTitle": "",
"Compact.Version.Outdated": "",
"Compact.Toggle.IndividualPairs": "",
"Compact.Toggle.Syncshells": "",
"Compact.AddUser.ModalTitle": "",
"Compact.AddUser.Description": "",
"Compact.AddUser.NoteHint": "",
"Compact.AddUser.Save": "",
"Compact.AddCharacter.Button": "",
"Compact.AddCharacter.SecretKeyLabel": "",
"Compact.AddCharacter.NoKeys": "",
"Compact.AddPair.Hint": "",
"Compact.AddPair.Tooltip": "",
"Compact.AddPair.Tooltip.DefaultUser": "",
"Compact.Filter.Hint": "",
"Compact.Filter.ToggleTooltip": "",
"Compact.Filter.ToggleTooltip.Resume": "",
"Compact.Filter.ToggleTooltip.Pause": "",
"Compact.Filter.CooldownTooltip": "",
"Compact.Nearby.Title": "",
"Compact.Nearby.Button": "",
"Compact.Nearby.None": "",
"Compact.Nearby.Tooltip.AlreadyPaired": "",
"Compact.Nearby.Tooltip.RequestsDisabled": "",
"Compact.Nearby.Tooltip.SendInvite": "",
"Compact.Nearby.Tooltip.CannotInvite": "",
"Compact.Nearby.Incoming": "",
"Compact.Nearby.Incoming.Entry": "",
"Compact.Nearby.Incoming.Accept": "",
"Compact.Nearby.Incoming.Dismiss": "",
"Compact.Header.SettingsTooltip": "",
"Compact.Header.CopyUid": "",
"Compact.ServerStatus.UsersOnline": "",
"Compact.ServerStatus.Shard": "",
"Compact.ServerStatus.NotConnected": "",
"Compact.ServerStatus.EditProfile": "",
"Compact.ServerStatus.Disconnect": "",
"Compact.ServerStatus.Connect": "",
"Compact.ServerError.Connecting": "",
"Compact.ServerError.Reconnecting": "",
"Compact.ServerError.Disconnected": "",
"Compact.ServerError.Disconnecting": "",
"Compact.ServerError.Unauthorized": "",
"Compact.ServerError.Offline": "",
"Compact.ServerError.VersionMismatch": "",
"Compact.ServerError.RateLimited": "",
"Compact.ServerError.NoSecretKey": "",
"Compact.ServerError.MultiChara": "",
"Compact.Transfers.CharacterAnalysis": "",
"Compact.Transfers.CharacterDataHub": "",
"Compact.UidText.Reconnecting": "",
"Compact.UidText.Connecting": "",
"Compact.UidText.Disconnected": "",
"Compact.UidText.Disconnecting": "",
"Compact.UidText.Unauthorized": "",
"Compact.UidText.VersionMismatch": "",
"Compact.UidText.Offline": "",
"Compact.UidText.RateLimited": "",
"Compact.UidText.NoSecretKey": "",
"Compact.UidText.MultiChara": "",
"UserPair.Status.Online": "",
"UserPair.Status.Offline": "",
"UserPair.Tooltip.NotAddedBack": "",
"UserPair.Tooltip.Paused": "",
"UserPair.Tooltip.Visible": "",
"UserPair.Tooltip.Visible.LastPrefix": "",
"UserPair.Tooltip.Visible.ModsInfo": "",
"UserPair.Tooltip.Visible.FilesSize": "",
"UserPair.Tooltip.Visible.Vram": "",
"UserPair.Tooltip.Visible.Tris": "",
"UserPair.Tooltip.Pause": "",
"UserPair.Tooltip.Resume": "",
"UserPair.Tooltip.Permission.Header": "",
"UserPair.Tooltip.Permission.Sound": "",
"UserPair.Tooltip.Permission.Animation": "",
"UserPair.Tooltip.Permission.Vfx": "",
"UserPair.Tooltip.Permission.Status": "",
"UserPair.Tooltip.Permission.State.Disabled": "",
"UserPair.Tooltip.Permission.State.Enabled": "",
"UserPair.Tooltip.SharedData": "",
"UserPair.Tooltip.SharedData.OpenHub": "",
"UserPair.Menu.Target": "",
"UserPair.Menu.OpenProfile": "",
"UserPair.Menu.OpenProfile.Tooltip": "",
"UserPair.Menu.OpenAnalysis": "",
"UserPair.Menu.ReloadData": "",
"UserPair.Menu.ReloadData.Tooltip": "",
"UserPair.Menu.CyclePause": "",
"UserPair.Menu.PairGroups": "",
"UserPair.Menu.PairGroups.Tooltip": "",
"UserPair.Menu.EnableSoundSync": "",
"UserPair.Menu.DisableSoundSync": "",
"UserPair.Menu.EnableAnimationSync": "",
"UserPair.Menu.DisableAnimationSync": "",
"UserPair.Menu.EnableVfxSync": "",
"UserPair.Menu.DisableVfxSync": "",
"UserPair.Menu.Unpair": "",
"UserPair.Menu.Unpair.Tooltip": "",
"Popup.Generic.Close": "",
"Popup.BanUser.Description": "",
"Popup.BanUser.ReasonHint": "",
"Popup.BanUser.Button": "",
"Popup.BanUser.ReasonNote": "",
"Popup.Report.Title": "",
"Popup.Report.Note": "",
"Popup.Report.Warning": "",
"Popup.Report.Scope": "",
"Popup.Report.Button": "",
"PairGroups.Popup.Title": "",
"PairGroups.Popup.SelectPrompt": "",
"PairGroups.Popup.CreatePrompt": "",
"PairGroups.Popup.NewGroupHint": "",
"PairGroups.SelectPairs.Title": "",
"PairGroups.SelectPairs.SelectPrompt": "",
"PairGroups.SelectPairs.FilterHint": "",
"UidDisplay.Tooltip": "",
"UidDisplay.EditNotes.Hint": "",
"DataAnalysis.WindowTitle": "",
"DataAnalysis.Bc7.ModalTitle": "",
"DataAnalysis.Bc7.Status": "",
"DataAnalysis.Bc7.CurrentFile": "",
"DataAnalysis.Bc7.Cancel": "",
"DataAnalysis.Description": "",
"DataAnalysis.Analyzing": "",
"DataAnalysis.Button.CancelAnalysis": "",
"DataAnalysis.Analyze.MissingNotice": "",
"DataAnalysis.Button.StartMissing": "",
"DataAnalysis.Button.StartAll": "",
"DataAnalysis.TotalFiles": "",
"DataAnalysis.Tooltip.FileSummary": "",
"DataAnalysis.TotalSizeActual": "",
"DataAnalysis.TotalSizeDownload": "",
"DataAnalysis.Tooltip.CalculateDownloadSize": "",
"DataAnalysis.TotalTriangles": "",
"DataAnalysis.FilesFor": "",
"DataAnalysis.Object.SizeActual": "",
"DataAnalysis.Object.SizeDownload": "",
"DataAnalysis.Object.Vram": "",
"DataAnalysis.Object.Triangles": "",
"DataAnalysis.FileGroup.Count": "",
"DataAnalysis.FileGroup.SizeActual": "",
"DataAnalysis.FileGroup.SizeDownload": "",
"DataAnalysis.Bc7.EnableMode": "",
"DataAnalysis.Bc7.WarningTitle": "",
"DataAnalysis.Bc7.WarningIrreversible": "",
"DataAnalysis.Bc7.WarningDetails": "",
"DataAnalysis.Bc7.StartConversion": "",
"DataAnalysis.Table.Hash": "",
"DataAnalysis.Table.Filepaths": "",
"DataAnalysis.Table.Gamepaths": "",
"DataAnalysis.Table.FileSize": "",
"DataAnalysis.Table.DownloadSize": "",
"DataAnalysis.Table.Format": "",
"DataAnalysis.Table.ConvertToBc7": "",
"DataAnalysis.Table.Triangles": "",
"DataAnalysis.SelectedFile": "",
"DataAnalysis.LocalFilePath": "",
"DataAnalysis.MoreCount": "",
"DataAnalysis.GamePath": "",
"DownloadUi.WindowTitle": "",
"DownloadUi.UploadStatus": "",
"DownloadUi.DownloadStatus": "",
"DownloadUi.UploadingLabel": "",
"EventViewer.WindowTitle": "",
"EventViewer.Button.Unfreeze": "",
"EventViewer.Button.Freeze": "",
"EventViewer.Tooltip.NewEvents": "",
"EventViewer.FilterLabel": "",
"EventViewer.Button.OpenLog": "",
"EventViewer.Column.Time": "",
"EventViewer.Column.Source": "",
"EventViewer.Column.Uid": "",
"EventViewer.Column.Character": "",
"EventViewer.Column.Event": "",
"EventViewer.Severity.Informational": "",
"EventViewer.Severity.Warning": "",
"EventViewer.Severity.Error": "",
"EventViewer.NoValue": "",
"DtrEntry.EntryName": "",
"DtrEntry.Tooltip.Connected": "",
"DtrEntry.Tooltip.Disconnected": "",
"PermissionWindow.Title": "",
"PermissionWindow.Pause.Label": "",
"PermissionWindow.Pause.HelpMain": "",
"PermissionWindow.Pause.HelpNote": "",
"PermissionWindow.OtherPaused.True": "",
"PermissionWindow.OtherPaused.False": "",
"PermissionWindow.Sounds.Label": "",
"PermissionWindow.Sounds.HelpMain": "",
"PermissionWindow.Sounds.HelpNote": "",
"PermissionWindow.OtherSoundDisabled.True": "",
"PermissionWindow.OtherSoundDisabled.False": "",
"PermissionWindow.Animations.Label": "",
"PermissionWindow.Animations.HelpMain": "",
"PermissionWindow.Animations.HelpNote": "",
"PermissionWindow.OtherAnimationDisabled.True": "",
"PermissionWindow.OtherAnimationDisabled.False": "",
"PermissionWindow.Vfx.Label": "",
"PermissionWindow.Vfx.HelpMain": "",
"PermissionWindow.Vfx.HelpNote": "",
"PermissionWindow.OtherVfxDisabled.True": "",
"PermissionWindow.OtherVfxDisabled.False": "",
"PermissionWindow.Button.Save": "",
"PermissionWindow.Tooltip.Save": "",
"PermissionWindow.Button.Revert": "",
"PermissionWindow.Tooltip.Revert": "",
"PermissionWindow.Button.Reset": "",
"PermissionWindow.Tooltip.Reset": "",
"EditProfile.WindowTitle": "",
"EditProfile.CurrentProfile": "",
"EditProfile.Button.UploadPicture": "",
"EditProfile.Dialog.PictureTitle": "",
"EditProfile.Tooltip.UploadPicture": "",
"EditProfile.Button.ClearPicture": "",
"EditProfile.Tooltip.ClearPicture": "",
"EditProfile.Error.PictureTooLarge": "",
"EditProfile.Checkbox.Nsfw": "",
"EditProfile.Help.Nsfw": "",
"EditProfile.DescriptionCounter": "",
"EditProfile.PreviewLabel": "",
"EditProfile.Button.SaveDescription": "",
"EditProfile.Tooltip.SaveDescription": "",
"EditProfile.Button.ClearDescription": "",
"EditProfile.Tooltip.ClearDescription": "",
"Intro.Welcome.Title": "",
"Intro.Welcome.Paragraph1": "",
"Intro.Welcome.Paragraph2": "",
"Intro.Welcome.Note": "",
"Intro.Welcome.Next": "",
"Intro.Agreement.Title": "",
"Intro.Agreement.Callout": "",
"Intro.Agreement.Timeout": "",
"Intro.Agreement.Paragraph1": "",
"Intro.Agreement.Paragraph2": "",
"Intro.Agreement.Paragraph3": "",
"Intro.Agreement.Paragraph4": "",
"Intro.Agreement.Paragraph5": "",
"Intro.Agreement.Paragraph6": "",
"Intro.Agreement.Paragraph7": "",
"Intro.Agreement.Paragraph8": "",
"Intro.Agreement.Paragraph9": "",
"Intro.Agreement.Paragraph10": "",
"Intro.Agreement.Accept": "",
"Intro.Storage.Title": "",
"Intro.Storage.Description": "",
"Intro.Storage.ScanNote": "",
"Intro.Storage.Warning.FileCache": "",
"Intro.Storage.Warning.ScanHang": "",
"Intro.Storage.NoPenumbra": "",
"Intro.Storage.StartScan": "",
"Intro.Storage.UseCompactor": "",
"Intro.Storage.CompactorDescription": "",
"Intro.Registration.Title": "",
"Intro.Registration.Description": "",
"Intro.Registration.Support": "",
"Intro.Registration.NewAccountInfo": "",
"Intro.Registration.RegisterButton": "",
"Intro.Registration.SendingRequest": "",
"Intro.Registration.Success": "",
"Intro.Registration.UnknownError": "",
"Intro.Registration.SecretKeyLabel": "",
"Intro.Registration.SecretKeyLabelRegistered": "",
"Intro.Registration.SecretKeyInstructions": "",
"Intro.Registration.SecretKeyLength": "",
"Intro.Registration.SecretKeyCharacters": "",
"Intro.Registration.SaveAndConnect": "",
"Intro.Registration.SavedKeyRegistered": "",
"Intro.Registration.SavedKeySetup": "",
"Intro.ConnectionStatus.Connected": "",
"AutoDetect.Disabled": "",
"AutoDetect.MaxDistance": "",
"AutoDetect.Table.Name": "",
"AutoDetect.Table.World": "",
"AutoDetect.Table.Distance": "",
"AutoDetect.Table.Status": "",
"AutoDetect.Table.Action": "",
"AutoDetect.World.Unknown": "",
"AutoDetect.Distance.Unknown": "",
"AutoDetect.Distance.Format": "",
"AutoDetect.Status.Paired": "",
"AutoDetect.Status.RequestsDisabled": "",
"AutoDetect.Status.OnUmbra": "",
"AutoDetect.Action.AlreadySynced": "",
"AutoDetect.Action.RequestsDisabled": "",
"AutoDetect.Action.SendRequest": "",
"PairGroups.ResumeAll": "",
"PairGroups.PauseAll": "",
"PairGroups.Menu.Title": "",
"PairGroups.Menu.AddPeople": "",
"PairGroups.Menu.AddPeople.Tooltip": "",
"PairGroups.Menu.Delete": "",
"PairGroups.Menu.Delete.Tooltip": "",
"PairGroups.Tag.Unpaired": "",
"PairGroups.Tag.Offline": "",
"PairGroups.Tag.Online": "",
"PairGroups.Tag.Contacts": "",
"PairGroups.Tag.Visible": "",
"PairGroups.Header.WithCounts": "",
"PairGroups.Header.Special": "",
"PairGroups.Tooltip.Title": "",
"PairGroups.Tooltip.Visible": "",
"PairGroups.Tooltip.Online": "",
"PairGroups.Tooltip.Total": "",
"GroupPanel.Join.InputHint": "",
"GroupPanel.Join.PasswordPopup": "",
"GroupPanel.Create.PopupTitle": "",
"GroupPanel.Create.Tooltip": "",
"GroupPanel.Create.TooMany": "",
"GroupPanel.Join.Tooltip": "",
"GroupPanel.Join.TooMany": "",
"GroupPanel.Join.Warning": "",
"GroupPanel.Join.EnterPassword": "",
"GroupPanel.Join.PasswordHint": "",
"GroupPanel.Join.Error": "",
"GroupPanel.Join.Button": "",
"GroupPanel.Create.ChooseType": "",
"GroupPanel.Create.Permanent": "",
"GroupPanel.Create.Temporary": "",
"GroupPanel.Create.AliasPrompt": "",
"GroupPanel.Create.AliasHint": "",
"GroupPanel.Create.TempMaxDuration": "",
"GroupPanel.Create.TempExpires": "",
"GroupPanel.Create.Instruction": "",
"GroupPanel.Create.Button": "",
"GroupPanel.Create.Error.NameInUse": "",
"GroupPanel.Create.Result.Name": "",
"GroupPanel.Create.Result.Id": "",
"GroupPanel.Create.Result.Password": "",
"GroupPanel.Create.Result.ChangeLater": "",
"GroupPanel.Create.Result.TempExpires": "",
"GroupPanel.Create.Error.Generic": "",
"GroupPanel.CommentHint": "",
"GroupPanel.CommentTooltip": "",
"GroupPanel.Banlist.Title": "",
"GroupPanel.Banlist.Refresh": "",
"GroupPanel.Banlist.Column.Uid": "",
"GroupPanel.Banlist.Column.Alias": "",
"GroupPanel.Banlist.Column.By": "",
"GroupPanel.Banlist.Column.Date": "",
"GroupPanel.Banlist.Column.Reason": "",
"GroupPanel.Banlist.Column.Actions": "",
"GroupPanel.Banlist.Unban": "",
"GroupPanel.Password.Title": "",
"GroupPanel.Password.Description": "",
"GroupPanel.Password.Warning": "",
"GroupPanel.Password.Hint": "",
"GroupPanel.Password.Button": "",
"GroupPanel.Password.Error.TooShort": "",
"GroupPanel.Invites.Title": "",
"GroupPanel.Invites.Description": "",
"GroupPanel.Invites.CreateButton": "",
"GroupPanel.Invites.Result": "",
"GroupPanel.Invites.Copy": "",
"GroupPanel.List.Visible": "",
"GroupPanel.List.Online": "",
"GroupPanel.List.Offline": "",
"GroupPanel.List.OfflineOmitted": "",
"GroupPanel.Permissions.Header": "",
"GroupPanel.Permissions.InvitesDisabled": "",
"GroupPanel.Permissions.SoundDisabledOwner": "",
"GroupPanel.Permissions.AnimationDisabledOwner": "",
"GroupPanel.Permissions.VfxDisabledOwner": "",
"GroupPanel.Permissions.OwnHeader": "",
"GroupPanel.Permissions.SoundDisabledSelf": "",
"GroupPanel.Permissions.AnimationDisabledSelf": "",
"GroupPanel.Permissions.VfxDisabledSelf": "",
"GroupPanel.Permissions.NotePriority": "",
"GroupPanel.PauseToggle.Tooltip": "",
"GroupPanel.PauseToggle.Resume": "",
"GroupPanel.PauseToggle.Pause": "",
"GroupPanel.Popup.Leave": "",
"GroupPanel.Popup.LeaveTooltip": "",
"GroupPanel.Popup.LeaveWarning": "",
"GroupPanel.Popup.CopyId": "",
"GroupPanel.Popup.CopyIdTooltip": "",
"GroupPanel.Popup.CopyNotes": "",
"GroupPanel.Popup.CopyNotesTooltip": "",
"GroupPanel.Popup.EnableSound": "",
"GroupPanel.Popup.DisableSound": "",
"GroupPanel.Popup.SoundTooltip": "",
"GroupPanel.Popup.EnableAnimations": "",
"GroupPanel.Popup.DisableAnimations": "",
"GroupPanel.Popup.AnimTooltip": "",
"GroupPanel.Popup.EnableVfx": "",
"GroupPanel.Popup.DisableVfx": "",
"GroupPanel.Popup.VfxTooltip": "",
"GroupPanel.Syncshell.OwnerTooltip": "",
"GroupPanel.Syncshell.ModeratorTooltip": "",
"GroupPanel.Syncshell.MemberCount": "",
"GroupPanel.Syncshell.MemberCountTooltip": "",
"GroupPanel.Syncshell.NameTooltip": "",
"GroupPanel.Syncshell.TempTag": "",
"GroupPanel.Syncshell.TempExpires": "",
"GroupPanel.Syncshell.TempTooltip": "",
"GroupPanel.Create.Duration.SingleDay": "",
"GroupPanel.Create.Duration.Days": "",
"GroupPanel.Create.Duration.Hours": "",
"GroupPanel.Invites.AmountLabel": "",
"GroupPanel.Popup.OpenAdmin": ""
} }

View File

@@ -4,6 +4,7 @@ using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using MareSynchronos.Localization;
using MareSynchronos.MareConfiguration; using MareSynchronos.MareConfiguration;
using MareSynchronos.Services; using MareSynchronos.Services;
using MareSynchronos.PlayerData.Pairs; using MareSynchronos.PlayerData.Pairs;
@@ -24,6 +25,10 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
private readonly PairManager _pairManager; private readonly PairManager _pairManager;
private List<Services.Mediator.NearbyEntry> _entries = new(); private List<Services.Mediator.NearbyEntry> _entries = new();
private static string L(string key, string fallback, params object[] args)
=> LocalizationService.Instance?.GetString(key, fallback, args)
?? string.Format(CultureInfo.CurrentCulture, fallback, args);
public AutoDetectUi(ILogger<AutoDetectUi> logger, MareMediator mediator, public AutoDetectUi(ILogger<AutoDetectUi> logger, MareMediator mediator,
MareConfigService configService, DalamudUtilService dalamudUtilService, IObjectTable objectTable, MareConfigService configService, DalamudUtilService dalamudUtilService, IObjectTable objectTable,
Services.AutoDetect.AutoDetectRequestService requestService, PairManager pairManager, Services.AutoDetect.AutoDetectRequestService requestService, PairManager pairManager,
@@ -55,13 +60,13 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
if (!_configService.Current.EnableAutoDetectDiscovery) if (!_configService.Current.EnableAutoDetectDiscovery)
{ {
UiSharedService.ColorTextWrapped("Nearby detection is disabled. Enable it in Settings to start detecting nearby Umbra users.", ImGuiColors.DalamudYellow); UiSharedService.ColorTextWrapped(L("AutoDetect.Disabled", "Nearby detection is disabled. Enable it in Settings to start detecting nearby Umbra users."), ImGuiColors.DalamudYellow);
ImGuiHelpers.ScaledDummy(6); ImGuiHelpers.ScaledDummy(6);
} }
int maxDist = Math.Clamp(_configService.Current.AutoDetectMaxDistanceMeters, 5, 100); int maxDist = Math.Clamp(_configService.Current.AutoDetectMaxDistanceMeters, 5, 100);
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Max distance (m)"); ImGui.TextUnformatted(L("AutoDetect.MaxDistance", "Max distance (m)"));
ImGui.SameLine(); ImGui.SameLine();
ImGui.SetNextItemWidth(120 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(120 * ImGuiHelpers.GlobalScale);
if (ImGui.SliderInt("##autodetect-dist", ref maxDist, 5, 100)) if (ImGui.SliderInt("##autodetect-dist", ref maxDist, 5, 100))
@@ -75,11 +80,11 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
// Table header // Table header
if (ImGui.BeginTable("autodetect-nearby", 5, ImGuiTableFlags.SizingStretchProp)) if (ImGui.BeginTable("autodetect-nearby", 5, ImGuiTableFlags.SizingStretchProp))
{ {
ImGui.TableSetupColumn("Name"); ImGui.TableSetupColumn(L("AutoDetect.Table.Name", "Name"));
ImGui.TableSetupColumn("World"); ImGui.TableSetupColumn(L("AutoDetect.Table.World", "World"));
ImGui.TableSetupColumn("Distance"); ImGui.TableSetupColumn(L("AutoDetect.Table.Distance", "Distance"));
ImGui.TableSetupColumn("Status"); ImGui.TableSetupColumn(L("AutoDetect.Table.Status", "Status"));
ImGui.TableSetupColumn("Action"); ImGui.TableSetupColumn(L("AutoDetect.Table.Action", "Action"));
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
var data = _entries.Count > 0 ? _entries.Where(e => e.IsMatch).ToList() : new List<Services.Mediator.NearbyEntry>(); var data = _entries.Count > 0 ? _entries.Where(e => e.IsMatch).ToList() : new List<Services.Mediator.NearbyEntry>();
@@ -88,25 +93,31 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.TextUnformatted(e.Name); ImGui.TextUnformatted(e.Name);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.TextUnformatted(e.WorldId == 0 ? "-" : (_dalamud.WorldData.Value.TryGetValue(e.WorldId, out var w) ? w : e.WorldId.ToString())); ImGui.TextUnformatted(e.WorldId == 0 ? L("AutoDetect.World.Unknown", "-") : (_dalamud.WorldData.Value.TryGetValue(e.WorldId, out var w) ? w : e.WorldId.ToString()));
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.TextUnformatted(float.IsNaN(e.Distance) ? "-" : $"{e.Distance:0.0} m"); ImGui.TextUnformatted(float.IsNaN(e.Distance)
? L("AutoDetect.Distance.Unknown", "-")
: string.Format(CultureInfo.CurrentCulture, L("AutoDetect.Distance.Format", "{0:0.0} m"), e.Distance));
ImGui.TableNextColumn(); ImGui.TableNextColumn();
bool alreadyPaired = IsAlreadyPairedByUidOrAlias(e); bool alreadyPaired = IsAlreadyPairedByUidOrAlias(e);
string status = alreadyPaired ? "Paired" : (string.IsNullOrEmpty(e.Token) ? "Requests disabled" : "On Umbra"); string status = alreadyPaired
? L("AutoDetect.Status.Paired", "Paired")
: (string.IsNullOrEmpty(e.Token)
? L("AutoDetect.Status.RequestsDisabled", "Requests disabled")
: L("AutoDetect.Status.OnUmbra", "On Umbra"));
ImGui.TextUnformatted(status); ImGui.TextUnformatted(status);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
using (ImRaii.Disabled(alreadyPaired || string.IsNullOrEmpty(e.Token))) using (ImRaii.Disabled(alreadyPaired || string.IsNullOrEmpty(e.Token)))
{ {
if (alreadyPaired) if (alreadyPaired)
{ {
ImGui.Button($"Already sync##{e.Name}"); ImGui.Button(L("AutoDetect.Action.AlreadySynced", "Already sync") + "##" + e.Name);
} }
else if (string.IsNullOrEmpty(e.Token)) else if (string.IsNullOrEmpty(e.Token))
{ {
ImGui.Button($"Requests disabled##{e.Name}"); ImGui.Button(L("AutoDetect.Action.RequestsDisabled", "Requests disabled") + "##" + e.Name);
} }
else if (ImGui.Button($"Send request##{e.Name}")) else if (ImGui.Button(L("AutoDetect.Action.SendRequest", "Send request") + "##" + e.Name))
{ {
_ = _requestService.SendRequestAsync(e.Token!); _ = _requestService.SendRequestAsync(e.Token!);
} }

View File

@@ -63,6 +63,8 @@ public class CompactUi : WindowMediatorSubscriberBase
private bool _nearbyOpen = true; private bool _nearbyOpen = true;
private List<Services.Mediator.NearbyEntry> _nearbyEntries = new(); private List<Services.Mediator.NearbyEntry> _nearbyEntries = new();
private string L(string key, string fallback, params object[] args) => _uiSharedService.Localize(key, fallback, args);
public CompactUi(ILogger<CompactUi> logger, UiSharedService uiShared, MareConfigService configService, ApiController apiController, PairManager pairManager, ChatService chatService, public CompactUi(ILogger<CompactUi> logger, UiSharedService uiShared, MareConfigService configService, ApiController apiController, PairManager pairManager, ChatService chatService,
ServerConfigurationManager serverManager, MareMediator mediator, FileUploadManager fileTransferManager, UidDisplayHandler uidDisplayHandler, CharaDataManager charaDataManager, ServerConfigurationManager serverManager, MareMediator mediator, FileUploadManager fileTransferManager, UidDisplayHandler uidDisplayHandler, CharaDataManager charaDataManager,
NearbyPendingService nearbyPendingService, NearbyPendingService nearbyPendingService,
@@ -84,7 +86,7 @@ public class CompactUi : WindowMediatorSubscriberBase
_groupPanel = new(this, uiShared, _pairManager, chatService, uidDisplayHandler, _configService, _serverManager, _charaDataManager); _groupPanel = new(this, uiShared, _pairManager, chatService, uidDisplayHandler, _configService, _serverManager, _charaDataManager);
_selectGroupForPairUi = new(tagHandler, uidDisplayHandler, _uiSharedService); _selectGroupForPairUi = new(tagHandler, uidDisplayHandler, _uiSharedService);
_selectPairsForGroupUi = new(tagHandler, uidDisplayHandler); _selectPairsForGroupUi = new(tagHandler, uidDisplayHandler, _uiSharedService);
_pairGroupsUi = new(configService, tagHandler, uidDisplayHandler, apiController, _selectPairsForGroupUi, _uiSharedService); _pairGroupsUi = new(configService, tagHandler, uidDisplayHandler, apiController, _selectPairsForGroupUi, _uiSharedService);
#if DEBUG #if DEBUG
@@ -121,7 +123,7 @@ public class CompactUi : WindowMediatorSubscriberBase
if (!_apiController.IsCurrentVersion) if (!_apiController.IsCurrentVersion)
{ {
var ver = _apiController.CurrentClientVersion; var ver = _apiController.CurrentClientVersion;
var unsupported = "UNSUPPORTED VERSION"; var unsupported = L("Compact.Version.UnsupportedTitle", "UNSUPPORTED VERSION");
using (_uiSharedService.UidFont.Push()) using (_uiSharedService.UidFont.Push())
{ {
var uidTextSize = ImGui.CalcTextSize(unsupported); var uidTextSize = ImGui.CalcTextSize(unsupported);
@@ -129,8 +131,10 @@ public class CompactUi : WindowMediatorSubscriberBase
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.TextColored(ImGuiColors.DalamudRed, unsupported); ImGui.TextColored(ImGuiColors.DalamudRed, unsupported);
} }
UiSharedService.ColorTextWrapped($"Your UmbraSync installation is out of date, the current version is {ver.Major}.{ver.Minor}.{ver.Build}. " + UiSharedService.ColorTextWrapped(L("Compact.Version.Outdated",
$"It is highly recommended to keep UmbraSync up to date. Open /xlplugins and update the plugin.", ImGuiColors.DalamudRed); "Your UmbraSync installation is out of date, the current version is {0}.{1}.{2}. It is highly recommended to keep UmbraSync up to date. Open /xlplugins and update the plugin.",
ver.Major, ver.Minor, ver.Build),
ImGuiColors.DalamudRed);
} }
using (ImRaii.PushId("header")) DrawUIDHeader(); using (ImRaii.PushId("header")) DrawUIDHeader();
@@ -155,7 +159,7 @@ public class CompactUi : WindowMediatorSubscriberBase
ImGui.PopStyleColor(); ImGui.PopStyleColor();
} }
ImGui.PopFont(); ImGui.PopFont();
UiSharedService.AttachToolTip("Individual pairs"); UiSharedService.AttachToolTip(L("Compact.Toggle.IndividualPairs", "Individual pairs"));
ImGui.SameLine(); ImGui.SameLine();
@@ -174,7 +178,7 @@ public class CompactUi : WindowMediatorSubscriberBase
} }
ImGui.PopFont(); ImGui.PopFont();
UiSharedService.AttachToolTip("Syncshells"); UiSharedService.AttachToolTip(L("Compact.Toggle.Syncshells", "Syncshells"));
ImGui.Separator(); ImGui.Separator();
if (!hasShownSyncShells) if (!hasShownSyncShells)
@@ -196,12 +200,14 @@ public class CompactUi : WindowMediatorSubscriberBase
{ {
_lastAddedUser = _pairManager.LastAddedUser; _lastAddedUser = _pairManager.LastAddedUser;
_pairManager.LastAddedUser = null; _pairManager.LastAddedUser = null;
ImGui.OpenPopup("Set Notes for New User"); var setNotesTitle = L("Compact.AddUser.ModalTitle", "Set Notes for New User");
ImGui.OpenPopup(setNotesTitle);
_showModalForUserAddition = true; _showModalForUserAddition = true;
_lastAddedUserComment = string.Empty; _lastAddedUserComment = string.Empty;
} }
if (ImGui.BeginPopupModal("Set Notes for New User", ref _showModalForUserAddition, UiSharedService.PopupWindowFlags)) var setNotesModalTitle = L("Compact.AddUser.ModalTitle", "Set Notes for New User");
if (ImGui.BeginPopupModal(setNotesModalTitle, ref _showModalForUserAddition, UiSharedService.PopupWindowFlags))
{ {
if (_lastAddedUser == null) if (_lastAddedUser == null)
{ {
@@ -209,9 +215,9 @@ public class CompactUi : WindowMediatorSubscriberBase
} }
else else
{ {
UiSharedService.TextWrapped($"You have successfully added {_lastAddedUser.UserData.AliasOrUID}. Set a local note for the user in the field below:"); UiSharedService.TextWrapped(L("Compact.AddUser.Description", "You have successfully added {0}. Set a local note for the user in the field below:", _lastAddedUser.UserData.AliasOrUID));
ImGui.InputTextWithHint("##noteforuser", $"Note for {_lastAddedUser.UserData.AliasOrUID}", ref _lastAddedUserComment, 100); ImGui.InputTextWithHint("##noteforuser", L("Compact.AddUser.NoteHint", "Note for {0}", _lastAddedUser.UserData.AliasOrUID), ref _lastAddedUserComment, 100);
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, "Save Note")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, L("Compact.AddUser.Save", "Save Note")))
{ {
_serverManager.SetNoteForUid(_lastAddedUser.UserData.UID, _lastAddedUserComment); _serverManager.SetNoteForUid(_lastAddedUser.UserData.UID, _lastAddedUserComment);
_lastAddedUser = null; _lastAddedUser = null;
@@ -246,7 +252,7 @@ public class CompactUi : WindowMediatorSubscriberBase
if (keys.Any()) if (keys.Any())
{ {
if (_secretKeyIdx == -1) _secretKeyIdx = keys.First().Key; if (_secretKeyIdx == -1) _secretKeyIdx = keys.First().Key;
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Plus, "Add current character with secret key")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.Plus, L("Compact.AddCharacter.Button", "Add current character with secret key")))
{ {
_serverManager.CurrentServer!.Authentications.Add(new MareConfiguration.Models.Authentication() _serverManager.CurrentServer!.Authentications.Add(new MareConfiguration.Models.Authentication()
{ {
@@ -260,11 +266,11 @@ public class CompactUi : WindowMediatorSubscriberBase
_ = _apiController.CreateConnections(); _ = _apiController.CreateConnections();
} }
_uiSharedService.DrawCombo("Secret Key##addCharacterSecretKey", keys, (f) => f.Value.FriendlyName, (f) => _secretKeyIdx = f.Key); _uiSharedService.DrawCombo(L("Compact.AddCharacter.SecretKeyLabel", "Secret Key") + "##addCharacterSecretKey", keys, (f) => f.Value.FriendlyName, (f) => _secretKeyIdx = f.Key);
} }
else else
{ {
UiSharedService.ColorTextWrapped("No secret keys are configured for the current server.", ImGuiColors.DalamudYellow); UiSharedService.ColorTextWrapped(L("Compact.AddCharacter.NoKeys", "No secret keys are configured for the current server."), ImGuiColors.DalamudYellow);
} }
} }
@@ -272,7 +278,7 @@ public class CompactUi : WindowMediatorSubscriberBase
{ {
var buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus); var buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus);
ImGui.SetNextItemWidth(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X - buttonSize.X); ImGui.SetNextItemWidth(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X - buttonSize.X);
ImGui.InputTextWithHint("##otheruid", "Other players UID/Alias", ref _pairToAdd, 20); ImGui.InputTextWithHint("##otheruid", L("Compact.AddPair.Hint", "Other player's UID/Alias"), ref _pairToAdd, 20);
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X); ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X);
var canAdd = !_pairManager.DirectPairs.Any(p => string.Equals(p.UserData.UID, _pairToAdd, StringComparison.Ordinal) || string.Equals(p.UserData.Alias, _pairToAdd, StringComparison.Ordinal)); var canAdd = !_pairManager.DirectPairs.Any(p => string.Equals(p.UserData.UID, _pairToAdd, StringComparison.Ordinal) || string.Equals(p.UserData.Alias, _pairToAdd, StringComparison.Ordinal));
using (ImRaii.Disabled(!canAdd)) using (ImRaii.Disabled(!canAdd))
@@ -282,7 +288,7 @@ public class CompactUi : WindowMediatorSubscriberBase
_ = _apiController.UserAddPair(new(new(_pairToAdd))); _ = _apiController.UserAddPair(new(new(_pairToAdd)));
_pairToAdd = string.Empty; _pairToAdd = string.Empty;
} }
UiSharedService.AttachToolTip("Pair with " + (_pairToAdd.IsNullOrEmpty() ? "other user" : _pairToAdd)); UiSharedService.AttachToolTip(L("Compact.AddPair.Tooltip", "Pair with {0}", _pairToAdd.IsNullOrEmpty() ? L("Compact.AddPair.Tooltip.DefaultUser", "other user") : _pairToAdd));
} }
ImGuiHelpers.ScaledDummy(2); ImGuiHelpers.ScaledDummy(2);
@@ -300,7 +306,7 @@ public class CompactUi : WindowMediatorSubscriberBase
: 0; : 0;
ImGui.SetNextItemWidth(WindowContentWidth - spacing); ImGui.SetNextItemWidth(WindowContentWidth - spacing);
ImGui.InputTextWithHint("##filter", "Filter for UID/notes", ref _characterOrCommentFilter, 255); ImGui.InputTextWithHint("##filter", L("Compact.Filter.Hint", "Filter for UID/notes"), ref _characterOrCommentFilter, 255);
if (userCount == 0) return; if (userCount == 0) return;
@@ -349,9 +355,12 @@ public class CompactUi : WindowMediatorSubscriberBase
_buttonState = !_buttonState; _buttonState = !_buttonState;
} }
if (!_timeout.IsRunning) if (!_timeout.IsRunning)
UiSharedService.AttachToolTip($"Hold Control to {(button == FontAwesomeIcon.Play ? "resume" : "pause")} pairing with {users.Count} out of {userCount} displayed users."); UiSharedService.AttachToolTip(L("Compact.Filter.ToggleTooltip", "Hold Control to {0} pairing with {1} out of {2} displayed users.",
button == FontAwesomeIcon.Play ? L("Compact.Filter.ToggleTooltip.Resume", "resume") : L("Compact.Filter.ToggleTooltip.Pause", "pause"),
users.Count, userCount));
else else
UiSharedService.AttachToolTip($"Next execution is available at {(5000 - _timeout.ElapsedMilliseconds) / 1000} seconds"); UiSharedService.AttachToolTip(L("Compact.Filter.CooldownTooltip", "Next execution is available at {0} seconds",
(5000 - _timeout.ElapsedMilliseconds) / 1000));
} }
} }
@@ -388,13 +397,14 @@ public class CompactUi : WindowMediatorSubscriberBase
if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) _nearbyOpen = !_nearbyOpen; if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) _nearbyOpen = !_nearbyOpen;
ImGui.SameLine(); ImGui.SameLine();
var onUmbra = _nearbyEntries?.Count(e => e.IsMatch) ?? 0; var onUmbra = _nearbyEntries?.Count(e => e.IsMatch) ?? 0;
ImGui.TextUnformatted($"Nearby ({onUmbra})"); ImGui.TextUnformatted(L("Compact.Nearby.Title", "Nearby ({0})", onUmbra));
if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) _nearbyOpen = !_nearbyOpen; if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) _nearbyOpen = !_nearbyOpen;
var btnWidth = _uiSharedService.GetIconTextButtonSize(FontAwesomeIcon.UserPlus, "Nearby"); var nearbyButtonLabel = L("Compact.Nearby.Button", "Nearby");
var btnWidth = _uiSharedService.GetIconTextButtonSize(FontAwesomeIcon.UserPlus, nearbyButtonLabel);
var headerRight = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth(); var headerRight = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth();
ImGui.SameLine(); ImGui.SameLine();
ImGui.SetCursorPosX(headerRight - btnWidth); ImGui.SetCursorPosX(headerRight - btnWidth);
if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserPlus, "Nearby", btnWidth)) if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserPlus, nearbyButtonLabel, btnWidth))
{ {
Mediator.Publish(new UiToggleMessage(typeof(AutoDetectUi))); Mediator.Publish(new UiToggleMessage(typeof(AutoDetectUi)));
} }
@@ -409,7 +419,7 @@ public class CompactUi : WindowMediatorSubscriberBase
.ToList(); .ToList();
if (nearby.Count == 0) if (nearby.Count == 0)
{ {
UiSharedService.ColorTextWrapped("No nearby players detected.", ImGuiColors.DalamudGrey3); UiSharedService.ColorTextWrapped(L("Compact.Nearby.None", "No nearby players detected."), ImGuiColors.DalamudGrey3);
} }
else else
{ {
@@ -438,12 +448,12 @@ public class CompactUi : WindowMediatorSubscriberBase
if (isPaired) if (isPaired)
{ {
_uiSharedService.IconText(FontAwesomeIcon.Check, ImGuiColors.ParsedGreen); _uiSharedService.IconText(FontAwesomeIcon.Check, ImGuiColors.ParsedGreen);
UiSharedService.AttachToolTip("Déjà apparié sur Umbra"); UiSharedService.AttachToolTip(L("Compact.Nearby.Tooltip.AlreadyPaired", "Already paired on Umbra"));
} }
else if (!e.AcceptPairRequests) else if (!e.AcceptPairRequests)
{ {
_uiSharedService.IconText(FontAwesomeIcon.Ban, ImGuiColors.DalamudGrey3); _uiSharedService.IconText(FontAwesomeIcon.Ban, ImGuiColors.DalamudGrey3);
UiSharedService.AttachToolTip("Les demandes sont désactivées pour ce joueur"); UiSharedService.AttachToolTip(L("Compact.Nearby.Tooltip.RequestsDisabled", "Pair requests are disabled for this player"));
} }
else if (!string.IsNullOrEmpty(e.Token)) else if (!string.IsNullOrEmpty(e.Token))
{ {
@@ -451,12 +461,12 @@ public class CompactUi : WindowMediatorSubscriberBase
{ {
_ = _autoDetectRequestService.SendRequestAsync(e.Token!); _ = _autoDetectRequestService.SendRequestAsync(e.Token!);
} }
UiSharedService.AttachToolTip("Envoyer une invitation Umbra"); UiSharedService.AttachToolTip(L("Compact.Nearby.Tooltip.SendInvite", "Send Umbra invitation"));
} }
else else
{ {
_uiSharedService.IconText(FontAwesomeIcon.QuestionCircle, ImGuiColors.DalamudGrey3); _uiSharedService.IconText(FontAwesomeIcon.QuestionCircle, ImGuiColors.DalamudGrey3);
UiSharedService.AttachToolTip("Impossible d'inviter ce joueur"); UiSharedService.AttachToolTip(L("Compact.Nearby.Tooltip.CannotInvite", "Unable to invite this player"));
} }
} }
} }
@@ -466,23 +476,23 @@ public class CompactUi : WindowMediatorSubscriberBase
if (inbox != null && inbox.Pending.Count > 0) if (inbox != null && inbox.Pending.Count > 0)
{ {
ImGuiHelpers.ScaledDummy(6); ImGuiHelpers.ScaledDummy(6);
_uiSharedService.BigText("Incoming requests"); _uiSharedService.BigText(L("Compact.Nearby.Incoming", "Incoming requests"));
foreach (var kv in inbox.Pending) foreach (var kv in inbox.Pending)
{ {
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted($"{kv.Value} [{kv.Key}]"); ImGui.TextUnformatted(L("Compact.Nearby.Incoming.Entry", "{0} [{1}]", kv.Value, kv.Key));
ImGui.SameLine(); ImGui.SameLine();
if (_uiSharedService.IconButton(FontAwesomeIcon.Check)) if (_uiSharedService.IconButton(FontAwesomeIcon.Check))
{ {
_ = inbox.AcceptAsync(kv.Key); _ = inbox.AcceptAsync(kv.Key);
} }
UiSharedService.AttachToolTip("Accept and add as pair"); UiSharedService.AttachToolTip(L("Compact.Nearby.Incoming.Accept", "Accept and add as pair"));
ImGui.SameLine(); ImGui.SameLine();
if (_uiSharedService.IconButton(FontAwesomeIcon.Times)) if (_uiSharedService.IconButton(FontAwesomeIcon.Times))
{ {
inbox.Remove(kv.Key); inbox.Remove(kv.Key);
} }
UiSharedService.AttachToolTip("Dismiss request"); UiSharedService.AttachToolTip(L("Compact.Nearby.Incoming.Dismiss", "Dismiss request"));
} }
} }
} }
@@ -501,8 +511,11 @@ public class CompactUi : WindowMediatorSubscriberBase
var buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Link); var buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Link);
var userCount = _apiController.OnlineUsers.ToString(CultureInfo.InvariantCulture); var userCount = _apiController.OnlineUsers.ToString(CultureInfo.InvariantCulture);
var userSize = ImGui.CalcTextSize(userCount); var userSize = ImGui.CalcTextSize(userCount);
var textSize = ImGui.CalcTextSize("Users Online"); var usersOnlineText = L("Compact.ServerStatus.UsersOnline", "Users Online");
string shardConnection = string.Equals(_apiController.ServerInfo.ShardName, "Main", StringComparison.OrdinalIgnoreCase) ? string.Empty : $"Shard: {_apiController.ServerInfo.ShardName}"; var textSize = ImGui.CalcTextSize(usersOnlineText);
string shardConnection = string.Equals(_apiController.ServerInfo.ShardName, "Main", StringComparison.OrdinalIgnoreCase)
? string.Empty
: L("Compact.ServerStatus.Shard", "Shard: {0}", _apiController.ServerInfo.ShardName);
var shardTextSize = ImGui.CalcTextSize(shardConnection); var shardTextSize = ImGui.CalcTextSize(shardConnection);
var printShard = !string.IsNullOrEmpty(_apiController.ServerInfo.ShardName) && shardConnection != string.Empty; var printShard = !string.IsNullOrEmpty(_apiController.ServerInfo.ShardName) && shardConnection != string.Empty;
@@ -513,12 +526,12 @@ public class CompactUi : WindowMediatorSubscriberBase
ImGui.TextColored(UiSharedService.AccentColor, userCount); ImGui.TextColored(UiSharedService.AccentColor, userCount);
ImGui.SameLine(); ImGui.SameLine();
if (!printShard) ImGui.AlignTextToFramePadding(); if (!printShard) ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Users Online"); ImGui.TextUnformatted(usersOnlineText);
} }
else else
{ {
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.TextColored(ImGuiColors.DalamudRed, "Not connected to any server"); ImGui.TextColored(ImGuiColors.DalamudRed, L("Compact.ServerStatus.NotConnected", "Not connected to any server"));
} }
if (printShard) if (printShard)
@@ -544,7 +557,7 @@ public class CompactUi : WindowMediatorSubscriberBase
{ {
Mediator.Publish(new UiToggleMessage(typeof(EditProfileUi))); Mediator.Publish(new UiToggleMessage(typeof(EditProfileUi)));
} }
UiSharedService.AttachToolTip("Edit your Profile"); UiSharedService.AttachToolTip(L("Compact.ServerStatus.EditProfile", "Edit your Profile"));
} }
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X); ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X);
@@ -563,7 +576,9 @@ public class CompactUi : WindowMediatorSubscriberBase
_ = _apiController.CreateConnections(); _ = _apiController.CreateConnections();
} }
ImGui.PopStyleColor(); ImGui.PopStyleColor();
UiSharedService.AttachToolTip(!_serverManager.CurrentServer.FullPause ? "Disconnect from " + _serverManager.CurrentServer.ServerName : "Connect to " + _serverManager.CurrentServer.ServerName); UiSharedService.AttachToolTip(!_serverManager.CurrentServer.FullPause
? L("Compact.ServerStatus.Disconnect", "Disconnect from {0}", _serverManager.CurrentServer.ServerName)
: L("Compact.ServerStatus.Connect", "Connect to {0}", _serverManager.CurrentServer.ServerName));
} }
} }
@@ -612,13 +627,13 @@ public class CompactUi : WindowMediatorSubscriberBase
} }
var spacing = ImGui.GetStyle().ItemSpacing.X; var spacing = ImGui.GetStyle().ItemSpacing.X;
var bottomButtonWidth = (WindowContentWidth - spacing) / 2f; var bottomButtonWidth = (WindowContentWidth - spacing) / 2f;
if (_uiSharedService.IconTextButton(FontAwesomeIcon.PersonCircleQuestion, "Character Analysis", bottomButtonWidth)) if (_uiSharedService.IconTextButton(FontAwesomeIcon.PersonCircleQuestion, L("Compact.Transfers.CharacterAnalysis", "Character Analysis"), bottomButtonWidth))
{ {
Mediator.Publish(new UiToggleMessage(typeof(DataAnalysisUi))); Mediator.Publish(new UiToggleMessage(typeof(DataAnalysisUi)));
} }
ImGui.SameLine(); ImGui.SameLine();
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Running, "Character Data Hub", bottomButtonWidth)) if (_uiSharedService.IconTextButton(FontAwesomeIcon.Running, L("Compact.Transfers.CharacterDataHub", "Character Data Hub"), bottomButtonWidth))
{ {
Mediator.Publish(new UiToggleMessage(typeof(CharaDataHubUi))); Mediator.Publish(new UiToggleMessage(typeof(CharaDataHubUi)));
} }
@@ -646,7 +661,7 @@ public class CompactUi : WindowMediatorSubscriberBase
{ {
Mediator.Publish(new OpenSettingsUiMessage()); Mediator.Publish(new OpenSettingsUiMessage());
} }
UiSharedService.AttachToolTip("Open the UmbraSync Settings"); UiSharedService.AttachToolTip(L("Compact.Header.SettingsTooltip", "Open the UmbraSync settings"));
ImGui.SameLine(); ImGui.SameLine();
ImGui.SetCursorPos(originalPos); ImGui.SetCursorPos(originalPos);
@@ -659,7 +674,7 @@ public class CompactUi : WindowMediatorSubscriberBase
{ {
ImGui.SetClipboardText(_apiController.DisplayName); ImGui.SetClipboardText(_apiController.DisplayName);
} }
UiSharedService.AttachToolTip("Copy your UID to clipboard"); UiSharedService.AttachToolTip(L("Compact.Header.CopyUid", "Copy your UID to clipboard"));
ImGui.SameLine(); ImGui.SameLine();
} }
ImGui.SetWindowFontScale(1f); ImGui.SetWindowFontScale(1f);
@@ -694,18 +709,19 @@ public class CompactUi : WindowMediatorSubscriberBase
{ {
return _apiController.ServerState switch return _apiController.ServerState switch
{ {
ServerState.Connecting => "Attempting to connect to the server.", ServerState.Connecting => L("Compact.ServerError.Connecting", "Attempting to connect to the server."),
ServerState.Reconnecting => "Connection to server interrupted, attempting to reconnect to the server.", ServerState.Reconnecting => L("Compact.ServerError.Reconnecting", "Connection to server interrupted, attempting to reconnect to the server."),
ServerState.Disconnected => "You are currently disconnected from the sync server.", ServerState.Disconnected => L("Compact.ServerError.Disconnected", "You are currently disconnected from the sync server."),
ServerState.Disconnecting => "Disconnecting from the server", ServerState.Disconnecting => L("Compact.ServerError.Disconnecting", "Disconnecting from the server"),
ServerState.Unauthorized => "Server Response: " + _apiController.AuthFailureMessage, ServerState.Unauthorized => L("Compact.ServerError.Unauthorized", "Server Response: {0}", _apiController.AuthFailureMessage),
ServerState.Offline => "Your selected sync server is currently offline.", ServerState.Offline => L("Compact.ServerError.Offline", "Your selected sync server is currently offline."),
ServerState.VersionMisMatch => ServerState.VersionMisMatch =>
"Your plugin or the server you are connecting to is out of date. Please update your plugin now. If you already did so, contact the server provider to update their server to the latest version.", L("Compact.ServerError.VersionMismatch",
ServerState.RateLimited => "You are rate limited for (re)connecting too often. Disconnect, wait 10 minutes and try again.", "Your plugin or the server you are connecting to is out of date. Please update your plugin now. If you already did so, contact the server provider to update their server to the latest version."),
ServerState.RateLimited => L("Compact.ServerError.RateLimited", "You are rate limited for (re)connecting too often. Disconnect, wait 10 minutes and try again."),
ServerState.Connected => string.Empty, ServerState.Connected => string.Empty,
ServerState.NoSecretKey => "You have no secret key set for this current character. Use the button below or open the settings and set a secret key for the current character. You can reuse the same secret key for multiple characters.", ServerState.NoSecretKey => L("Compact.ServerError.NoSecretKey", "You have no secret key set for this current character. Use the button below or open the settings and set a secret key for the current character. You can reuse the same secret key for multiple characters."),
ServerState.MultiChara => "Your Character Configuration has multiple characters configured with same name and world. You will not be able to connect until you fix this issue. Remove the duplicates from the configuration in Settings -> Service Settings -> Character Management and reconnect manually after.", ServerState.MultiChara => L("Compact.ServerError.MultiChara", "Your Character Configuration has multiple characters configured with same name and world. You will not be able to connect until you fix this issue. Remove the duplicates from the configuration in Settings -> Service Settings -> Character Management and reconnect manually after."),
_ => string.Empty _ => string.Empty
}; };
} }
@@ -733,16 +749,16 @@ public class CompactUi : WindowMediatorSubscriberBase
{ {
return _apiController.ServerState switch return _apiController.ServerState switch
{ {
ServerState.Reconnecting => "Reconnecting", ServerState.Reconnecting => L("Compact.UidText.Reconnecting", "Reconnecting"),
ServerState.Connecting => "Connecting", ServerState.Connecting => L("Compact.UidText.Connecting", "Connecting"),
ServerState.Disconnected => "Disconnected", ServerState.Disconnected => L("Compact.UidText.Disconnected", "Disconnected"),
ServerState.Disconnecting => "Disconnecting", ServerState.Disconnecting => L("Compact.UidText.Disconnecting", "Disconnecting"),
ServerState.Unauthorized => "Unauthorized", ServerState.Unauthorized => L("Compact.UidText.Unauthorized", "Unauthorized"),
ServerState.VersionMisMatch => "Version mismatch", ServerState.VersionMisMatch => L("Compact.UidText.VersionMismatch", "Version mismatch"),
ServerState.Offline => "Unavailable", ServerState.Offline => L("Compact.UidText.Offline", "Unavailable"),
ServerState.RateLimited => "Rate Limited", ServerState.RateLimited => L("Compact.UidText.RateLimited", "Rate Limited"),
ServerState.NoSecretKey => "No Secret Key", ServerState.NoSecretKey => L("Compact.UidText.NoSecretKey", "No Secret Key"),
ServerState.MultiChara => "Duplicate Characters", ServerState.MultiChara => L("Compact.UidText.MultiChara", "Duplicate Characters"),
ServerState.Connected => _apiController.DisplayName, ServerState.Connected => _apiController.DisplayName,
_ => string.Empty _ => string.Empty
}; };

View File

@@ -1,4 +1,5 @@
using System.Numerics; using System;
using System.Numerics;
using Dalamud.Bindings.ImGui; using Dalamud.Bindings.ImGui;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
@@ -12,6 +13,7 @@ using MareSynchronos.Services;
using MareSynchronos.Services.Mediator; using MareSynchronos.Services.Mediator;
using MareSynchronos.UI.Handlers; using MareSynchronos.UI.Handlers;
using MareSynchronos.WebAPI; using MareSynchronos.WebAPI;
using MareSynchronos.Localization;
namespace MareSynchronos.UI.Components; namespace MareSynchronos.UI.Components;
@@ -22,6 +24,13 @@ public class DrawGroupPair : DrawPairBase
private readonly GroupFullInfoDto _group; private readonly GroupFullInfoDto _group;
private readonly CharaDataManager _charaDataManager; private readonly CharaDataManager _charaDataManager;
private static string L(string key, string fallback, params object[] args)
{
var safeArgs = args ?? Array.Empty<object>();
return LocalizationService.Instance?.GetString(key, fallback, safeArgs)
?? string.Format(System.Globalization.CultureInfo.CurrentCulture, fallback, safeArgs);
}
public DrawGroupPair(string id, Pair entry, ApiController apiController, public DrawGroupPair(string id, Pair entry, ApiController apiController,
MareMediator mareMediator, GroupFullInfoDto group, GroupPairFullInfoDto fullInfoDto, MareMediator mareMediator, GroupFullInfoDto group, GroupPairFullInfoDto fullInfoDto,
UidDisplayHandler handler, UiSharedService uiSharedService, CharaDataManager charaDataManager) UidDisplayHandler handler, UiSharedService uiSharedService, CharaDataManager charaDataManager)
@@ -41,20 +50,20 @@ public class DrawGroupPair : DrawPairBase
var entryIsPinned = _fullInfoDto.GroupPairStatusInfo.IsPinned(); var entryIsPinned = _fullInfoDto.GroupPairStatusInfo.IsPinned();
var presenceIcon = _pair.IsVisible ? FontAwesomeIcon.Eye : FontAwesomeIcon.CloudMoon; var presenceIcon = _pair.IsVisible ? FontAwesomeIcon.Eye : FontAwesomeIcon.CloudMoon;
var presenceColor = (_pair.IsOnline || _pair.IsVisible) ? new Vector4(0.63f, 0.25f, 1f, 1f) : ImGuiColors.DalamudGrey; var presenceColor = (_pair.IsOnline || _pair.IsVisible) ? new Vector4(0.63f, 0.25f, 1f, 1f) : ImGuiColors.DalamudGrey;
var presenceText = entryUID + " is offline"; var presenceText = L("GroupPair.Presence.Offline", "{0} is offline", entryUID);
ImGui.SetCursorPosY(textPosY); ImGui.SetCursorPosY(textPosY);
bool drewPrefixIcon = false; bool drewPrefixIcon = false;
if (_pair.IsPaused) if (_pair.IsPaused)
{ {
presenceText = entryUID + " online status is unknown (paused)"; presenceText = L("GroupPair.Presence.Paused", "{0} online status is unknown (paused)", entryUID);
ImGui.PushFont(UiBuilder.IconFont); ImGui.PushFont(UiBuilder.IconFont);
UiSharedService.ColorText(FontAwesomeIcon.PauseCircle.ToIconString(), ImGuiColors.DalamudYellow); UiSharedService.ColorText(FontAwesomeIcon.PauseCircle.ToIconString(), ImGuiColors.DalamudYellow);
ImGui.PopFont(); ImGui.PopFont();
UiSharedService.AttachToolTip("Pairing status with " + entryUID + " is paused"); UiSharedService.AttachToolTip(L("GroupPair.Tooltip.Paused", "Pairing status with {0} is paused", entryUID));
drewPrefixIcon = true; drewPrefixIcon = true;
} }
else else
@@ -66,7 +75,7 @@ public class DrawGroupPair : DrawPairBase
ImGui.PushFont(UiBuilder.IconFont); ImGui.PushFont(UiBuilder.IconFont);
UiSharedService.ColorText(FontAwesomeIcon.Moon.ToIconString(), violet); UiSharedService.ColorText(FontAwesomeIcon.Moon.ToIconString(), violet);
ImGui.PopFont(); ImGui.PopFont();
UiSharedService.AttachToolTip("You are individually paired with " + entryUID); UiSharedService.AttachToolTip(L("GroupPair.Tooltip.IndividuallyPaired", "You are individually paired with {0}", entryUID));
drewPrefixIcon = true; drewPrefixIcon = true;
} }
} }
@@ -78,8 +87,10 @@ public class DrawGroupPair : DrawPairBase
UiSharedService.ColorText(presenceIcon.ToIconString(), presenceColor); UiSharedService.ColorText(presenceIcon.ToIconString(), presenceColor);
ImGui.PopFont(); ImGui.PopFont();
if (_pair.IsOnline && !_pair.IsVisible) presenceText = entryUID + " is online"; if (_pair.IsOnline && !_pair.IsVisible)
else if (_pair.IsOnline && _pair.IsVisible) presenceText = entryUID + " is visible: " + _pair.PlayerName + Environment.NewLine + "Click to target this player"; presenceText = L("GroupPair.Presence.Online", "{0} is online", entryUID);
else if (_pair.IsOnline && _pair.IsVisible)
presenceText = L("GroupPair.Presence.Visible", "{0} is visible: {1}\nClick to target this player", entryUID, _pair.PlayerName);
if (_pair.IsVisible) if (_pair.IsVisible)
{ {
@@ -90,16 +101,19 @@ public class DrawGroupPair : DrawPairBase
if (_pair.LastAppliedDataBytes >= 0) if (_pair.LastAppliedDataBytes >= 0)
{ {
presenceText += UiSharedService.TooltipSeparator; presenceText += UiSharedService.TooltipSeparator;
presenceText += ((!_pair.IsVisible) ? "(Last) " : string.Empty) + "Mods Info" + Environment.NewLine; presenceText += (!_pair.IsVisible ? L("GroupPair.Presence.LastPrefix", "(Last) ") : string.Empty)
presenceText += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true); + L("GroupPair.Presence.ModsInfo", "Mods Info") + Environment.NewLine;
presenceText += L("GroupPair.Presence.FilesSize", "Files Size: {0}", UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true));
if (_pair.LastAppliedApproximateVRAMBytes >= 0) if (_pair.LastAppliedApproximateVRAMBytes >= 0)
{ {
presenceText += Environment.NewLine + "Approx. VRAM Usage: " + UiSharedService.ByteToString(_pair.LastAppliedApproximateVRAMBytes, true); presenceText += Environment.NewLine + L("GroupPair.Presence.Vram", "Approx. VRAM Usage: {0}", UiSharedService.ByteToString(_pair.LastAppliedApproximateVRAMBytes, true));
} }
if (_pair.LastAppliedDataTris >= 0) if (_pair.LastAppliedDataTris >= 0)
{ {
presenceText += Environment.NewLine + "Triangle Count (excl. Vanilla): " var trisValue = _pair.LastAppliedDataTris > 1000
+ (_pair.LastAppliedDataTris > 1000 ? (_pair.LastAppliedDataTris / 1000d).ToString("0.0'k'") : _pair.LastAppliedDataTris); ? (_pair.LastAppliedDataTris / 1000d).ToString("0.0'k'", System.Globalization.CultureInfo.CurrentCulture)
: _pair.LastAppliedDataTris.ToString(System.Globalization.CultureInfo.CurrentCulture);
presenceText += Environment.NewLine + L("GroupPair.Presence.Tris", "Triangle Count (excl. Vanilla): {0}", trisValue);
} }
} }
} }
@@ -113,7 +127,7 @@ public class DrawGroupPair : DrawPairBase
ImGui.PushFont(UiBuilder.IconFont); ImGui.PushFont(UiBuilder.IconFont);
ImGui.TextUnformatted(FontAwesomeIcon.Crown.ToIconString()); ImGui.TextUnformatted(FontAwesomeIcon.Crown.ToIconString());
ImGui.PopFont(); ImGui.PopFont();
UiSharedService.AttachToolTip("User is owner of this Syncshell"); UiSharedService.AttachToolTip(L("GroupPair.Tooltip.Owner", "User is owner of this Syncshell"));
} }
else if (entryIsMod) else if (entryIsMod)
{ {
@@ -122,7 +136,7 @@ public class DrawGroupPair : DrawPairBase
ImGui.PushFont(UiBuilder.IconFont); ImGui.PushFont(UiBuilder.IconFont);
ImGui.TextUnformatted(FontAwesomeIcon.UserShield.ToIconString()); ImGui.TextUnformatted(FontAwesomeIcon.UserShield.ToIconString());
ImGui.PopFont(); ImGui.PopFont();
UiSharedService.AttachToolTip("User is moderator of this Syncshell"); UiSharedService.AttachToolTip(L("GroupPair.Tooltip.Moderator", "User is moderator of this Syncshell"));
} }
else if (entryIsPinned) else if (entryIsPinned)
{ {
@@ -131,7 +145,7 @@ public class DrawGroupPair : DrawPairBase
ImGui.PushFont(UiBuilder.IconFont); ImGui.PushFont(UiBuilder.IconFont);
ImGui.TextUnformatted(FontAwesomeIcon.Thumbtack.ToIconString()); ImGui.TextUnformatted(FontAwesomeIcon.Thumbtack.ToIconString());
ImGui.PopFont(); ImGui.PopFont();
UiSharedService.AttachToolTip("User is pinned in this Syncshell"); UiSharedService.AttachToolTip(L("GroupPair.Tooltip.Pinned", "User is pinned in this Syncshell"));
} }
} }
@@ -176,8 +190,9 @@ public class DrawGroupPair : DrawPairBase
{ {
_uiSharedService.IconText(FontAwesomeIcon.Running); _uiSharedService.IconText(FontAwesomeIcon.Running);
UiSharedService.AttachToolTip($"This user has shared {sharedData!.Count} Character Data Sets with you." + UiSharedService.TooltipSeparator UiSharedService.AttachToolTip(L("GroupPair.Tooltip.SharedData", "This user has shared {0} Character Data Sets with you.", sharedData!.Count)
+ "Click to open the Character Data Hub and show the entries."); + UiSharedService.TooltipSeparator
+ L("GroupPair.Tooltip.SharedData.OpenHub", "Click to open the Character Data Hub and show the entries."));
if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
{ {
@@ -186,7 +201,7 @@ public class DrawGroupPair : DrawPairBase
ImGui.SameLine(); ImGui.SameLine();
} }
if (individualAnimDisabled || individualSoundsDisabled) if (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled)
{ {
ImGui.SetCursorPosY(textPosY); ImGui.SetCursorPosY(textPosY);
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow); ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow);
@@ -196,46 +211,52 @@ public class DrawGroupPair : DrawPairBase
{ {
ImGui.BeginTooltip(); ImGui.BeginTooltip();
ImGui.TextUnformatted("Individual User permissions"); ImGui.TextUnformatted(L("GroupPair.Tooltip.IndividualHeader", "Individual User permissions"));
if (individualSoundsDisabled) if (individualSoundsDisabled)
{ {
var userSoundsText = "Sound sync disabled with " + _pair.UserData.AliasOrUID; var userSoundsText = L("GroupPair.Tooltip.SoundWith", "Sound sync disabled with {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.VolumeOff); _uiSharedService.IconText(FontAwesomeIcon.VolumeOff);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userSoundsText); ImGui.TextUnformatted(userSoundsText);
ImGui.NewLine(); ImGui.NewLine();
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted("You: " + (_pair.UserPair!.OwnPermissions.IsDisableSounds() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableSounds() ? "Disabled" : "Enabled")); ImGui.TextUnformatted(L("GroupPair.Tooltip.YouThey", "You: {0}, They: {1}",
_pair.UserPair!.OwnPermissions.IsDisableSounds() ? L("GroupPair.Toggle.Disabled", "Disabled") : L("GroupPair.Toggle.Enabled", "Enabled"),
_pair.UserPair!.OtherPermissions.IsDisableSounds() ? L("GroupPair.Toggle.Disabled", "Disabled") : L("GroupPair.Toggle.Enabled", "Enabled")));
} }
if (individualAnimDisabled) if (individualAnimDisabled)
{ {
var userAnimText = "Animation sync disabled with " + _pair.UserData.AliasOrUID; var userAnimText = L("GroupPair.Tooltip.AnimWith", "Animation sync disabled with {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.Stop); _uiSharedService.IconText(FontAwesomeIcon.Stop);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userAnimText); ImGui.TextUnformatted(userAnimText);
ImGui.NewLine(); ImGui.NewLine();
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted("You: " + (_pair.UserPair!.OwnPermissions.IsDisableAnimations() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableAnimations() ? "Disabled" : "Enabled")); ImGui.TextUnformatted(L("GroupPair.Tooltip.YouThey", "You: {0}, They: {1}",
_pair.UserPair!.OwnPermissions.IsDisableAnimations() ? L("GroupPair.Toggle.Disabled", "Disabled") : L("GroupPair.Toggle.Enabled", "Enabled"),
_pair.UserPair!.OtherPermissions.IsDisableAnimations() ? L("GroupPair.Toggle.Disabled", "Disabled") : L("GroupPair.Toggle.Enabled", "Enabled")));
} }
if (individualVFXDisabled) if (individualVFXDisabled)
{ {
var userVFXText = "VFX sync disabled with " + _pair.UserData.AliasOrUID; var userVFXText = L("GroupPair.Tooltip.VfxWith", "VFX sync disabled with {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.Circle); _uiSharedService.IconText(FontAwesomeIcon.Circle);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userVFXText); ImGui.TextUnformatted(userVFXText);
ImGui.NewLine(); ImGui.NewLine();
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted("You: " + (_pair.UserPair!.OwnPermissions.IsDisableVFX() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableVFX() ? "Disabled" : "Enabled")); ImGui.TextUnformatted(L("GroupPair.Tooltip.YouThey", "You: {0}, They: {1}",
_pair.UserPair!.OwnPermissions.IsDisableVFX() ? L("GroupPair.Toggle.Disabled", "Disabled") : L("GroupPair.Toggle.Enabled", "Enabled"),
_pair.UserPair!.OtherPermissions.IsDisableVFX() ? L("GroupPair.Toggle.Disabled", "Disabled") : L("GroupPair.Toggle.Enabled", "Enabled")));
} }
ImGui.EndTooltip(); ImGui.EndTooltip();
} }
ImGui.SameLine(); ImGui.SameLine();
} }
else if ((animDisabled || soundsDisabled)) else if ((animDisabled || soundsDisabled || vfxDisabled))
{ {
ImGui.SetCursorPosY(textPosY); ImGui.SetCursorPosY(textPosY);
_uiSharedService.IconText(permIcon); _uiSharedService.IconText(permIcon);
@@ -243,11 +264,11 @@ public class DrawGroupPair : DrawPairBase
{ {
ImGui.BeginTooltip(); ImGui.BeginTooltip();
ImGui.TextUnformatted("Syncshell User permissions"); ImGui.TextUnformatted(L("GroupPair.Tooltip.SyncshellHeader", "Syncshell User permissions"));
if (soundsDisabled) if (soundsDisabled)
{ {
var userSoundsText = "Sound sync disabled by " + _pair.UserData.AliasOrUID; var userSoundsText = L("GroupPair.Tooltip.SoundBy", "Sound sync disabled by {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.VolumeOff); _uiSharedService.IconText(FontAwesomeIcon.VolumeOff);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userSoundsText); ImGui.TextUnformatted(userSoundsText);
@@ -255,7 +276,7 @@ public class DrawGroupPair : DrawPairBase
if (animDisabled) if (animDisabled)
{ {
var userAnimText = "Animation sync disabled by " + _pair.UserData.AliasOrUID; var userAnimText = L("GroupPair.Tooltip.AnimBy", "Animation sync disabled by {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.Stop); _uiSharedService.IconText(FontAwesomeIcon.Stop);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userAnimText); ImGui.TextUnformatted(userAnimText);
@@ -263,7 +284,7 @@ public class DrawGroupPair : DrawPairBase
if (vfxDisabled) if (vfxDisabled)
{ {
var userVFXText = "VFX sync disabled by " + _pair.UserData.AliasOrUID; var userVFXText = L("GroupPair.Tooltip.VfxBy", "VFX sync disabled by {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.Circle); _uiSharedService.IconText(FontAwesomeIcon.Circle);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userVFXText); ImGui.TextUnformatted(userVFXText);
@@ -282,7 +303,7 @@ public class DrawGroupPair : DrawPairBase
{ {
_ = _apiController.UserAddPair(new UserDto(new(_pair.UserData.UID))); _ = _apiController.UserAddPair(new UserDto(new(_pair.UserData.UID)));
} }
UiSharedService.AttachToolTip("Pair with " + entryUID + " individually"); UiSharedService.AttachToolTip(L("GroupPair.Popup.PairIndividually", "Pair with {0} individually", entryUID));
ImGui.SameLine(); ImGui.SameLine();
} }

View File

@@ -5,12 +5,15 @@ using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Utility.Raii;
using MareSynchronos.API.Data.Extensions; using MareSynchronos.API.Data.Extensions;
using MareSynchronos.API.Dto.User; using MareSynchronos.API.Dto.User;
using MareSynchronos.Localization;
using MareSynchronos.PlayerData.Pairs; using MareSynchronos.PlayerData.Pairs;
using MareSynchronos.Services; using MareSynchronos.Services;
using MareSynchronos.Services.Mediator; using MareSynchronos.Services.Mediator;
using MareSynchronos.UI.Handlers; using MareSynchronos.UI.Handlers;
using MareSynchronos.WebAPI; using MareSynchronos.WebAPI;
using System.Numerics; using System.Numerics;
using System.Globalization;
using System;
namespace MareSynchronos.UI.Components; namespace MareSynchronos.UI.Components;
@@ -21,6 +24,13 @@ public class DrawUserPair : DrawPairBase
private readonly SelectGroupForPairUi _selectGroupForPairUi; private readonly SelectGroupForPairUi _selectGroupForPairUi;
private readonly CharaDataManager _charaDataManager; private readonly CharaDataManager _charaDataManager;
private static string L(string key, string fallback, params object[] args)
{
var safeArgs = args ?? Array.Empty<object>();
return LocalizationService.Instance?.GetString(key, fallback, safeArgs)
?? string.Format(CultureInfo.CurrentCulture, fallback, safeArgs);
}
public DrawUserPair(string id, Pair entry, UidDisplayHandler displayHandler, ApiController apiController, public DrawUserPair(string id, Pair entry, UidDisplayHandler displayHandler, ApiController apiController,
MareMediator mareMediator, SelectGroupForPairUi selectGroupForPairUi, MareMediator mareMediator, SelectGroupForPairUi selectGroupForPairUi,
UiSharedService uiSharedService, CharaDataManager charaDataManager) UiSharedService uiSharedService, CharaDataManager charaDataManager)
@@ -47,8 +57,8 @@ public class DrawUserPair : DrawPairBase
UiSharedService.ColorText(FontAwesomeIcon.Moon.ToIconString(), online ? Violet : offlineGrey); UiSharedService.ColorText(FontAwesomeIcon.Moon.ToIconString(), online ? Violet : offlineGrey);
ImGui.PopFont(); ImGui.PopFont();
UiSharedService.AttachToolTip(online UiSharedService.AttachToolTip(online
? "User is online" ? L("UserPair.Status.Online", "User is online")
: "User is offline"); : L("UserPair.Status.Offline", "User is offline"));
if (!(_pair.UserPair!.OwnPermissions.IsPaired() && _pair.UserPair!.OtherPermissions.IsPaired())) if (!(_pair.UserPair!.OwnPermissions.IsPaired() && _pair.UserPair!.OtherPermissions.IsPaired()))
{ {
ImGui.SameLine(); ImGui.SameLine();
@@ -56,7 +66,7 @@ public class DrawUserPair : DrawPairBase
ImGui.PushFont(UiBuilder.IconFont); ImGui.PushFont(UiBuilder.IconFont);
UiSharedService.ColorText(FontAwesomeIcon.ArrowUp.ToIconString(), ImGuiColors.DalamudRed); UiSharedService.ColorText(FontAwesomeIcon.ArrowUp.ToIconString(), ImGuiColors.DalamudRed);
ImGui.PopFont(); ImGui.PopFont();
UiSharedService.AttachToolTip(_pair.UserData.AliasOrUID + " has not added you back"); UiSharedService.AttachToolTip(L("UserPair.Tooltip.NotAddedBack", "{0} has not added you back", _pair.UserData.AliasOrUID));
} }
else if (_pair.UserPair!.OwnPermissions.IsPaused() || _pair.UserPair!.OtherPermissions.IsPaused()) else if (_pair.UserPair!.OwnPermissions.IsPaused() || _pair.UserPair!.OtherPermissions.IsPaused())
{ {
@@ -65,7 +75,7 @@ public class DrawUserPair : DrawPairBase
ImGui.PushFont(UiBuilder.IconFont); ImGui.PushFont(UiBuilder.IconFont);
UiSharedService.ColorText(FontAwesomeIcon.PauseCircle.ToIconString(), ImGuiColors.DalamudYellow); UiSharedService.ColorText(FontAwesomeIcon.PauseCircle.ToIconString(), ImGuiColors.DalamudYellow);
ImGui.PopFont(); ImGui.PopFont();
UiSharedService.AttachToolTip("Pairing with " + _pair.UserData.AliasOrUID + " is paused"); UiSharedService.AttachToolTip(L("UserPair.Tooltip.Paused", "Pairing with {0} is paused", _pair.UserData.AliasOrUID));
} }
if (_pair is { IsOnline: true, IsVisible: true }) if (_pair is { IsOnline: true, IsVisible: true })
{ {
@@ -78,20 +88,23 @@ public class DrawUserPair : DrawPairBase
_mediator.Publish(new TargetPairMessage(_pair)); _mediator.Publish(new TargetPairMessage(_pair));
} }
ImGui.PopFont(); ImGui.PopFont();
var visibleTooltip = _pair.UserData.AliasOrUID + " is visible: " + _pair.PlayerName! + Environment.NewLine + "Click to target this player"; var visibleTooltip = L("UserPair.Tooltip.Visible", "{0} is visible: {1}\nClick to target this player", _pair.UserData.AliasOrUID, _pair.PlayerName!);
if (_pair.LastAppliedDataBytes >= 0) if (_pair.LastAppliedDataBytes >= 0)
{ {
visibleTooltip += UiSharedService.TooltipSeparator; visibleTooltip += UiSharedService.TooltipSeparator;
visibleTooltip += ((!_pair.IsVisible) ? "(Last) " : string.Empty) + "Mods Info" + Environment.NewLine; visibleTooltip += (!_pair.IsVisible ? L("UserPair.Tooltip.Visible.LastPrefix", "(Last) ") : string.Empty)
visibleTooltip += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true); + L("UserPair.Tooltip.Visible.ModsInfo", "Mods Info") + Environment.NewLine;
visibleTooltip += L("UserPair.Tooltip.Visible.FilesSize", "Files Size: {0}", UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true));
if (_pair.LastAppliedApproximateVRAMBytes >= 0) if (_pair.LastAppliedApproximateVRAMBytes >= 0)
{ {
visibleTooltip += Environment.NewLine + "Approx. VRAM Usage: " + UiSharedService.ByteToString(_pair.LastAppliedApproximateVRAMBytes, true); visibleTooltip += Environment.NewLine + L("UserPair.Tooltip.Visible.Vram", "Approx. VRAM Usage: {0}", UiSharedService.ByteToString(_pair.LastAppliedApproximateVRAMBytes, true));
} }
if (_pair.LastAppliedDataTris >= 0) if (_pair.LastAppliedDataTris >= 0)
{ {
visibleTooltip += Environment.NewLine + "Triangle Count (excl. Vanilla): " var trisValue = _pair.LastAppliedDataTris > 1000
+ (_pair.LastAppliedDataTris > 1000 ? (_pair.LastAppliedDataTris / 1000d).ToString("0.0'k'") : _pair.LastAppliedDataTris); ? (_pair.LastAppliedDataTris / 1000d).ToString("0.0'k'", CultureInfo.CurrentCulture)
: _pair.LastAppliedDataTris.ToString(CultureInfo.CurrentCulture);
visibleTooltip += Environment.NewLine + L("UserPair.Tooltip.Visible.Tris", "Triangle Count (excl. Vanilla): {0}", trisValue);
} }
} }
@@ -136,8 +149,8 @@ public class DrawUserPair : DrawPairBase
_ = _apiController.UserSetPairPermissions(new(_pair.UserData, perm)); _ = _apiController.UserSetPairPermissions(new(_pair.UserData, perm));
} }
UiSharedService.AttachToolTip(!_pair.UserPair!.OwnPermissions.IsPaused() UiSharedService.AttachToolTip(!_pair.UserPair!.OwnPermissions.IsPaused()
? "Pause pairing with " + entryUID ? L("UserPair.Tooltip.Pause", "Pause pairing with {0}", entryUID)
: "Resume pairing with " + entryUID); : L("UserPair.Tooltip.Resume", "Resume pairing with {0}", entryUID));
var individualSoundsDisabled = (_pair.UserPair?.OwnPermissions.IsDisableSounds() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableSounds() ?? false); var individualSoundsDisabled = (_pair.UserPair?.OwnPermissions.IsDisableSounds() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableSounds() ?? false);
@@ -158,39 +171,57 @@ public class DrawUserPair : DrawPairBase
{ {
ImGui.BeginTooltip(); ImGui.BeginTooltip();
ImGui.TextUnformatted("Individual User permissions"); ImGui.TextUnformatted(L("UserPair.Tooltip.Permission.Header", "Individual user permissions"));
if (individualSoundsDisabled) if (individualSoundsDisabled)
{ {
var userSoundsText = "Sound sync disabled with " + _pair.UserData.AliasOrUID; var userSoundsText = L("UserPair.Tooltip.Permission.Sound", "Sound sync disabled with {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.VolumeOff); _uiSharedService.IconText(FontAwesomeIcon.VolumeOff);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userSoundsText); ImGui.TextUnformatted(userSoundsText);
ImGui.NewLine(); ImGui.NewLine();
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted("You: " + (_pair.UserPair!.OwnPermissions.IsDisableSounds() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableSounds() ? "Disabled" : "Enabled")); var youStatus = _pair.UserPair!.OwnPermissions.IsDisableSounds()
? L("UserPair.Tooltip.Permission.State.Disabled", "Disabled")
: L("UserPair.Tooltip.Permission.State.Enabled", "Enabled");
var theyStatus = _pair.UserPair!.OtherPermissions.IsDisableSounds()
? L("UserPair.Tooltip.Permission.State.Disabled", "Disabled")
: L("UserPair.Tooltip.Permission.State.Enabled", "Enabled");
ImGui.TextUnformatted(L("UserPair.Tooltip.Permission.Status", "You: {0}, They: {1}", youStatus, theyStatus));
} }
if (individualAnimDisabled) if (individualAnimDisabled)
{ {
var userAnimText = "Animation sync disabled with " + _pair.UserData.AliasOrUID; var userAnimText = L("UserPair.Tooltip.Permission.Animation", "Animation sync disabled with {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.Stop); _uiSharedService.IconText(FontAwesomeIcon.Stop);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userAnimText); ImGui.TextUnformatted(userAnimText);
ImGui.NewLine(); ImGui.NewLine();
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted("You: " + (_pair.UserPair!.OwnPermissions.IsDisableAnimations() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableAnimations() ? "Disabled" : "Enabled")); var youStatus = _pair.UserPair!.OwnPermissions.IsDisableAnimations()
? L("UserPair.Tooltip.Permission.State.Disabled", "Disabled")
: L("UserPair.Tooltip.Permission.State.Enabled", "Enabled");
var theyStatus = _pair.UserPair!.OtherPermissions.IsDisableAnimations()
? L("UserPair.Tooltip.Permission.State.Disabled", "Disabled")
: L("UserPair.Tooltip.Permission.State.Enabled", "Enabled");
ImGui.TextUnformatted(L("UserPair.Tooltip.Permission.Status", "You: {0}, They: {1}", youStatus, theyStatus));
} }
if (individualVFXDisabled) if (individualVFXDisabled)
{ {
var userVFXText = "VFX sync disabled with " + _pair.UserData.AliasOrUID; var userVFXText = L("UserPair.Tooltip.Permission.Vfx", "VFX sync disabled with {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.Circle); _uiSharedService.IconText(FontAwesomeIcon.Circle);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userVFXText); ImGui.TextUnformatted(userVFXText);
ImGui.NewLine(); ImGui.NewLine();
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted("You: " + (_pair.UserPair!.OwnPermissions.IsDisableVFX() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableVFX() ? "Disabled" : "Enabled")); var youStatus = _pair.UserPair!.OwnPermissions.IsDisableVFX()
? L("UserPair.Tooltip.Permission.State.Disabled", "Disabled")
: L("UserPair.Tooltip.Permission.State.Enabled", "Enabled");
var theyStatus = _pair.UserPair!.OtherPermissions.IsDisableVFX()
? L("UserPair.Tooltip.Permission.State.Disabled", "Disabled")
: L("UserPair.Tooltip.Permission.State.Enabled", "Enabled");
ImGui.TextUnformatted(L("UserPair.Tooltip.Permission.Status", "You: {0}, They: {1}", youStatus, theyStatus));
} }
ImGui.EndTooltip(); ImGui.EndTooltip();
@@ -205,8 +236,9 @@ public class DrawUserPair : DrawPairBase
ImGui.SameLine(rightSidePos); ImGui.SameLine(rightSidePos);
_uiSharedService.IconText(icon); _uiSharedService.IconText(icon);
UiSharedService.AttachToolTip($"This user has shared {sharedData.Count} Character Data Sets with you." + UiSharedService.TooltipSeparator UiSharedService.AttachToolTip(L("UserPair.Tooltip.SharedData", "This user has shared {0} Character Data Sets with you.", sharedData.Count)
+ "Click to open the Character Data Hub and show the entries."); + UiSharedService.TooltipSeparator
+ L("UserPair.Tooltip.SharedData.OpenHub", "Click to open the Character Data Hub and show the entries."));
if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
{ {
@@ -221,7 +253,7 @@ public class DrawUserPair : DrawPairBase
{ {
if (entry.IsVisible) if (entry.IsVisible)
{ {
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Eye, "Target player")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.Eye, L("UserPair.Menu.Target", "Target player")))
{ {
_mediator.Publish(new TargetPairMessage(entry)); _mediator.Publish(new TargetPairMessage(entry));
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
@@ -229,44 +261,46 @@ public class DrawUserPair : DrawPairBase
} }
if (!entry.IsPaused) if (!entry.IsPaused)
{ {
if (_uiSharedService.IconTextButton(FontAwesomeIcon.User, "Open Profile")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.User, L("UserPair.Menu.OpenProfile", "Open Profile")))
{ {
_displayHandler.OpenProfile(entry); _displayHandler.OpenProfile(entry);
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
} }
UiSharedService.AttachToolTip("Opens the profile for this user in a new window"); UiSharedService.AttachToolTip(L("UserPair.Menu.OpenProfile.Tooltip", "Opens the profile for this user in a new window"));
} }
if (entry.IsVisible) if (entry.IsVisible)
{ {
#if DEBUG #if DEBUG
if (_uiSharedService.IconTextButton(FontAwesomeIcon.PersonCircleQuestion, "Open Analysis")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.PersonCircleQuestion, L("UserPair.Menu.OpenAnalysis", "Open Analysis")))
{ {
_displayHandler.OpenAnalysis(_pair); _displayHandler.OpenAnalysis(_pair);
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
} }
#endif #endif
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Sync, "Reload last data")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.Sync, L("UserPair.Menu.ReloadData", "Reload last data")))
{ {
entry.ApplyLastReceivedData(forced: true); entry.ApplyLastReceivedData(forced: true);
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
} }
UiSharedService.AttachToolTip("This reapplies the last received character data to this character"); UiSharedService.AttachToolTip(L("UserPair.Menu.ReloadData.Tooltip", "This reapplies the last received character data to this character"));
} }
if (_uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Cycle pause state")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, L("UserPair.Menu.CyclePause", "Cycle pause state")))
{ {
_ = _apiController.CyclePause(entry.UserData); _ = _apiController.CyclePause(entry.UserData);
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
} }
var entryUID = entry.UserData.AliasOrUID; var entryUID = entry.UserData.AliasOrUID;
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Folder, "Pair Groups")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.Folder, L("UserPair.Menu.PairGroups", "Pair Groups")))
{ {
_selectGroupForPairUi.Open(entry); _selectGroupForPairUi.Open(entry);
} }
UiSharedService.AttachToolTip("Choose pair groups for " + entryUID); UiSharedService.AttachToolTip(L("UserPair.Menu.PairGroups.Tooltip", "Choose pair groups for {0}", entryUID));
var isDisableSounds = entry.UserPair!.OwnPermissions.IsDisableSounds(); var isDisableSounds = entry.UserPair!.OwnPermissions.IsDisableSounds();
string disableSoundsText = isDisableSounds ? "Enable sound sync" : "Disable sound sync"; string disableSoundsText = isDisableSounds
? L("UserPair.Menu.EnableSoundSync", "Enable sound sync")
: L("UserPair.Menu.DisableSoundSync", "Disable sound sync");
var disableSoundsIcon = isDisableSounds ? FontAwesomeIcon.VolumeUp : FontAwesomeIcon.VolumeMute; var disableSoundsIcon = isDisableSounds ? FontAwesomeIcon.VolumeUp : FontAwesomeIcon.VolumeMute;
if (_uiSharedService.IconTextButton(disableSoundsIcon, disableSoundsText)) if (_uiSharedService.IconTextButton(disableSoundsIcon, disableSoundsText))
{ {
@@ -276,7 +310,9 @@ public class DrawUserPair : DrawPairBase
} }
var isDisableAnims = entry.UserPair!.OwnPermissions.IsDisableAnimations(); var isDisableAnims = entry.UserPair!.OwnPermissions.IsDisableAnimations();
string disableAnimsText = isDisableAnims ? "Enable animation sync" : "Disable animation sync"; string disableAnimsText = isDisableAnims
? L("UserPair.Menu.EnableAnimationSync", "Enable animation sync")
: L("UserPair.Menu.DisableAnimationSync", "Disable animation sync");
var disableAnimsIcon = isDisableAnims ? FontAwesomeIcon.Running : FontAwesomeIcon.Stop; var disableAnimsIcon = isDisableAnims ? FontAwesomeIcon.Running : FontAwesomeIcon.Stop;
if (_uiSharedService.IconTextButton(disableAnimsIcon, disableAnimsText)) if (_uiSharedService.IconTextButton(disableAnimsIcon, disableAnimsText))
{ {
@@ -286,7 +322,9 @@ public class DrawUserPair : DrawPairBase
} }
var isDisableVFX = entry.UserPair!.OwnPermissions.IsDisableVFX(); var isDisableVFX = entry.UserPair!.OwnPermissions.IsDisableVFX();
string disableVFXText = isDisableVFX ? "Enable VFX sync" : "Disable VFX sync"; string disableVFXText = isDisableVFX
? L("UserPair.Menu.EnableVfxSync", "Enable VFX sync")
: L("UserPair.Menu.DisableVfxSync", "Disable VFX sync");
var disableVFXIcon = isDisableVFX ? FontAwesomeIcon.Sun : FontAwesomeIcon.Circle; var disableVFXIcon = isDisableVFX ? FontAwesomeIcon.Sun : FontAwesomeIcon.Circle;
if (_uiSharedService.IconTextButton(disableVFXIcon, disableVFXText)) if (_uiSharedService.IconTextButton(disableVFXIcon, disableVFXText))
{ {
@@ -295,10 +333,10 @@ public class DrawUserPair : DrawPairBase
_ = _apiController.UserSetPairPermissions(new UserPermissionsDto(entry.UserData, permissions)); _ = _apiController.UserSetPairPermissions(new UserPermissionsDto(entry.UserData, permissions));
} }
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Unpair Permanently") && UiSharedService.CtrlPressed()) if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, L("UserPair.Menu.Unpair", "Unpair Permanently")) && UiSharedService.CtrlPressed())
{ {
_ = _apiController.UserRemovePair(new(entry.UserData)); _ = _apiController.UserRemovePair(new(entry.UserData));
} }
UiSharedService.AttachToolTip("Hold CTRL and click to unpair permanently from " + entryUID); UiSharedService.AttachToolTip(L("UserPair.Menu.Unpair.Tooltip", "Hold CTRL and click to unpair permanently from {0}", entryUID));
} }
} }

View File

@@ -17,6 +17,7 @@ using MareSynchronos.Services.ServerConfiguration;
using MareSynchronos.UI.Components; using MareSynchronos.UI.Components;
using MareSynchronos.UI.Handlers; using MareSynchronos.UI.Handlers;
using MareSynchronos.WebAPI; using MareSynchronos.WebAPI;
using MareSynchronos.Localization;
using System; using System;
using System.Globalization; using System.Globalization;
using System.Numerics; using System.Numerics;
@@ -72,6 +73,13 @@ internal sealed class GroupPanel
private string _syncShellPassword = string.Empty; private string _syncShellPassword = string.Empty;
private string _syncShellToJoin = string.Empty; private string _syncShellToJoin = string.Empty;
private static string L(string key, string fallback, params object[] args)
{
var safeArgs = args ?? Array.Empty<object>();
return LocalizationService.Instance?.GetString(key, fallback, safeArgs)
?? string.Format(CultureInfo.CurrentCulture, fallback, safeArgs);
}
public GroupPanel(CompactUi mainUi, UiSharedService uiShared, PairManager pairManager, ChatService chatServivce, public GroupPanel(CompactUi mainUi, UiSharedService uiShared, PairManager pairManager, ChatService chatServivce,
UidDisplayHandler uidDisplayHandler, MareConfigService mareConfig, ServerConfigurationManager serverConfigurationManager, UidDisplayHandler uidDisplayHandler, MareConfigService mareConfig, ServerConfigurationManager serverConfigurationManager,
CharaDataManager charaDataManager) CharaDataManager charaDataManager)
@@ -99,13 +107,15 @@ internal sealed class GroupPanel
{ {
var buttonSize = _uiShared.GetIconButtonSize(FontAwesomeIcon.Plus); var buttonSize = _uiShared.GetIconButtonSize(FontAwesomeIcon.Plus);
ImGui.SetNextItemWidth(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X - buttonSize.X); ImGui.SetNextItemWidth(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X - buttonSize.X);
ImGui.InputTextWithHint("##syncshellid", "Syncshell GID/Alias (leave empty to create)", ref _syncShellToJoin, 50); ImGui.InputTextWithHint("##syncshellid", L("GroupPanel.Join.InputHint", "Syncshell GID/Alias (leave empty to create)"), ref _syncShellToJoin, 50);
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X); ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X);
bool userCanJoinMoreGroups = _pairManager.GroupPairs.Count < ApiController.ServerInfo.MaxGroupsJoinedByUser; bool userCanJoinMoreGroups = _pairManager.GroupPairs.Count < ApiController.ServerInfo.MaxGroupsJoinedByUser;
bool userCanCreateMoreGroups = _pairManager.GroupPairs.Count(u => string.Equals(u.Key.Owner.UID, ApiController.UID, StringComparison.Ordinal)) < ApiController.ServerInfo.MaxGroupsCreatedByUser; bool userCanCreateMoreGroups = _pairManager.GroupPairs.Count(u => string.Equals(u.Key.Owner.UID, ApiController.UID, StringComparison.Ordinal)) < ApiController.ServerInfo.MaxGroupsCreatedByUser;
bool alreadyInGroup = _pairManager.GroupPairs.Select(p => p.Key).Any(p => string.Equals(p.Group.Alias, _syncShellToJoin, StringComparison.Ordinal) bool alreadyInGroup = _pairManager.GroupPairs.Select(p => p.Key).Any(p => string.Equals(p.Group.Alias, _syncShellToJoin, StringComparison.Ordinal)
|| string.Equals(p.Group.GID, _syncShellToJoin, StringComparison.Ordinal)); || string.Equals(p.Group.GID, _syncShellToJoin, StringComparison.Ordinal));
var enterPasswordPopupTitle = L("GroupPanel.Join.PasswordPopup", "Enter Syncshell Password");
var createPopupTitle = L("GroupPanel.Create.PopupTitle", "Create Syncshell");
if (alreadyInGroup) ImGui.BeginDisabled(); if (alreadyInGroup) ImGui.BeginDisabled();
if (_uiShared.IconButton(FontAwesomeIcon.Plus)) if (_uiShared.IconButton(FontAwesomeIcon.Plus))
@@ -116,7 +126,7 @@ internal sealed class GroupPanel
{ {
_errorGroupJoin = false; _errorGroupJoin = false;
_showModalEnterPassword = true; _showModalEnterPassword = true;
ImGui.OpenPopup("Enter Syncshell Password"); ImGui.OpenPopup(enterPasswordPopupTitle);
} }
} }
else else
@@ -130,30 +140,37 @@ internal sealed class GroupPanel
_tempSyncshellDurationHours = 24; _tempSyncshellDurationHours = 24;
_errorGroupCreateMessage = string.Empty; _errorGroupCreateMessage = string.Empty;
_showModalCreateGroup = true; _showModalCreateGroup = true;
ImGui.OpenPopup("Create Syncshell"); ImGui.OpenPopup(createPopupTitle);
} }
} }
} }
UiSharedService.AttachToolTip(_syncShellToJoin.IsNullOrEmpty() UiSharedService.AttachToolTip(_syncShellToJoin.IsNullOrEmpty()
? (userCanCreateMoreGroups ? "Create Syncshell" : $"You cannot create more than {ApiController.ServerInfo.MaxGroupsCreatedByUser} Syncshells") ? (userCanCreateMoreGroups
: (userCanJoinMoreGroups ? "Join Syncshell" + _syncShellToJoin : $"You cannot join more than {ApiController.ServerInfo.MaxGroupsJoinedByUser} Syncshells")); ? L("GroupPanel.Create.Tooltip", "Create Syncshell")
: L("GroupPanel.Create.TooMany", "You cannot create more than {0} Syncshells", ApiController.ServerInfo.MaxGroupsCreatedByUser))
: (userCanJoinMoreGroups
? L("GroupPanel.Join.Tooltip", "Join Syncshell {0}", _syncShellToJoin)
: L("GroupPanel.Join.TooMany", "You cannot join more than {0} Syncshells", ApiController.ServerInfo.MaxGroupsJoinedByUser)));
if (alreadyInGroup) ImGui.EndDisabled(); if (alreadyInGroup) ImGui.EndDisabled();
if (ImGui.BeginPopupModal("Enter Syncshell Password", ref _showModalEnterPassword, UiSharedService.PopupWindowFlags)) if (ImGui.BeginPopupModal(enterPasswordPopupTitle, ref _showModalEnterPassword, UiSharedService.PopupWindowFlags))
{ {
UiSharedService.TextWrapped("Before joining any Syncshells please be aware that you will be automatically paired with everyone in the Syncshell."); UiSharedService.TextWrapped(L("GroupPanel.Join.Warning", "Before joining any Syncshells please be aware that you will be automatically paired with everyone in the Syncshell."));
ImGui.Separator(); ImGui.Separator();
UiSharedService.TextWrapped("Enter the password for Syncshell " + _syncShellToJoin + ":"); UiSharedService.TextWrapped(L("GroupPanel.Join.EnterPassword", "Enter the password for Syncshell {0}:", _syncShellToJoin));
ImGui.SetNextItemWidth(-1); ImGui.SetNextItemWidth(-1);
ImGui.InputTextWithHint("##password", _syncShellToJoin + " Password", ref _syncShellPassword, 255, ImGuiInputTextFlags.Password); ImGui.InputTextWithHint("##password", L("GroupPanel.Join.PasswordHint", "{0} Password", _syncShellToJoin), ref _syncShellPassword, 255, ImGuiInputTextFlags.Password);
if (_errorGroupJoin) if (_errorGroupJoin)
{ {
UiSharedService.ColorTextWrapped($"An error occured during joining of this Syncshell: you either have joined the maximum amount of Syncshells ({ApiController.ServerInfo.MaxGroupsJoinedByUser}), " + UiSharedService.ColorTextWrapped(
$"it does not exist, the password you entered is wrong, you already joined the Syncshell, the Syncshell is full ({ApiController.ServerInfo.MaxGroupUserCount} users) or the Syncshell has closed invites.", L("GroupPanel.Join.Error",
"An error occured during joining of this Syncshell: you either have joined the maximum amount of Syncshells ({0}), it does not exist, the password you entered is wrong, you already joined the Syncshell, the Syncshell is full ({1} users) or the Syncshell has closed invites.",
ApiController.ServerInfo.MaxGroupsJoinedByUser,
ApiController.ServerInfo.MaxGroupUserCount),
new Vector4(1, 0, 0, 1)); new Vector4(1, 0, 0, 1));
} }
if (ImGui.Button("Join " + _syncShellToJoin)) if (ImGui.Button(L("GroupPanel.Join.Button", "Join {0}", _syncShellToJoin)))
{ {
var shell = _syncShellToJoin; var shell = _syncShellToJoin;
var pw = _syncShellPassword; var pw = _syncShellPassword;
@@ -169,16 +186,16 @@ internal sealed class GroupPanel
ImGui.EndPopup(); ImGui.EndPopup();
} }
if (ImGui.BeginPopupModal("Create Syncshell", ref _showModalCreateGroup, UiSharedService.PopupWindowFlags)) if (ImGui.BeginPopupModal(createPopupTitle, ref _showModalCreateGroup, UiSharedService.PopupWindowFlags))
{ {
UiSharedService.TextWrapped("Choisissez le type de Syncshell à créer."); UiSharedService.TextWrapped(L("GroupPanel.Create.ChooseType", "Choisissez le type de Syncshell à créer."));
bool showPermanent = !_createIsTemporary; bool showPermanent = !_createIsTemporary;
if (ImGui.RadioButton("Permanente", showPermanent)) if (ImGui.RadioButton(L("GroupPanel.Create.Permanent", "Permanente"), showPermanent))
{ {
_createIsTemporary = false; _createIsTemporary = false;
} }
ImGui.SameLine(); ImGui.SameLine();
if (ImGui.RadioButton("Temporaire", _createIsTemporary)) if (ImGui.RadioButton(L("GroupPanel.Create.Temporary", "Temporaire"), _createIsTemporary))
{ {
_createIsTemporary = true; _createIsTemporary = true;
_newSyncShellAlias = string.Empty; _newSyncShellAlias = string.Empty;
@@ -186,9 +203,9 @@ internal sealed class GroupPanel
if (!_createIsTemporary) if (!_createIsTemporary)
{ {
UiSharedService.TextWrapped("Donnez un nom à votre Syncshell (optionnel) puis créez-la."); UiSharedService.TextWrapped(L("GroupPanel.Create.AliasPrompt", "Donnez un nom à votre Syncshell (optionnel) puis créez-la."));
ImGui.SetNextItemWidth(-1); ImGui.SetNextItemWidth(-1);
ImGui.InputTextWithHint("##syncshellalias", "Nom du Syncshell", ref _newSyncShellAlias, 50); ImGui.InputTextWithHint("##syncshellalias", L("GroupPanel.Create.AliasHint", "Nom du Syncshell"), ref _newSyncShellAlias, 50);
} }
else else
{ {
@@ -197,7 +214,7 @@ internal sealed class GroupPanel
if (_createIsTemporary) if (_createIsTemporary)
{ {
UiSharedService.TextWrapped("Durée maximale d'une Syncshell temporaire : 7 jours."); UiSharedService.TextWrapped(L("GroupPanel.Create.TempMaxDuration", "Durée maximale d'une Syncshell temporaire : 7 jours."));
if (_tempSyncshellDurationHours > 168) _tempSyncshellDurationHours = 168; if (_tempSyncshellDurationHours > 168) _tempSyncshellDurationHours = 168;
for (int i = 0; i < _temporaryDurationOptions.Length; i++) for (int i = 0; i < _temporaryDurationOptions.Length; i++)
{ {
@@ -205,8 +222,10 @@ internal sealed class GroupPanel
var isSelected = _tempSyncshellDurationHours == option; var isSelected = _tempSyncshellDurationHours == option;
string label = option switch string label = option switch
{ {
>= 24 when option % 24 == 0 => option == 24 ? "24h" : $"{option / 24}j", >= 24 when option % 24 == 0 => option == 24
_ => option + "h" ? L("GroupPanel.Create.Duration.SingleDay", "24h")
: L("GroupPanel.Create.Duration.Days", "{0}j", option / 24),
_ => L("GroupPanel.Create.Duration.Hours", "{0}h", option)
}; };
if (ImGui.RadioButton(label, isSelected)) if (ImGui.RadioButton(label, isSelected))
@@ -214,7 +233,6 @@ internal sealed class GroupPanel
_tempSyncshellDurationHours = option; _tempSyncshellDurationHours = option;
} }
// Start a new line after every 3 buttons
if ((i + 1) % 3 == 0) if ((i + 1) % 3 == 0)
{ {
ImGui.NewLine(); ImGui.NewLine();
@@ -226,12 +244,12 @@ internal sealed class GroupPanel
} }
var expiresLocal = DateTime.Now.AddHours(_tempSyncshellDurationHours); var expiresLocal = DateTime.Now.AddHours(_tempSyncshellDurationHours);
UiSharedService.TextWrapped($"Expiration le {expiresLocal:g} (heure locale)."); UiSharedService.TextWrapped(L("GroupPanel.Create.TempExpires", "Expiration le {0:g} (heure locale).", expiresLocal));
} }
UiSharedService.TextWrapped("Appuyez sur le bouton ci-dessous pour créer une nouvelle Syncshell."); UiSharedService.TextWrapped(L("GroupPanel.Create.Instruction", "Appuyez sur le bouton ci-dessous pour créer une nouvelle Syncshell."));
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
if (ImGui.Button("Create Syncshell")) if (ImGui.Button(L("GroupPanel.Create.Button", "Create Syncshell")))
{ {
try try
{ {
@@ -256,7 +274,7 @@ internal sealed class GroupPanel
_errorGroupCreate = true; _errorGroupCreate = true;
if (ex.Message.Contains("name is already in use", StringComparison.OrdinalIgnoreCase)) if (ex.Message.Contains("name is already in use", StringComparison.OrdinalIgnoreCase))
{ {
_errorGroupCreateMessage = "Le nom de la Syncshell est déjà utilisé."; _errorGroupCreateMessage = L("GroupPanel.Create.Error.NameInUse", "Le nom de la Syncshell est déjà utilisé.");
} }
else else
{ {
@@ -272,28 +290,28 @@ internal sealed class GroupPanel
_errorGroupCreateMessage = string.Empty; _errorGroupCreateMessage = string.Empty;
if (!string.IsNullOrWhiteSpace(_lastCreatedGroup.Group.Alias)) if (!string.IsNullOrWhiteSpace(_lastCreatedGroup.Group.Alias))
{ {
ImGui.TextUnformatted("Syncshell Name: " + _lastCreatedGroup.Group.Alias); ImGui.TextUnformatted(L("GroupPanel.Create.Result.Name", "Syncshell Name: {0}", _lastCreatedGroup.Group.Alias));
} }
ImGui.TextUnformatted("Syncshell ID: " + _lastCreatedGroup.Group.GID); ImGui.TextUnformatted(L("GroupPanel.Create.Result.Id", "Syncshell ID: {0}", _lastCreatedGroup.Group.GID));
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Syncshell Password: " + _lastCreatedGroup.Password); ImGui.TextUnformatted(L("GroupPanel.Create.Result.Password", "Syncshell Password: {0}", _lastCreatedGroup.Password));
ImGui.SameLine(); ImGui.SameLine();
if (_uiShared.IconButton(FontAwesomeIcon.Copy)) if (_uiShared.IconButton(FontAwesomeIcon.Copy))
{ {
ImGui.SetClipboardText(_lastCreatedGroup.Password); ImGui.SetClipboardText(_lastCreatedGroup.Password);
} }
UiSharedService.TextWrapped("You can change the Syncshell password later at any time."); UiSharedService.TextWrapped(L("GroupPanel.Create.Result.ChangeLater", "You can change the Syncshell password later at any time."));
if (_lastCreatedGroup.IsTemporary && _lastCreatedGroup.ExpiresAt != null) if (_lastCreatedGroup.IsTemporary && _lastCreatedGroup.ExpiresAt != null)
{ {
var expiresLocal = _lastCreatedGroup.ExpiresAt.Value.ToLocalTime(); var expiresLocal = _lastCreatedGroup.ExpiresAt.Value.ToLocalTime();
UiSharedService.TextWrapped($"Cette Syncshell expirera le {expiresLocal:g} (heure locale)."); UiSharedService.TextWrapped(L("GroupPanel.Create.Result.TempExpires", "Cette Syncshell expirera le {0:g} (heure locale).", expiresLocal));
} }
} }
if (_errorGroupCreate) if (_errorGroupCreate)
{ {
var msg = string.IsNullOrWhiteSpace(_errorGroupCreateMessage) var msg = string.IsNullOrWhiteSpace(_errorGroupCreateMessage)
? "You are already owner of the maximum amount of Syncshells (3) or joined the maximum amount of Syncshells (6). Relinquish ownership of your own Syncshells to someone else or leave existing Syncshells." ? L("GroupPanel.Create.Error.Generic", "You are already owner of the maximum amount of Syncshells (3) or joined the maximum amount of Syncshells (6). Relinquish ownership of your own Syncshells to someone else or leave existing Syncshells.")
: _errorGroupCreateMessage; : _errorGroupCreateMessage;
UiSharedService.ColorTextWrapped(msg, new Vector4(1, 0, 0, 1)); UiSharedService.ColorTextWrapped(msg, new Vector4(1, 0, 0, 1));
} }
@@ -332,7 +350,7 @@ internal sealed class GroupPanel
ImGui.PushFont(UiBuilder.IconFont); ImGui.PushFont(UiBuilder.IconFont);
ImGui.TextUnformatted(FontAwesomeIcon.Crown.ToIconString()); ImGui.TextUnformatted(FontAwesomeIcon.Crown.ToIconString());
ImGui.PopFont(); ImGui.PopFont();
UiSharedService.AttachToolTip("You are the owner of Syncshell " + groupName); UiSharedService.AttachToolTip(L("GroupPanel.Syncshell.OwnerTooltip", "You are the owner of Syncshell {0}", groupName));
ImGui.SameLine(); ImGui.SameLine();
} }
else if (groupDto.GroupUserInfo.IsModerator()) else if (groupDto.GroupUserInfo.IsModerator())
@@ -340,7 +358,7 @@ internal sealed class GroupPanel
ImGui.PushFont(UiBuilder.IconFont); ImGui.PushFont(UiBuilder.IconFont);
ImGui.TextUnformatted(FontAwesomeIcon.UserShield.ToIconString()); ImGui.TextUnformatted(FontAwesomeIcon.UserShield.ToIconString());
ImGui.PopFont(); ImGui.PopFont();
UiSharedService.AttachToolTip("You are a moderator of Syncshell " + groupName); UiSharedService.AttachToolTip(L("GroupPanel.Syncshell.ModeratorTooltip", "You are a moderator of Syncshell {0}", groupName));
ImGui.SameLine(); ImGui.SameLine();
} }
@@ -358,29 +376,33 @@ internal sealed class GroupPanel
var totalMembers = pairsInGroup.Count + 1; var totalMembers = pairsInGroup.Count + 1;
var connectedMembers = pairsInGroup.Count(p => p.IsOnline) + 1; var connectedMembers = pairsInGroup.Count(p => p.IsOnline) + 1;
var maxCapacity = ApiController.ServerInfo.MaxGroupUserCount; var maxCapacity = ApiController.ServerInfo.MaxGroupUserCount;
ImGui.TextUnformatted($"{connectedMembers}/{totalMembers}"); ImGui.TextUnformatted(L("GroupPanel.Syncshell.MemberCount", "{0}/{1}", connectedMembers, totalMembers));
UiSharedService.AttachToolTip("Membres connectés / membres totaux" + Environment.NewLine + UiSharedService.AttachToolTip(
$"Capacité maximale : {maxCapacity}" + Environment.NewLine + L("GroupPanel.Syncshell.MemberCountTooltip",
"Syncshell ID: " + groupDto.Group.GID); "Membres connectés / membres totaux\nCapacité maximale : {0}\nSyncshell ID: {1}",
maxCapacity,
groupDto.Group.GID));
if (textIsGid) ImGui.PushFont(UiBuilder.MonoFont); if (textIsGid) ImGui.PushFont(UiBuilder.MonoFont);
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted(groupName); ImGui.TextUnformatted(groupName);
if (textIsGid) ImGui.PopFont(); if (textIsGid) ImGui.PopFont();
UiSharedService.AttachToolTip("Left click to switch between GID display and comment" + Environment.NewLine + UiSharedService.AttachToolTip(L("GroupPanel.Syncshell.NameTooltip",
"Right click to change comment for " + groupName + Environment.NewLine + Environment.NewLine "Left click to switch between GID display and comment\nRight click to change comment for {0}\n\nUsers: {1}, Owner: {2}",
+ "Users: " + (pairsInGroup.Count + 1) + ", Owner: " + groupDto.OwnerAliasOrUID); groupName,
pairsInGroup.Count + 1,
groupDto.OwnerAliasOrUID));
if (groupDto.IsTemporary) if (groupDto.IsTemporary)
{ {
ImGui.SameLine(); ImGui.SameLine();
UiSharedService.ColorText("(Temp)", ImGuiColors.DalamudOrange); UiSharedService.ColorText(L("GroupPanel.Syncshell.TempTag", "(Temp)"), ImGuiColors.DalamudOrange);
if (groupDto.ExpiresAt != null) if (groupDto.ExpiresAt != null)
{ {
var tempExpireLocal = groupDto.ExpiresAt.Value.ToLocalTime(); var tempExpireLocal = groupDto.ExpiresAt.Value.ToLocalTime();
UiSharedService.AttachToolTip($"Expire le {tempExpireLocal:g}"); UiSharedService.AttachToolTip(L("GroupPanel.Syncshell.TempExpires", "Expire le {0:g}", tempExpireLocal));
} }
else else
{ {
UiSharedService.AttachToolTip("Syncshell temporaire"); UiSharedService.AttachToolTip(L("GroupPanel.Syncshell.TempTooltip", "Syncshell temporaire"));
} }
} }
if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
@@ -406,7 +428,7 @@ internal sealed class GroupPanel
{ {
var buttonSizes = _uiShared.GetIconButtonSize(FontAwesomeIcon.Bars).X + _uiShared.GetIconButtonSize(FontAwesomeIcon.LockOpen).X; var buttonSizes = _uiShared.GetIconButtonSize(FontAwesomeIcon.Bars).X + _uiShared.GetIconButtonSize(FontAwesomeIcon.LockOpen).X;
ImGui.SetNextItemWidth(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetCursorPosX() - buttonSizes - ImGui.GetStyle().ItemSpacing.X * 2); ImGui.SetNextItemWidth(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetCursorPosX() - buttonSizes - ImGui.GetStyle().ItemSpacing.X * 2);
if (ImGui.InputTextWithHint("", "Comment/Notes", ref _editGroupComment, 255, ImGuiInputTextFlags.EnterReturnsTrue)) if (ImGui.InputTextWithHint("", L("GroupPanel.CommentHint", "Comment/Notes"), ref _editGroupComment, 255, ImGuiInputTextFlags.EnterReturnsTrue))
{ {
_serverConfigurationManager.SetNoteForGid(groupDto.GID, _editGroupComment); _serverConfigurationManager.SetNoteForGid(groupDto.GID, _editGroupComment);
_editGroupEntry = string.Empty; _editGroupEntry = string.Empty;
@@ -417,7 +439,7 @@ internal sealed class GroupPanel
{ {
_editGroupEntry = string.Empty; _editGroupEntry = string.Empty;
} }
UiSharedService.AttachToolTip("Hit ENTER to save\nRight click to cancel"); UiSharedService.AttachToolTip(L("GroupPanel.CommentTooltip", "Hit ENTER to save\nRight click to cancel"));
} }
@@ -426,26 +448,26 @@ internal sealed class GroupPanel
if (_showModalBanList && !_modalBanListOpened) if (_showModalBanList && !_modalBanListOpened)
{ {
_modalBanListOpened = true; _modalBanListOpened = true;
ImGui.OpenPopup("Manage Banlist for " + groupDto.GID); ImGui.OpenPopup(L("GroupPanel.Banlist.Title", "Manage Banlist for {0}", groupDto.GID));
} }
if (!_showModalBanList) _modalBanListOpened = false; if (!_showModalBanList) _modalBanListOpened = false;
if (ImGui.BeginPopupModal("Manage Banlist for " + groupDto.GID, ref _showModalBanList, UiSharedService.PopupWindowFlags)) if (ImGui.BeginPopupModal(L("GroupPanel.Banlist.Title", "Manage Banlist for {0}", groupDto.GID), ref _showModalBanList, UiSharedService.PopupWindowFlags))
{ {
if (_uiShared.IconTextButton(FontAwesomeIcon.Retweet, "Refresh Banlist from Server")) if (_uiShared.IconTextButton(FontAwesomeIcon.Retweet, L("GroupPanel.Banlist.Refresh", "Refresh Banlist from Server")))
{ {
_bannedUsers = ApiController.GroupGetBannedUsers(groupDto).Result; _bannedUsers = ApiController.GroupGetBannedUsers(groupDto).Result;
} }
if (ImGui.BeginTable("bannedusertable" + groupDto.GID, 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.ScrollY)) if (ImGui.BeginTable("bannedusertable" + groupDto.GID, 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.ScrollY))
{ {
ImGui.TableSetupColumn("UID", ImGuiTableColumnFlags.None, 1); ImGui.TableSetupColumn(L("GroupPanel.Banlist.Column.Uid", "UID"), ImGuiTableColumnFlags.None, 1);
ImGui.TableSetupColumn("Alias", ImGuiTableColumnFlags.None, 1); ImGui.TableSetupColumn(L("GroupPanel.Banlist.Column.Alias", "Alias"), ImGuiTableColumnFlags.None, 1);
ImGui.TableSetupColumn("By", ImGuiTableColumnFlags.None, 1); ImGui.TableSetupColumn(L("GroupPanel.Banlist.Column.By", "By"), ImGuiTableColumnFlags.None, 1);
ImGui.TableSetupColumn("Date", ImGuiTableColumnFlags.None, 2); ImGui.TableSetupColumn(L("GroupPanel.Banlist.Column.Date", "Date"), ImGuiTableColumnFlags.None, 2);
ImGui.TableSetupColumn("Reason", ImGuiTableColumnFlags.None, 3); ImGui.TableSetupColumn(L("GroupPanel.Banlist.Column.Reason", "Reason"), ImGuiTableColumnFlags.None, 3);
ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.None, 1); ImGui.TableSetupColumn(L("GroupPanel.Banlist.Column.Actions", "Actions"), ImGuiTableColumnFlags.None, 1);
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
@@ -462,7 +484,7 @@ internal sealed class GroupPanel
ImGui.TableNextColumn(); ImGui.TableNextColumn();
UiSharedService.TextWrapped(bannedUser.Reason); UiSharedService.TextWrapped(bannedUser.Reason);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (_uiShared.IconTextButton(FontAwesomeIcon.Check, "Unban#" + bannedUser.UID)) if (_uiShared.IconTextButton(FontAwesomeIcon.Check, L("GroupPanel.Banlist.Unban", "Unban") + "#" + bannedUser.UID))
{ {
_ = ApiController.GroupUnbanUser(bannedUser); _ = ApiController.GroupUnbanUser(bannedUser);
_bannedUsers.RemoveAll(b => string.Equals(b.UID, bannedUser.UID, StringComparison.Ordinal)); _bannedUsers.RemoveAll(b => string.Equals(b.UID, bannedUser.UID, StringComparison.Ordinal));
@@ -478,18 +500,18 @@ internal sealed class GroupPanel
if (_showModalChangePassword && !_modalChangePwOpened) if (_showModalChangePassword && !_modalChangePwOpened)
{ {
_modalChangePwOpened = true; _modalChangePwOpened = true;
ImGui.OpenPopup("Change Syncshell Password"); ImGui.OpenPopup(L("GroupPanel.Password.Title", "Change Syncshell Password"));
} }
if (!_showModalChangePassword) _modalChangePwOpened = false; if (!_showModalChangePassword) _modalChangePwOpened = false;
if (ImGui.BeginPopupModal("Change Syncshell Password", ref _showModalChangePassword, UiSharedService.PopupWindowFlags)) if (ImGui.BeginPopupModal(L("GroupPanel.Password.Title", "Change Syncshell Password"), ref _showModalChangePassword, UiSharedService.PopupWindowFlags))
{ {
UiSharedService.TextWrapped("Enter the new Syncshell password for Syncshell " + name + " here."); UiSharedService.TextWrapped(L("GroupPanel.Password.Description", "Enter the new Syncshell password for Syncshell {0} here.", name));
UiSharedService.TextWrapped("This action is irreversible"); UiSharedService.TextWrapped(L("GroupPanel.Password.Warning", "This action is irreversible"));
ImGui.SetNextItemWidth(-1); ImGui.SetNextItemWidth(-1);
ImGui.InputTextWithHint("##changepw", "New password for " + name, ref _newSyncShellPassword, 255); ImGui.InputTextWithHint("##changepw", L("GroupPanel.Password.Hint", "New password for {0}", name), ref _newSyncShellPassword, 255);
if (ImGui.Button("Change password")) if (ImGui.Button(L("GroupPanel.Password.Button", "Change password")))
{ {
var pw = _newSyncShellPassword; var pw = _newSyncShellPassword;
_isPasswordValid = ApiController.GroupChangePassword(new(groupDto.Group, pw)).Result; _isPasswordValid = ApiController.GroupChangePassword(new(groupDto.Group, pw)).Result;
@@ -499,7 +521,7 @@ internal sealed class GroupPanel
if (!_isPasswordValid) if (!_isPasswordValid)
{ {
UiSharedService.ColorTextWrapped("The selected password is too short. It must be at least 10 characters.", new Vector4(1, 0, 0, 1)); UiSharedService.ColorTextWrapped(L("GroupPanel.Password.Error.TooShort", "The selected password is too short. It must be at least 10 characters."), new Vector4(1, 0, 0, 1));
} }
UiSharedService.SetScaledWindowSize(290); UiSharedService.SetScaledWindowSize(290);
@@ -509,29 +531,28 @@ internal sealed class GroupPanel
if (_showModalBulkOneTimeInvites && !_modalBulkOneTimeInvitesOpened) if (_showModalBulkOneTimeInvites && !_modalBulkOneTimeInvitesOpened)
{ {
_modalBulkOneTimeInvitesOpened = true; _modalBulkOneTimeInvitesOpened = true;
ImGui.OpenPopup("Create Bulk One-Time Invites"); ImGui.OpenPopup(L("GroupPanel.Invites.Title", "Create Bulk One-Time Invites"));
} }
if (!_showModalBulkOneTimeInvites) _modalBulkOneTimeInvitesOpened = false; if (!_showModalBulkOneTimeInvites) _modalBulkOneTimeInvitesOpened = false;
if (ImGui.BeginPopupModal("Create Bulk One-Time Invites", ref _showModalBulkOneTimeInvites, UiSharedService.PopupWindowFlags)) if (ImGui.BeginPopupModal(L("GroupPanel.Invites.Title", "Create Bulk One-Time Invites"), ref _showModalBulkOneTimeInvites, UiSharedService.PopupWindowFlags))
{ {
UiSharedService.TextWrapped("This allows you to create up to 100 one-time invites at once for the Syncshell " + name + "." + Environment.NewLine UiSharedService.TextWrapped(L("GroupPanel.Invites.Description", "This allows you to create up to 100 one-time invites at once for the Syncshell {0}.\nThe invites are valid for 24h after creation and will automatically expire.", name));
+ "The invites are valid for 24h after creation and will automatically expire.");
ImGui.Separator(); ImGui.Separator();
if (_bulkOneTimeInvites.Count == 0) if (_bulkOneTimeInvites.Count == 0)
{ {
ImGui.SetNextItemWidth(-1); ImGui.SetNextItemWidth(-1);
ImGui.SliderInt("Amount##bulkinvites", ref _bulkInviteCount, 1, 100); ImGui.SliderInt(L("GroupPanel.Invites.AmountLabel", "Amount") + "##bulkinvites", ref _bulkInviteCount, 1, 100);
if (_uiShared.IconTextButton(FontAwesomeIcon.MailBulk, "Create invites")) if (_uiShared.IconTextButton(FontAwesomeIcon.MailBulk, L("GroupPanel.Invites.CreateButton", "Create invites")))
{ {
_bulkOneTimeInvites = ApiController.GroupCreateTempInvite(groupDto, _bulkInviteCount).Result; _bulkOneTimeInvites = ApiController.GroupCreateTempInvite(groupDto, _bulkInviteCount).Result;
} }
} }
else else
{ {
UiSharedService.TextWrapped("A total of " + _bulkOneTimeInvites.Count + " invites have been created."); UiSharedService.TextWrapped(L("GroupPanel.Invites.Result", "A total of {0} invites have been created.", _bulkOneTimeInvites.Count));
if (_uiShared.IconTextButton(FontAwesomeIcon.Copy, "Copy invites to clipboard")) if (_uiShared.IconTextButton(FontAwesomeIcon.Copy, L("GroupPanel.Invites.Copy", "Copy invites to clipboard")))
{ {
ImGui.SetClipboardText(string.Join(Environment.NewLine, _bulkOneTimeInvites)); ImGui.SetClipboardText(string.Join(Environment.NewLine, _bulkOneTimeInvites));
} }
@@ -578,14 +599,14 @@ internal sealed class GroupPanel
if (visibleUsers.Count > 0) if (visibleUsers.Count > 0)
{ {
ImGui.TextUnformatted("Visible"); ImGui.TextUnformatted(L("GroupPanel.List.Visible", "Visible"));
ImGui.Separator(); ImGui.Separator();
_uidDisplayHandler.RenderPairList(visibleUsers); _uidDisplayHandler.RenderPairList(visibleUsers);
} }
if (onlineUsers.Count > 0) if (onlineUsers.Count > 0)
{ {
ImGui.TextUnformatted("Online"); ImGui.TextUnformatted(L("GroupPanel.List.Online", "Online"));
ImGui.Separator(); ImGui.Separator();
_uidDisplayHandler.RenderPairList(onlineUsers); _uidDisplayHandler.RenderPairList(onlineUsers);
} }
@@ -593,12 +614,12 @@ internal sealed class GroupPanel
if (offlineUsers.Count > 0) if (offlineUsers.Count > 0)
{ {
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey); ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey);
ImGui.TextUnformatted("Offline/Unknown"); ImGui.TextUnformatted(L("GroupPanel.List.Offline", "Offline/Unknown"));
ImGui.PopStyleColor(); ImGui.PopStyleColor();
ImGui.Separator(); ImGui.Separator();
if (hideOfflineUsers) if (hideOfflineUsers)
{ {
UiSharedService.ColorText($" {offlineUsers.Count} offline users omitted from display.", ImGuiColors.DalamudGrey); UiSharedService.ColorText(L("GroupPanel.List.OfflineOmitted", " {0} offline users omitted from display.", offlineUsers.Count), ImGuiColors.DalamudGrey);
} }
else else
{ {
@@ -653,11 +674,11 @@ internal sealed class GroupPanel
ImGui.BeginTooltip(); ImGui.BeginTooltip();
if (!invitesEnabled || soundsDisabled || animDisabled || vfxDisabled) if (!invitesEnabled || soundsDisabled || animDisabled || vfxDisabled)
{ {
ImGui.TextUnformatted("Syncshell permissions"); ImGui.TextUnformatted(L("GroupPanel.Permissions.Header", "Syncshell permissions"));
if (!invitesEnabled) if (!invitesEnabled)
{ {
var lockedText = "Syncshell is closed for joining"; var lockedText = L("GroupPanel.Permissions.InvitesDisabled", "Syncshell is closed for joining");
_uiShared.IconText(lockedIcon); _uiShared.IconText(lockedIcon);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(lockedText); ImGui.TextUnformatted(lockedText);
@@ -665,7 +686,7 @@ internal sealed class GroupPanel
if (soundsDisabled) if (soundsDisabled)
{ {
var soundsText = "Sound sync disabled through owner"; var soundsText = L("GroupPanel.Permissions.SoundDisabledOwner", "Sound sync disabled through owner");
_uiShared.IconText(soundsIcon); _uiShared.IconText(soundsIcon);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(soundsText); ImGui.TextUnformatted(soundsText);
@@ -673,7 +694,7 @@ internal sealed class GroupPanel
if (animDisabled) if (animDisabled)
{ {
var animText = "Animation sync disabled through owner"; var animText = L("GroupPanel.Permissions.AnimationDisabledOwner", "Animation sync disabled through owner");
_uiShared.IconText(animIcon); _uiShared.IconText(animIcon);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(animText); ImGui.TextUnformatted(animText);
@@ -681,7 +702,7 @@ internal sealed class GroupPanel
if (vfxDisabled) if (vfxDisabled)
{ {
var vfxText = "VFX sync disabled through owner"; var vfxText = L("GroupPanel.Permissions.VfxDisabledOwner", "VFX sync disabled through owner");
_uiShared.IconText(vfxIcon); _uiShared.IconText(vfxIcon);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(vfxText); ImGui.TextUnformatted(vfxText);
@@ -693,11 +714,11 @@ internal sealed class GroupPanel
if (!invitesEnabled || soundsDisabled || animDisabled || vfxDisabled) if (!invitesEnabled || soundsDisabled || animDisabled || vfxDisabled)
ImGui.Separator(); ImGui.Separator();
ImGui.TextUnformatted("Your permissions"); ImGui.TextUnformatted(L("GroupPanel.Permissions.OwnHeader", "Your permissions"));
if (userSoundsDisabled) if (userSoundsDisabled)
{ {
var userSoundsText = "Sound sync disabled through you"; var userSoundsText = L("GroupPanel.Permissions.SoundDisabledSelf", "Sound sync disabled through you");
_uiShared.IconText(userSoundsIcon); _uiShared.IconText(userSoundsIcon);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userSoundsText); ImGui.TextUnformatted(userSoundsText);
@@ -705,7 +726,7 @@ internal sealed class GroupPanel
if (userAnimDisabled) if (userAnimDisabled)
{ {
var userAnimText = "Animation sync disabled through you"; var userAnimText = L("GroupPanel.Permissions.AnimationDisabledSelf", "Animation sync disabled through you");
_uiShared.IconText(userAnimIcon); _uiShared.IconText(userAnimIcon);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userAnimText); ImGui.TextUnformatted(userAnimText);
@@ -713,14 +734,14 @@ internal sealed class GroupPanel
if (userVFXDisabled) if (userVFXDisabled)
{ {
var userVFXText = "VFX sync disabled through you"; var userVFXText = L("GroupPanel.Permissions.VfxDisabledSelf", "VFX sync disabled through you");
_uiShared.IconText(userVFXIcon); _uiShared.IconText(userVFXIcon);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userVFXText); ImGui.TextUnformatted(userVFXText);
} }
if (!invitesEnabled || soundsDisabled || animDisabled || vfxDisabled) if (!invitesEnabled || soundsDisabled || animDisabled || vfxDisabled)
UiSharedService.TextWrapped("Note that syncshell permissions for disabling take precedence over your own set permissions"); UiSharedService.TextWrapped(L("GroupPanel.Permissions.NotePriority", "Note that syncshell permissions for disabling take precedence over your own set permissions"));
} }
ImGui.EndTooltip(); ImGui.EndTooltip();
} }
@@ -732,7 +753,8 @@ internal sealed class GroupPanel
var userPerm = groupDto.GroupUserPermissions ^ GroupUserPermissions.Paused; var userPerm = groupDto.GroupUserPermissions ^ GroupUserPermissions.Paused;
_ = ApiController.GroupChangeIndividualPermissionState(new GroupPairUserPermissionDto(groupDto.Group, new UserData(ApiController.UID), userPerm)); _ = ApiController.GroupChangeIndividualPermissionState(new GroupPairUserPermissionDto(groupDto.Group, new UserData(ApiController.UID), userPerm));
} }
UiSharedService.AttachToolTip((groupDto.GroupUserPermissions.IsPaused() ? "Resume" : "Pause") + " pairing with all users in this Syncshell"); UiSharedService.AttachToolTip(L("GroupPanel.PauseToggle.Tooltip", "{0} pairing with all users in this Syncshell",
groupDto.GroupUserPermissions.IsPaused() ? L("GroupPanel.PauseToggle.Resume", "Resume") : L("GroupPanel.PauseToggle.Pause", "Pause")));
ImGui.SameLine(); ImGui.SameLine();
if (_uiShared.IconButton(FontAwesomeIcon.Bars)) if (_uiShared.IconButton(FontAwesomeIcon.Bars))
@@ -742,28 +764,32 @@ internal sealed class GroupPanel
if (ImGui.BeginPopup("ShellPopup")) if (ImGui.BeginPopup("ShellPopup"))
{ {
if (_uiShared.IconTextButton(FontAwesomeIcon.ArrowCircleLeft, "Leave Syncshell") && UiSharedService.CtrlPressed()) if (_uiShared.IconTextButton(FontAwesomeIcon.ArrowCircleLeft, L("GroupPanel.Popup.Leave", "Leave Syncshell")) && UiSharedService.CtrlPressed())
{ {
_ = ApiController.GroupLeave(groupDto); _ = ApiController.GroupLeave(groupDto);
} }
UiSharedService.AttachToolTip("Hold CTRL and click to leave this Syncshell" + (!string.Equals(groupDto.OwnerUID, ApiController.UID, StringComparison.Ordinal) ? string.Empty : Environment.NewLine UiSharedService.AttachToolTip(L("GroupPanel.Popup.LeaveTooltip", "Hold CTRL and click to leave this Syncshell{0}",
+ "WARNING: This action is irreversible" + Environment.NewLine + "Leaving an owned Syncshell will transfer the ownership to a random person in the Syncshell.")); !string.Equals(groupDto.OwnerUID, ApiController.UID, StringComparison.Ordinal)
? string.Empty
: Environment.NewLine + L("GroupPanel.Popup.LeaveWarning", "WARNING: This action is irreversible\nLeaving an owned Syncshell will transfer the ownership to a random person in the Syncshell.")));
if (_uiShared.IconTextButton(FontAwesomeIcon.Copy, "Copy ID")) if (_uiShared.IconTextButton(FontAwesomeIcon.Copy, L("GroupPanel.Popup.CopyId", "Copy ID")))
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
ImGui.SetClipboardText(groupDto.GroupAliasOrGID); ImGui.SetClipboardText(groupDto.GroupAliasOrGID);
} }
UiSharedService.AttachToolTip("Copy Syncshell ID to Clipboard"); UiSharedService.AttachToolTip(L("GroupPanel.Popup.CopyIdTooltip", "Copy Syncshell ID to Clipboard"));
if (_uiShared.IconTextButton(FontAwesomeIcon.StickyNote, "Copy Notes")) if (_uiShared.IconTextButton(FontAwesomeIcon.StickyNote, L("GroupPanel.Popup.CopyNotes", "Copy Notes")))
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
ImGui.SetClipboardText(UiSharedService.GetNotes(groupPairs)); ImGui.SetClipboardText(UiSharedService.GetNotes(groupPairs));
} }
UiSharedService.AttachToolTip("Copies all your notes for all users in this Syncshell to the clipboard." + Environment.NewLine + "They can be imported via Settings -> General -> Notes -> Import notes from clipboard"); UiSharedService.AttachToolTip(L("GroupPanel.Popup.CopyNotesTooltip", "Copies all your notes for all users in this Syncshell to the clipboard.\nThey can be imported via Settings -> General -> Notes -> Import notes from clipboard"));
var soundsText = userSoundsDisabled ? "Enable sound sync" : "Disable sound sync"; var soundsText = userSoundsDisabled
? L("GroupPanel.Popup.EnableSound", "Enable sound sync")
: L("GroupPanel.Popup.DisableSound", "Disable sound sync");
if (_uiShared.IconTextButton(userSoundsIcon, soundsText)) if (_uiShared.IconTextButton(userSoundsIcon, soundsText))
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
@@ -771,12 +797,11 @@ internal sealed class GroupPanel
perm.SetDisableSounds(!perm.IsDisableSounds()); perm.SetDisableSounds(!perm.IsDisableSounds());
_ = ApiController.GroupChangeIndividualPermissionState(new(groupDto.Group, new UserData(ApiController.UID), perm)); _ = ApiController.GroupChangeIndividualPermissionState(new(groupDto.Group, new UserData(ApiController.UID), perm));
} }
UiSharedService.AttachToolTip("Sets your allowance for sound synchronization for users of this syncshell." UiSharedService.AttachToolTip(L("GroupPanel.Popup.SoundTooltip", "Sets your allowance for sound synchronization for users of this syncshell.\nDisabling the synchronization will stop applying sound modifications for users of this syncshell.\nNote: this setting can be forcefully overridden to 'disabled' through the syncshell owner.\nNote: this setting does not apply to individual pairs that are also in the syncshell."));
+ Environment.NewLine + "Disabling the synchronization will stop applying sound modifications for users of this syncshell."
+ Environment.NewLine + "Note: this setting can be forcefully overridden to 'disabled' through the syncshell owner."
+ Environment.NewLine + "Note: this setting does not apply to individual pairs that are also in the syncshell.");
var animText = userAnimDisabled ? "Enable animations sync" : "Disable animations sync"; var animText = userAnimDisabled
? L("GroupPanel.Popup.EnableAnimations", "Enable animations sync")
: L("GroupPanel.Popup.DisableAnimations", "Disable animations sync");
if (_uiShared.IconTextButton(userAnimIcon, animText)) if (_uiShared.IconTextButton(userAnimIcon, animText))
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
@@ -784,13 +809,11 @@ internal sealed class GroupPanel
perm.SetDisableAnimations(!perm.IsDisableAnimations()); perm.SetDisableAnimations(!perm.IsDisableAnimations());
_ = ApiController.GroupChangeIndividualPermissionState(new(groupDto.Group, new UserData(ApiController.UID), perm)); _ = ApiController.GroupChangeIndividualPermissionState(new(groupDto.Group, new UserData(ApiController.UID), perm));
} }
UiSharedService.AttachToolTip("Sets your allowance for animations synchronization for users of this syncshell." UiSharedService.AttachToolTip(L("GroupPanel.Popup.AnimTooltip", "Sets your allowance for animations synchronization for users of this syncshell.\nDisabling the synchronization will stop applying animations modifications for users of this syncshell.\nNote: this setting might also affect sound synchronization\nNote: this setting can be forcefully overridden to 'disabled' through the syncshell owner.\nNote: this setting does not apply to individual pairs that are also in the syncshell."));
+ Environment.NewLine + "Disabling the synchronization will stop applying animations modifications for users of this syncshell."
+ Environment.NewLine + "Note: this setting might also affect sound synchronization"
+ Environment.NewLine + "Note: this setting can be forcefully overridden to 'disabled' through the syncshell owner."
+ Environment.NewLine + "Note: this setting does not apply to individual pairs that are also in the syncshell.");
var vfxText = userVFXDisabled ? "Enable VFX sync" : "Disable VFX sync"; var vfxText = userVFXDisabled
? L("GroupPanel.Popup.EnableVfx", "Enable VFX sync")
: L("GroupPanel.Popup.DisableVfx", "Disable VFX sync");
if (_uiShared.IconTextButton(userVFXIcon, vfxText)) if (_uiShared.IconTextButton(userVFXIcon, vfxText))
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
@@ -798,16 +821,12 @@ internal sealed class GroupPanel
perm.SetDisableVFX(!perm.IsDisableVFX()); perm.SetDisableVFX(!perm.IsDisableVFX());
_ = ApiController.GroupChangeIndividualPermissionState(new(groupDto.Group, new UserData(ApiController.UID), perm)); _ = ApiController.GroupChangeIndividualPermissionState(new(groupDto.Group, new UserData(ApiController.UID), perm));
} }
UiSharedService.AttachToolTip("Sets your allowance for VFX synchronization for users of this syncshell." UiSharedService.AttachToolTip(L("GroupPanel.Popup.VfxTooltip", "Sets your allowance for VFX synchronization for users of this syncshell.\nDisabling the synchronization will stop applying VFX modifications for users of this syncshell.\nNote: this setting might also affect animation synchronization to some degree\nNote: this setting can be forcefully overridden to 'disabled' through the syncshell owner.\nNote: this setting does not apply to individual pairs that are also in the syncshell."));
+ Environment.NewLine + "Disabling the synchronization will stop applying VFX modifications for users of this syncshell."
+ Environment.NewLine + "Note: this setting might also affect animation synchronization to some degree"
+ Environment.NewLine + "Note: this setting can be forcefully overridden to 'disabled' through the syncshell owner."
+ Environment.NewLine + "Note: this setting does not apply to individual pairs that are also in the syncshell.");
if (isOwner || groupDto.GroupUserInfo.IsModerator()) if (isOwner || groupDto.GroupUserInfo.IsModerator())
{ {
ImGui.Separator(); ImGui.Separator();
if (_uiShared.IconTextButton(FontAwesomeIcon.Cog, "Open Admin Panel")) if (_uiShared.IconTextButton(FontAwesomeIcon.Cog, L("GroupPanel.Popup.OpenAdmin", "Open Admin Panel")))
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
_mainUi.Mediator.Publish(new OpenSyncshellAdminPanel(groupDto)); _mainUi.Mediator.Publish(new OpenSyncshellAdminPanel(groupDto));

View File

@@ -1,10 +1,12 @@
using Dalamud.Bindings.ImGui; using System;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Utility.Raii;
using MareSynchronos.API.Data.Extensions; using MareSynchronos.API.Data.Extensions;
using MareSynchronos.MareConfiguration; using MareSynchronos.MareConfiguration;
using MareSynchronos.UI.Handlers; using MareSynchronos.UI.Handlers;
using MareSynchronos.WebAPI; using MareSynchronos.WebAPI;
using MareSynchronos.Localization;
namespace MareSynchronos.UI.Components; namespace MareSynchronos.UI.Components;
@@ -17,6 +19,13 @@ public class PairGroupsUi
private readonly UidDisplayHandler _uidDisplayHandler; private readonly UidDisplayHandler _uidDisplayHandler;
private readonly UiSharedService _uiSharedService; private readonly UiSharedService _uiSharedService;
private string L(string key, string fallback, params object[] args)
{
var safeArgs = args ?? Array.Empty<object>();
return LocalizationService.Instance?.GetString(key, fallback, safeArgs)
?? string.Format(System.Globalization.CultureInfo.CurrentCulture, fallback, safeArgs);
}
public PairGroupsUi(MareConfigService mareConfig, TagHandler tagHandler, UidDisplayHandler uidDisplayHandler, ApiController apiController, public PairGroupsUi(MareConfigService mareConfig, TagHandler tagHandler, UidDisplayHandler uidDisplayHandler, ApiController apiController,
SelectPairForGroupUi selectGroupForPairUi, UiSharedService uiSharedService) SelectPairForGroupUi selectGroupForPairUi, UiSharedService uiSharedService)
{ {
@@ -65,21 +74,21 @@ public class PairGroupsUi
} }
if (allArePaused) if (allArePaused)
{ {
UiSharedService.AttachToolTip($"Resume pairing with all pairs in {tag}"); UiSharedService.AttachToolTip(L("PairGroups.ResumeAll", "Resume pairing with all pairs in {0}", tag));
} }
else else
{ {
UiSharedService.AttachToolTip($"Pause pairing with all pairs in {tag}"); UiSharedService.AttachToolTip(L("PairGroups.PauseAll", "Pause pairing with all pairs in {0}", tag));
} }
var buttonDeleteOffset = windowX + windowWidth - flyoutMenuX; var buttonDeleteOffset = windowX + windowWidth - flyoutMenuX;
ImGui.SameLine(buttonDeleteOffset); ImGui.SameLine(buttonDeleteOffset);
if (_uiSharedService.IconButton(FontAwesomeIcon.Bars)) if (_uiSharedService.IconButton(FontAwesomeIcon.Bars))
{ {
ImGui.OpenPopup("Group Flyout Menu"); ImGui.OpenPopup(L("PairGroups.Menu.Title", "Group Flyout Menu"));
} }
if (ImGui.BeginPopup("Group Flyout Menu")) if (ImGui.BeginPopup(L("PairGroups.Menu.Title", "Group Flyout Menu")))
{ {
using (ImRaii.PushId($"buttons-{tag}")) DrawGroupMenu(tag); using (ImRaii.PushId($"buttons-{tag}")) DrawGroupMenu(tag);
ImGui.EndPopup(); ImGui.EndPopup();
@@ -132,31 +141,35 @@ public class PairGroupsUi
private void DrawGroupMenu(string tag) private void DrawGroupMenu(string tag)
{ {
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Add people to " + tag)) if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, L("PairGroups.Menu.AddPeople", "Add people to {0}", tag)))
{ {
_selectGroupForPairUi.Open(tag); _selectGroupForPairUi.Open(tag);
} }
UiSharedService.AttachToolTip($"Add more users to Group {tag}"); UiSharedService.AttachToolTip(L("PairGroups.Menu.AddPeople.Tooltip", "Add more users to Group {0}", tag));
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete " + tag) && UiSharedService.CtrlPressed()) if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, L("PairGroups.Menu.Delete", "Delete {0}", tag)) && UiSharedService.CtrlPressed())
{ {
_tagHandler.RemoveTag(tag); _tagHandler.RemoveTag(tag);
} }
UiSharedService.AttachToolTip($"Delete Group {tag} (Will not delete the pairs)" + Environment.NewLine + "Hold CTRL to delete"); UiSharedService.AttachToolTip(L("PairGroups.Menu.Delete.Tooltip", "Delete Group {0} (Will not delete the pairs)\nHold CTRL to delete", tag));
} }
private void DrawName(string tag, bool isSpecialTag, int visible, int online, int? total) private void DrawName(string tag, bool isSpecialTag, int visible, int online, int? total)
{ {
string displayedName = tag switch string displayedName = tag switch
{ {
TagHandler.CustomUnpairedTag => "Unpaired", TagHandler.CustomUnpairedTag => L("PairGroups.Tag.Unpaired", "Unpaired"),
TagHandler.CustomOfflineTag => "Offline", TagHandler.CustomOfflineTag => L("PairGroups.Tag.Offline", "Offline"),
TagHandler.CustomOnlineTag => _mareConfig.Current.ShowOfflineUsersSeparately ? "Online" : "Contacts", TagHandler.CustomOnlineTag => _mareConfig.Current.ShowOfflineUsersSeparately
TagHandler.CustomVisibleTag => "Visible", ? L("PairGroups.Tag.Online", "Online")
: L("PairGroups.Tag.Contacts", "Contacts"),
TagHandler.CustomVisibleTag => L("PairGroups.Tag.Visible", "Visible"),
_ => tag _ => tag
}; };
string resultFolderName = !isSpecialTag ? $"{displayedName} ({visible}/{online}/{total} Pairs)" : $"{displayedName} ({online} Pairs)"; string resultFolderName = !isSpecialTag
? L("PairGroups.Header.WithCounts", "{0} ({1}/{2}/{3} Pairs)", displayedName, visible, online, total ?? 0)
: L("PairGroups.Header.Special", "{0} ({1} Pairs)", displayedName, online);
var icon = _tagHandler.IsTagOpen(tag) ? FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight; var icon = _tagHandler.IsTagOpen(tag) ? FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight;
_uiSharedService.IconText(icon); _uiSharedService.IconText(icon);
if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
@@ -173,11 +186,11 @@ public class PairGroupsUi
if (!isSpecialTag && ImGui.IsItemHovered()) if (!isSpecialTag && ImGui.IsItemHovered())
{ {
ImGui.BeginTooltip(); ImGui.BeginTooltip();
ImGui.TextUnformatted($"Group {tag}"); ImGui.TextUnformatted(L("PairGroups.Tooltip.Title", "Group {0}", tag));
ImGui.Separator(); ImGui.Separator();
ImGui.TextUnformatted($"{visible} Pairs visible"); ImGui.TextUnformatted(L("PairGroups.Tooltip.Visible", "{0} Pairs visible", visible));
ImGui.TextUnformatted($"{online} Pairs online/paused"); ImGui.TextUnformatted(L("PairGroups.Tooltip.Online", "{0} Pairs online/paused", online));
ImGui.TextUnformatted($"{total} Pairs total"); ImGui.TextUnformatted(L("PairGroups.Tooltip.Total", "{0} Pairs total", total ?? 0));
ImGui.EndTooltip(); ImGui.EndTooltip();
} }
} }

View File

@@ -28,17 +28,17 @@ public class BanUserPopupHandler : IPopupHandler
public void DrawContent() public void DrawContent()
{ {
UiSharedService.TextWrapped("User " + (_reportedPair.UserData.AliasOrUID) + " will be banned and removed from this Syncshell."); UiSharedService.TextWrapped(_uiSharedService.Localize("Popup.BanUser.Description", "User {0} will be banned and removed from this Syncshell.", _reportedPair.UserData.AliasOrUID));
ImGui.InputTextWithHint("##banreason", "Ban Reason", ref _banReason, 255); ImGui.InputTextWithHint("##banreason", _uiSharedService.Localize("Popup.BanUser.ReasonHint", "Ban Reason"), ref _banReason, 255);
if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserSlash, "Ban User")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserSlash, _uiSharedService.Localize("Popup.BanUser.Button", "Ban User")))
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
var reason = _banReason; var reason = _banReason;
_ = _apiController.GroupBanUser(new GroupPairDto(_group.Group, _reportedPair.UserData), reason); _ = _apiController.GroupBanUser(new GroupPairDto(_group.Group, _reportedPair.UserData), reason);
_banReason = string.Empty; _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.TextWrapped(_uiSharedService.Localize("Popup.BanUser.ReasonNote", "The reason will be displayed in the banlist. The current server-side alias if present (Vanity ID) will automatically be attached to the reason."));
} }
public void Open(OpenBanUserPopupMessage message) public void Open(OpenBanUserPopupMessage message)

View File

@@ -72,7 +72,7 @@ public class PopupHandler : WindowMediatorSubscriberBase
if (_currentHandler.ShowClose) if (_currentHandler.ShowClose)
{ {
ImGui.Separator(); ImGui.Separator();
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Times, "Close")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.Times, _uiSharedService.Localize("Popup.Generic.Close", "Close")))
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
} }

View File

@@ -29,23 +29,21 @@ internal class ReportPopupHandler : IPopupHandler
public void DrawContent() public void DrawContent()
{ {
using (_uiSharedService.UidFont.Push()) using (_uiSharedService.UidFont.Push())
UiSharedService.TextWrapped("Report " + _reportedPair!.UserData.AliasOrUID + " Profile"); UiSharedService.TextWrapped(_uiSharedService.Localize("Popup.Report.Title", "Report {0} Profile", _reportedPair!.UserData.AliasOrUID));
ImGui.InputTextMultiline("##reportReason", ref _reportReason, 500, new Vector2(500 - ImGui.GetStyle().ItemSpacing.X * 2, 200)); ImGui.InputTextMultiline("##reportReason", ref _reportReason, 500, new Vector2(500 - ImGui.GetStyle().ItemSpacing.X * 2, 200));
UiSharedService.TextWrapped($"Note: Sending a report will disable the offending profile globally.{Environment.NewLine}" + UiSharedService.TextWrapped(_uiSharedService.Localize("Popup.Report.Note", "Note: Sending a report will disable the offending profile globally.\nThe report will be sent to the team of your currently connected server.\nDepending on the severity of the offense the users profile or account can be permanently disabled or banned."));
$"The report will be sent to the team of your currently connected server.{Environment.NewLine}" + UiSharedService.ColorTextWrapped(_uiSharedService.Localize("Popup.Report.Warning", "Report spam and wrong reports will not be tolerated and can lead to permanent account suspension."), ImGuiColors.DalamudRed);
$"Depending on the severity of the offense the users profile or account can be permanently disabled or banned."); UiSharedService.ColorTextWrapped(_uiSharedService.Localize("Popup.Report.Scope", "This is not for reporting misbehavior but solely for the actual profile. Reports that are not solely for the profile will be ignored."), ImGuiColors.DalamudYellow);
UiSharedService.ColorTextWrapped("Report spam and wrong reports will not be tolerated and can lead to permanent account suspension.", ImGuiColors.DalamudRed);
UiSharedService.ColorTextWrapped("This is not for reporting misbehavior but solely for the actual profile. " +
"Reports that are not solely for the profile will be ignored.", ImGuiColors.DalamudYellow);
using (ImRaii.Disabled(string.IsNullOrEmpty(_reportReason))) using (ImRaii.Disabled(string.IsNullOrEmpty(_reportReason)))
{ {
if (_uiSharedService.IconTextButton(FontAwesomeIcon.ExclamationTriangle, "Send Report")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.ExclamationTriangle, _uiSharedService.Localize("Popup.Report.Button", "Send Report")))
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
var reason = _reportReason; var reason = _reportReason;
_ = _apiController.UserReportProfile(new(_reportedPair.UserData, reason)); _ = _apiController.UserReportProfile(new(_reportedPair.UserData, reason));
_reportReason = string.Empty;
} }
} }
} }

View File

@@ -36,7 +36,7 @@ public class SelectGroupForPairUi
} }
var name = PairName(_pair); var name = PairName(_pair);
var popupName = $"Choose Groups for {name}"; var popupName = _uiSharedService.Localize("PairGroups.Popup.Title", "Choose Groups for {0}", name);
if (_show) if (_show)
{ {
ImGui.OpenPopup(popupName); ImGui.OpenPopup(popupName);
@@ -49,7 +49,7 @@ public class SelectGroupForPairUi
var childHeight = tags.Count != 0 ? tags.Count * 25 : 1; var childHeight = tags.Count != 0 ? tags.Count * 25 : 1;
var childSize = new Vector2(0, childHeight > 100 ? 100 : childHeight) * ImGuiHelpers.GlobalScale; var childSize = new Vector2(0, childHeight > 100 ? 100 : childHeight) * ImGuiHelpers.GlobalScale;
ImGui.TextUnformatted($"Select the groups you want {name} to be in."); ImGui.TextUnformatted(_uiSharedService.Localize("PairGroups.Popup.SelectPrompt", "Select the groups you want {0} to be in.", name));
if (ImGui.BeginChild(name + "##listGroups", childSize)) if (ImGui.BeginChild(name + "##listGroups", childSize))
{ {
foreach (var tag in tags) foreach (var tag in tags)
@@ -60,13 +60,13 @@ public class SelectGroupForPairUi
} }
ImGui.Separator(); ImGui.Separator();
ImGui.TextUnformatted($"Create a new group for {name}."); ImGui.TextUnformatted(_uiSharedService.Localize("PairGroups.Popup.CreatePrompt", "Create a new group for {0}.", name));
if (_uiSharedService.IconButton(FontAwesomeIcon.Plus)) if (_uiSharedService.IconButton(FontAwesomeIcon.Plus))
{ {
HandleAddTag(); HandleAddTag();
} }
ImGui.SameLine(); ImGui.SameLine();
ImGui.InputTextWithHint("##category_name", "New Group", ref _tagNameToAdd, 40); ImGui.InputTextWithHint("##category_name", _uiSharedService.Localize("PairGroups.Popup.NewGroupHint", "New Group"), ref _tagNameToAdd, 40);
if (ImGui.IsKeyDown(ImGuiKey.Enter)) if (ImGui.IsKeyDown(ImGuiKey.Enter))
{ {
HandleAddTag(); HandleAddTag();

View File

@@ -1,6 +1,7 @@
using Dalamud.Bindings.ImGui; using Dalamud.Bindings.ImGui;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using MareSynchronos.PlayerData.Pairs; using MareSynchronos.PlayerData.Pairs;
using MareSynchronos.UI;
using MareSynchronos.UI.Handlers; using MareSynchronos.UI.Handlers;
using System.Numerics; using System.Numerics;
@@ -15,11 +16,13 @@ public class SelectPairForGroupUi
private HashSet<string> _peopleInGroup = new(StringComparer.Ordinal); private HashSet<string> _peopleInGroup = new(StringComparer.Ordinal);
private bool _show = false; private bool _show = false;
private string _tag = string.Empty; private string _tag = string.Empty;
private readonly UiSharedService _uiSharedService;
public SelectPairForGroupUi(TagHandler tagHandler, UidDisplayHandler uidDisplayHandler) public SelectPairForGroupUi(TagHandler tagHandler, UidDisplayHandler uidDisplayHandler, UiSharedService uiSharedService)
{ {
_tagHandler = tagHandler; _tagHandler = tagHandler;
_uidDisplayHandler = uidDisplayHandler; _uidDisplayHandler = uidDisplayHandler;
_uiSharedService = uiSharedService;
} }
public void Draw(List<Pair> pairs) public void Draw(List<Pair> pairs)
@@ -28,7 +31,7 @@ public class SelectPairForGroupUi
var minSize = new Vector2(300, workHeight < 400 ? workHeight : 400) * ImGuiHelpers.GlobalScale; var minSize = new Vector2(300, workHeight < 400 ? workHeight : 400) * ImGuiHelpers.GlobalScale;
var maxSize = new Vector2(300, 1000) * ImGuiHelpers.GlobalScale; var maxSize = new Vector2(300, 1000) * ImGuiHelpers.GlobalScale;
var popupName = $"Choose Users for Group {_tag}"; var popupName = _uiSharedService.Localize("PairGroups.SelectPairs.Title", "Choose Users for Group {0}", _tag);
if (!_show) if (!_show)
{ {
@@ -46,9 +49,9 @@ public class SelectPairForGroupUi
ImGui.SetNextWindowSizeConstraints(minSize, maxSize); ImGui.SetNextWindowSizeConstraints(minSize, maxSize);
if (ImGui.BeginPopupModal(popupName, ref _show, ImGuiWindowFlags.Popup | ImGuiWindowFlags.Modal)) if (ImGui.BeginPopupModal(popupName, ref _show, ImGuiWindowFlags.Popup | ImGuiWindowFlags.Modal))
{ {
ImGui.TextUnformatted($"Select users for group {_tag}"); ImGui.TextUnformatted(_uiSharedService.Localize("PairGroups.SelectPairs.SelectPrompt", "Select users for group {0}", _tag));
ImGui.InputTextWithHint("##filter", "Filter", ref _filter, 255, ImGuiInputTextFlags.None); ImGui.InputTextWithHint("##filter", _uiSharedService.Localize("PairGroups.SelectPairs.FilterHint", "Filter"), ref _filter, 255, ImGuiInputTextFlags.None);
foreach (var item in pairs foreach (var item in pairs
.Where(p => string.IsNullOrEmpty(_filter) || PairName(p).Contains(_filter, StringComparison.OrdinalIgnoreCase)) .Where(p => string.IsNullOrEmpty(_filter) || PairName(p).Contains(_filter, StringComparison.OrdinalIgnoreCase))
.OrderBy(p => PairName(p), StringComparer.OrdinalIgnoreCase) .OrderBy(p => PairName(p), StringComparer.OrdinalIgnoreCase)

View File

@@ -9,6 +9,8 @@ using MareSynchronos.Services.Mediator;
using MareSynchronos.Utils; using MareSynchronos.Utils;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Numerics; using System.Numerics;
using MareSynchronos.Localization;
using System.Globalization;
namespace MareSynchronos.UI; namespace MareSynchronos.UI;
@@ -33,11 +35,17 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
private ObjectKind _selectedObjectTab; private ObjectKind _selectedObjectTab;
private bool _showModal = false; private bool _showModal = false;
private string L(string key, string fallback, params object[] args)
{
var safeArgs = args ?? Array.Empty<object>();
return _uiSharedService.Localize(key, fallback, safeArgs);
}
public DataAnalysisUi(ILogger<DataAnalysisUi> logger, MareMediator mediator, public DataAnalysisUi(ILogger<DataAnalysisUi> logger, MareMediator mediator,
CharacterAnalyzer characterAnalyzer, IpcManager ipcManager, CharacterAnalyzer characterAnalyzer, IpcManager ipcManager,
PerformanceCollectorService performanceCollectorService, PerformanceCollectorService performanceCollectorService,
UiSharedService uiSharedService) UiSharedService uiSharedService)
: base(logger, mediator, "Character Data Analysis", performanceCollectorService) : base(logger, mediator, uiSharedService.Localize("DataAnalysis.WindowTitle", "Character Data Analysis"), performanceCollectorService)
{ {
_characterAnalyzer = characterAnalyzer; _characterAnalyzer = characterAnalyzer;
_ipcManager = ipcManager; _ipcManager = ipcManager;
@@ -65,14 +73,15 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
protected override void DrawInternal() protected override void DrawInternal()
{ {
var modalTitle = L("DataAnalysis.Bc7.ModalTitle", "BC7 Conversion in Progress");
if (_conversionTask != null && !_conversionTask.IsCompleted) if (_conversionTask != null && !_conversionTask.IsCompleted)
{ {
_showModal = true; _showModal = true;
if (ImGui.BeginPopupModal("BC7 Conversion in Progress")) if (ImGui.BeginPopupModal(modalTitle))
{ {
ImGui.TextUnformatted("BC7 Conversion in progress: " + _conversionCurrentFileProgress + "/" + _texturesToConvert.Count); ImGui.TextUnformatted(L("DataAnalysis.Bc7.Status", "BC7 Conversion in progress: {0}/{1}", _conversionCurrentFileProgress, _texturesToConvert.Count));
UiSharedService.TextWrapped("Current file: " + _conversionCurrentFileName); UiSharedService.TextWrapped(L("DataAnalysis.Bc7.CurrentFile", "Current file: {0}", _conversionCurrentFileName));
if (_uiSharedService.IconTextButton(FontAwesomeIcon.StopCircle, "Cancel conversion")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.StopCircle, L("DataAnalysis.Bc7.Cancel", "Cancel conversion")))
{ {
_conversionCancellationTokenSource.Cancel(); _conversionCancellationTokenSource.Cancel();
} }
@@ -95,7 +104,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
if (_showModal && !_modalOpen) if (_showModal && !_modalOpen)
{ {
ImGui.OpenPopup("BC7 Conversion in Progress"); ImGui.OpenPopup(modalTitle);
_modalOpen = true; _modalOpen = true;
} }
@@ -106,7 +115,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
_sortDirty = true; _sortDirty = true;
} }
UiSharedService.TextWrapped("This window shows you all files and their sizes that are currently in use through your character and associated entities"); UiSharedService.TextWrapped(L("DataAnalysis.Description", "This window shows you all files and their sizes that are currently in use through your character and associated entities"));
if (_cachedAnalysis == null || _cachedAnalysis.Count == 0) return; if (_cachedAnalysis == null || _cachedAnalysis.Count == 0) return;
@@ -114,9 +123,9 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
bool needAnalysis = _cachedAnalysis!.Any(c => c.Value.Any(f => !f.Value.IsComputed)); bool needAnalysis = _cachedAnalysis!.Any(c => c.Value.Any(f => !f.Value.IsComputed));
if (isAnalyzing) if (isAnalyzing)
{ {
UiSharedService.ColorTextWrapped($"Analyzing {_characterAnalyzer.CurrentFile}/{_characterAnalyzer.TotalFiles}", UiSharedService.ColorTextWrapped(L("DataAnalysis.Analyzing", "Analyzing {0}/{1}", _characterAnalyzer.CurrentFile, _characterAnalyzer.TotalFiles),
ImGuiColors.DalamudYellow); ImGuiColors.DalamudYellow);
if (_uiSharedService.IconTextButton(FontAwesomeIcon.StopCircle, "Cancel analysis")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.StopCircle, L("DataAnalysis.Button.CancelAnalysis", "Cancel analysis")))
{ {
_characterAnalyzer.CancelAnalyze(); _characterAnalyzer.CancelAnalyze();
} }
@@ -125,16 +134,16 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
{ {
if (needAnalysis) if (needAnalysis)
{ {
UiSharedService.ColorTextWrapped("Some entries in the analysis have file size not determined yet, press the button below to analyze your current data", UiSharedService.ColorTextWrapped(L("DataAnalysis.Analyze.MissingNotice", "Some entries in the analysis have file size not determined yet, press the button below to analyze your current data"),
ImGuiColors.DalamudYellow); ImGuiColors.DalamudYellow);
if (_uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Start analysis (missing entries)")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, L("DataAnalysis.Button.StartMissing", "Start analysis (missing entries)")))
{ {
_ = _characterAnalyzer.ComputeAnalysis(print: false); _ = _characterAnalyzer.ComputeAnalysis(print: false);
} }
} }
else else
{ {
if (_uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Start analysis (recalculate all entries)")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, L("DataAnalysis.Button.StartAll", "Start analysis (recalculate all entries)")))
{ {
_ = _characterAnalyzer.ComputeAnalysis(print: false, recalculate: true); _ = _characterAnalyzer.ComputeAnalysis(print: false, recalculate: true);
} }
@@ -143,7 +152,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
ImGui.Separator(); ImGui.Separator();
ImGui.TextUnformatted("Total files:"); ImGui.TextUnformatted(L("DataAnalysis.TotalFiles", "Total files:"));
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted(_cachedAnalysis!.Values.Sum(c => c.Values.Count).ToString()); ImGui.TextUnformatted(_cachedAnalysis!.Values.Sum(c => c.Values.Count).ToString());
ImGui.SameLine(); ImGui.SameLine();
@@ -153,17 +162,16 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
} }
if (ImGui.IsItemHovered()) if (ImGui.IsItemHovered())
{ {
string text = "";
var groupedfiles = _cachedAnalysis.Values.SelectMany(f => f.Values).GroupBy(f => f.FileType, StringComparer.Ordinal); var groupedfiles = _cachedAnalysis.Values.SelectMany(f => f.Values).GroupBy(f => f.FileType, StringComparer.Ordinal);
text = string.Join(Environment.NewLine, groupedfiles.OrderBy(f => f.Key, StringComparer.Ordinal) var summary = string.Join(Environment.NewLine, groupedfiles.OrderBy(f => f.Key, StringComparer.Ordinal)
.Select(f => f.Key + ": " + f.Count() + " files, size: " + UiSharedService.ByteToString(f.Sum(v => v.OriginalSize)) .Select(f => L("DataAnalysis.Tooltip.FileSummary", "{0}: {1} files, size: {2}, compressed: {3}",
+ ", compressed: " + UiSharedService.ByteToString(f.Sum(v => v.CompressedSize)))); f.Key, f.Count(), UiSharedService.ByteToString(f.Sum(v => v.OriginalSize)), UiSharedService.ByteToString(f.Sum(v => v.CompressedSize)))));
ImGui.SetTooltip(text); ImGui.SetTooltip(summary);
} }
ImGui.TextUnformatted("Total size (actual):"); ImGui.TextUnformatted(L("DataAnalysis.TotalSizeActual", "Total size (actual):"));
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted(UiSharedService.ByteToString(_cachedAnalysis!.Sum(c => c.Value.Sum(c => c.Value.OriginalSize)))); ImGui.TextUnformatted(UiSharedService.ByteToString(_cachedAnalysis!.Sum(c => c.Value.Sum(c => c.Value.OriginalSize))));
ImGui.TextUnformatted("Total size (download size):"); ImGui.TextUnformatted(L("DataAnalysis.TotalSizeDownload", "Total size (download size):"));
ImGui.SameLine(); ImGui.SameLine();
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, needAnalysis)) using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, needAnalysis))
{ {
@@ -173,10 +181,11 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
ImGui.SameLine(); ImGui.SameLine();
using (ImRaii.PushFont(UiBuilder.IconFont)) using (ImRaii.PushFont(UiBuilder.IconFont))
ImGui.TextUnformatted(FontAwesomeIcon.ExclamationCircle.ToIconString()); ImGui.TextUnformatted(FontAwesomeIcon.ExclamationCircle.ToIconString());
UiSharedService.AttachToolTip("Click \"Start analysis\" to calculate download size"); UiSharedService.AttachToolTip(L("DataAnalysis.Tooltip.CalculateDownloadSize", "Click \"Start analysis\" to calculate download size"));
} }
} }
ImGui.TextUnformatted($"Total modded model triangles: {UiSharedService.TrisToString(_cachedAnalysis.Sum(c => c.Value.Sum(f => f.Value.Triangles)))}"); ImGui.TextUnformatted(L("DataAnalysis.TotalTriangles", "Total modded model triangles: {0}",
UiSharedService.TrisToString(_cachedAnalysis.Sum(c => c.Value.Sum(f => f.Value.Triangles)))));
ImGui.Separator(); ImGui.Separator();
using var tabbar = ImRaii.TabBar("objectSelection"); using var tabbar = ImRaii.TabBar("objectSelection");
@@ -190,7 +199,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
var groupedfiles = kvp.Value.Select(v => v.Value).GroupBy(f => f.FileType, StringComparer.Ordinal) var groupedfiles = kvp.Value.Select(v => v.Value).GroupBy(f => f.FileType, StringComparer.Ordinal)
.OrderBy(k => k.Key, StringComparer.Ordinal).ToList(); .OrderBy(k => k.Key, StringComparer.Ordinal).ToList();
ImGui.TextUnformatted("Files for " + kvp.Key); ImGui.TextUnformatted(L("DataAnalysis.FilesFor", "Files for {0}", kvp.Key));
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted(kvp.Value.Count.ToString()); ImGui.TextUnformatted(kvp.Value.Count.ToString());
ImGui.SameLine(); ImGui.SameLine();
@@ -201,16 +210,15 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
} }
if (ImGui.IsItemHovered()) if (ImGui.IsItemHovered())
{ {
string text = ""; var summary = string.Join(Environment.NewLine, groupedfiles
text = string.Join(Environment.NewLine, groupedfiles .Select(f => L("DataAnalysis.Tooltip.FileSummary", "{0}: {1} files, size: {2}, compressed: {3}",
.Select(f => f.Key + ": " + f.Count() + " files, size: " + UiSharedService.ByteToString(f.Sum(v => v.OriginalSize)) f.Key, f.Count(), UiSharedService.ByteToString(f.Sum(v => v.OriginalSize)), UiSharedService.ByteToString(f.Sum(v => v.CompressedSize)))));
+ ", compressed: " + UiSharedService.ByteToString(f.Sum(v => v.CompressedSize)))); ImGui.SetTooltip(summary);
ImGui.SetTooltip(text);
} }
ImGui.TextUnformatted($"{kvp.Key} size (actual):"); ImGui.TextUnformatted(L("DataAnalysis.Object.SizeActual", "{0} size (actual):", kvp.Key));
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted(UiSharedService.ByteToString(kvp.Value.Sum(c => c.Value.OriginalSize))); ImGui.TextUnformatted(UiSharedService.ByteToString(kvp.Value.Sum(c => c.Value.OriginalSize)));
ImGui.TextUnformatted($"{kvp.Key} size (download size):"); ImGui.TextUnformatted(L("DataAnalysis.Object.SizeDownload", "{0} size (download size):", kvp.Key));
ImGui.SameLine(); ImGui.SameLine();
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, needAnalysis)) using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, needAnalysis))
{ {
@@ -220,17 +228,18 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
ImGui.SameLine(); ImGui.SameLine();
using (ImRaii.PushFont(UiBuilder.IconFont)) using (ImRaii.PushFont(UiBuilder.IconFont))
ImGui.TextUnformatted(FontAwesomeIcon.ExclamationCircle.ToIconString()); ImGui.TextUnformatted(FontAwesomeIcon.ExclamationCircle.ToIconString());
UiSharedService.AttachToolTip("Click \"Start analysis\" to calculate download size"); UiSharedService.AttachToolTip(L("DataAnalysis.Tooltip.CalculateDownloadSize", "Click \"Start analysis\" to calculate download size"));
} }
} }
ImGui.TextUnformatted($"{kvp.Key} VRAM usage:"); ImGui.TextUnformatted(L("DataAnalysis.Object.Vram", "{0} VRAM usage:", kvp.Key));
ImGui.SameLine(); ImGui.SameLine();
var vramUsage = groupedfiles.SingleOrDefault(v => string.Equals(v.Key, "tex", StringComparison.Ordinal)); var vramUsage = groupedfiles.SingleOrDefault(v => string.Equals(v.Key, "tex", StringComparison.Ordinal));
if (vramUsage != null) if (vramUsage != null)
{ {
ImGui.TextUnformatted(UiSharedService.ByteToString(vramUsage.Sum(f => f.OriginalSize))); ImGui.TextUnformatted(UiSharedService.ByteToString(vramUsage.Sum(f => f.OriginalSize)));
} }
ImGui.TextUnformatted($"{kvp.Key} modded model triangles: {UiSharedService.TrisToString(kvp.Value.Sum(f => f.Value.Triangles))}"); ImGui.TextUnformatted(L("DataAnalysis.Object.Triangles", "{0} modded model triangles: {1}", kvp.Key,
UiSharedService.TrisToString(kvp.Value.Sum(f => f.Value.Triangles))));
ImGui.Separator(); ImGui.Separator();
if (_selectedObjectTab != kvp.Key) if (_selectedObjectTab != kvp.Key)
@@ -266,33 +275,35 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
_texturesToConvert.Clear(); _texturesToConvert.Clear();
} }
ImGui.TextUnformatted($"{fileGroup.Key} files"); ImGui.TextUnformatted(L("DataAnalysis.FileGroup.Count", "{0} files", fileGroup.Key));
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted(fileGroup.Count().ToString()); ImGui.TextUnformatted(fileGroup.Count().ToString());
ImGui.TextUnformatted($"{fileGroup.Key} files size (actual):"); ImGui.TextUnformatted(L("DataAnalysis.FileGroup.SizeActual", "{0} files size (actual):", fileGroup.Key));
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted(UiSharedService.ByteToString(fileGroup.Sum(c => c.OriginalSize))); ImGui.TextUnformatted(UiSharedService.ByteToString(fileGroup.Sum(c => c.OriginalSize)));
ImGui.TextUnformatted($"{fileGroup.Key} files size (download size):"); ImGui.TextUnformatted(L("DataAnalysis.FileGroup.SizeDownload", "{0} files size (download size):", fileGroup.Key));
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted(UiSharedService.ByteToString(fileGroup.Sum(c => c.CompressedSize))); ImGui.TextUnformatted(UiSharedService.ByteToString(fileGroup.Sum(c => c.CompressedSize)));
if (string.Equals(_selectedFileTypeTab, "tex", StringComparison.Ordinal)) if (string.Equals(_selectedFileTypeTab, "tex", StringComparison.Ordinal))
{ {
ImGui.Checkbox("Enable BC7 Conversion Mode", ref _enableBc7ConversionMode); ImGui.Checkbox(L("DataAnalysis.Bc7.EnableMode", "Enable BC7 Conversion Mode"), ref _enableBc7ConversionMode);
if (_enableBc7ConversionMode) if (_enableBc7ConversionMode)
{ {
UiSharedService.ColorText("WARNING BC7 CONVERSION:", ImGuiColors.DalamudYellow); UiSharedService.ColorText(L("DataAnalysis.Bc7.WarningTitle", "WARNING BC7 CONVERSION:"), ImGuiColors.DalamudYellow);
ImGui.SameLine(); ImGui.SameLine();
UiSharedService.ColorText("Converting textures to BC7 is irreversible!", ImGuiColors.DalamudRed); UiSharedService.ColorText(L("DataAnalysis.Bc7.WarningIrreversible", "Converting textures to BC7 is irreversible!"), ImGuiColors.DalamudRed);
UiSharedService.ColorTextWrapped("- Converting textures to BC7 will reduce their size (compressed and uncompressed) drastically. It is recommended to be used for large (4k+) textures." + UiSharedService.ColorTextWrapped(L("DataAnalysis.Bc7.WarningDetails",
Environment.NewLine + "- Some textures, especially ones utilizing colorsets, might not be suited for BC7 conversion and might produce visual artifacts." + "- Converting textures to BC7 will reduce their size (compressed and uncompressed) drastically. It is recommended to be used for large (4k+) textures.\n"
Environment.NewLine + "- Before converting textures, make sure to have the original files of the mod you are converting so you can reimport it in case of issues." + + "- Some textures, especially ones utilizing colorsets, might not be suited for BC7 conversion and might produce visual artifacts.\n"
Environment.NewLine + "- Conversion will convert all found texture duplicates (entries with more than 1 file path) automatically." + + "- Before converting textures, make sure to have the original files of the mod you are converting so you can reimport it in case of issues.\n"
Environment.NewLine + "- Converting textures to BC7 is a very expensive operation and, depending on the amount of textures to convert, will take a while to complete." + "- Conversion will convert all found texture duplicates (entries with more than 1 file path) automatically.\n"
, ImGuiColors.DalamudYellow); + "- Converting textures to BC7 is a very expensive operation and, depending on the amount of textures to convert, will take a while to complete."),
if (_texturesToConvert.Count > 0 && _uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Start conversion of " + _texturesToConvert.Count + " texture(s)")) ImGuiColors.DalamudYellow);
if (_texturesToConvert.Count > 0 && _uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle,
L("DataAnalysis.Bc7.StartConversion", "Start conversion of {0} texture(s)", _texturesToConvert.Count)))
{ {
_conversionCancellationTokenSource = _conversionCancellationTokenSource.CancelRecreate(); _conversionCancellationTokenSource = _conversionCancellationTokenSource.CancelRecreate();
_conversionTask = _ipcManager.Penumbra.ConvertTextureFiles(_logger, _texturesToConvert, _conversionProgress, _conversionCancellationTokenSource.Token); _conversionTask = _ipcManager.Penumbra.ConvertTextureFiles(_logger, _texturesToConvert, _conversionProgress, _conversionCancellationTokenSource.Token);
@@ -310,33 +321,33 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
ImGui.Separator(); ImGui.Separator();
ImGui.TextUnformatted("Selected file:"); ImGui.TextUnformatted(L("DataAnalysis.SelectedFile", "Selected file:"));
ImGui.SameLine(); ImGui.SameLine();
UiSharedService.ColorText(_selectedHash, ImGuiColors.DalamudYellow); UiSharedService.ColorText(_selectedHash, ImGuiColors.DalamudYellow);
if (_cachedAnalysis[_selectedObjectTab].TryGetValue(_selectedHash, out CharacterAnalyzer.FileDataEntry? item)) if (_cachedAnalysis[_selectedObjectTab].TryGetValue(_selectedHash, out CharacterAnalyzer.FileDataEntry? item))
{ {
var filePaths = item.FilePaths; var filePaths = item.FilePaths;
ImGui.TextUnformatted("Local file path:"); ImGui.TextUnformatted(L("DataAnalysis.LocalFilePath", "Local file path:"));
ImGui.SameLine(); ImGui.SameLine();
UiSharedService.TextWrapped(filePaths[0]); UiSharedService.TextWrapped(filePaths[0]);
if (filePaths.Count > 1) if (filePaths.Count > 1)
{ {
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted($"(and {filePaths.Count - 1} more)"); ImGui.TextUnformatted(L("DataAnalysis.MoreCount", "(and {0} more)", filePaths.Count - 1));
ImGui.SameLine(); ImGui.SameLine();
_uiSharedService.IconText(FontAwesomeIcon.InfoCircle); _uiSharedService.IconText(FontAwesomeIcon.InfoCircle);
UiSharedService.AttachToolTip(string.Join(Environment.NewLine, filePaths.Skip(1))); UiSharedService.AttachToolTip(string.Join(Environment.NewLine, filePaths.Skip(1)));
} }
var gamepaths = item.GamePaths; var gamepaths = item.GamePaths;
ImGui.TextUnformatted("Used by game path:"); ImGui.TextUnformatted(L("DataAnalysis.GamePath", "Used by game path:"));
ImGui.SameLine(); ImGui.SameLine();
UiSharedService.TextWrapped(gamepaths[0]); UiSharedService.TextWrapped(gamepaths[0]);
if (gamepaths.Count > 1) if (gamepaths.Count > 1)
{ {
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted($"(and {gamepaths.Count - 1} more)"); ImGui.TextUnformatted(L("DataAnalysis.MoreCount", "(and {0} more)", gamepaths.Count - 1));
ImGui.SameLine(); ImGui.SameLine();
_uiSharedService.IconText(FontAwesomeIcon.InfoCircle); _uiSharedService.IconText(FontAwesomeIcon.InfoCircle);
UiSharedService.AttachToolTip(string.Join(Environment.NewLine, gamepaths.Skip(1))); UiSharedService.AttachToolTip(string.Join(Environment.NewLine, gamepaths.Skip(1)));
@@ -372,19 +383,19 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
using var table = ImRaii.Table("Analysis", tableColumns, ImGuiTableFlags.Sortable | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit, using var table = ImRaii.Table("Analysis", tableColumns, ImGuiTableFlags.Sortable | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit,
new Vector2(0, 300)); new Vector2(0, 300));
if (!table.Success) return; if (!table.Success) return;
ImGui.TableSetupColumn("Hash"); ImGui.TableSetupColumn(L("DataAnalysis.Table.Hash", "Hash"));
ImGui.TableSetupColumn("Filepaths", ImGuiTableColumnFlags.PreferSortDescending); ImGui.TableSetupColumn(L("DataAnalysis.Table.Filepaths", "Filepaths"), ImGuiTableColumnFlags.PreferSortDescending);
ImGui.TableSetupColumn("Gamepaths", ImGuiTableColumnFlags.PreferSortDescending); ImGui.TableSetupColumn(L("DataAnalysis.Table.Gamepaths", "Gamepaths"), ImGuiTableColumnFlags.PreferSortDescending);
ImGui.TableSetupColumn("File Size", ImGuiTableColumnFlags.DefaultSort | ImGuiTableColumnFlags.PreferSortDescending); ImGui.TableSetupColumn(L("DataAnalysis.Table.FileSize", "File Size"), ImGuiTableColumnFlags.DefaultSort | ImGuiTableColumnFlags.PreferSortDescending);
ImGui.TableSetupColumn("Download Size", ImGuiTableColumnFlags.PreferSortDescending); ImGui.TableSetupColumn(L("DataAnalysis.Table.DownloadSize", "Download Size"), ImGuiTableColumnFlags.PreferSortDescending);
if (string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal)) if (string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal))
{ {
ImGui.TableSetupColumn("Format"); ImGui.TableSetupColumn(L("DataAnalysis.Table.Format", "Format"));
if (_enableBc7ConversionMode) ImGui.TableSetupColumn("Convert to BC7"); if (_enableBc7ConversionMode) ImGui.TableSetupColumn(L("DataAnalysis.Table.ConvertToBc7", "Convert to BC7"));
} }
if (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal)) if (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal))
{ {
ImGui.TableSetupColumn("Triangles", ImGuiTableColumnFlags.PreferSortDescending); ImGui.TableSetupColumn(L("DataAnalysis.Table.Triangles", "Triangles"), ImGuiTableColumnFlags.PreferSortDescending);
} }
ImGui.TableSetupScrollFreeze(0, 1); ImGui.TableSetupScrollFreeze(0, 1);
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();

View File

@@ -23,7 +23,7 @@ public class DownloadUi : WindowMediatorSubscriberBase
public DownloadUi(ILogger<DownloadUi> logger, DalamudUtilService dalamudUtilService, MareConfigService configService, public DownloadUi(ILogger<DownloadUi> logger, DalamudUtilService dalamudUtilService, MareConfigService configService,
FileUploadManager fileTransferManager, MareMediator mediator, UiSharedService uiShared, PerformanceCollectorService performanceCollectorService) FileUploadManager fileTransferManager, MareMediator mediator, UiSharedService uiShared, PerformanceCollectorService performanceCollectorService)
: base(logger, mediator, "Umbra Downloads", performanceCollectorService) : base(logger, mediator, uiShared.Localize("DownloadUi.WindowTitle", "Umbra Downloads"), performanceCollectorService)
{ {
_dalamudUtilService = dalamudUtilService; _dalamudUtilService = dalamudUtilService;
_configService = configService; _configService = configService;
@@ -69,6 +69,8 @@ public class DownloadUi : WindowMediatorSubscriberBase
}); });
} }
private string L(string key, string fallback, params object[] args) => _uiShared.Localize(key, fallback, args);
protected override void DrawInternal() protected override void DrawInternal()
{ {
if (_configService.Current.ShowTransferWindow) if (_configService.Current.ShowTransferWindow)
@@ -87,7 +89,7 @@ public class DownloadUi : WindowMediatorSubscriberBase
UiSharedService.DrawOutlinedFont($"▲", ImGuiColors.DalamudWhite, new Vector4(0, 0, 0, 255), 1); UiSharedService.DrawOutlinedFont($"▲", ImGuiColors.DalamudWhite, new Vector4(0, 0, 0, 255), 1);
ImGui.SameLine(); ImGui.SameLine();
var xDistance = ImGui.GetCursorPosX(); var xDistance = ImGui.GetCursorPosX();
UiSharedService.DrawOutlinedFont($"Compressing+Uploading {doneUploads}/{totalUploads}", UiSharedService.DrawOutlinedFont(L("DownloadUi.UploadStatus", "Compressing+Uploading {0}/{1}", doneUploads, totalUploads),
ImGuiColors.DalamudWhite, new Vector4(0, 0, 0, 255), 1); ImGuiColors.DalamudWhite, new Vector4(0, 0, 0, 255), 1);
ImGui.NewLine(); ImGui.NewLine();
ImGui.SameLine(xDistance); ImGui.SameLine(xDistance);
@@ -120,7 +122,7 @@ public class DownloadUi : WindowMediatorSubscriberBase
ImGui.SameLine(); ImGui.SameLine();
var xDistance = ImGui.GetCursorPosX(); var xDistance = ImGui.GetCursorPosX();
UiSharedService.DrawOutlinedFont( UiSharedService.DrawOutlinedFont(
$"{item.Key.Name} [W:{dlSlot}/Q:{dlQueue}/P:{dlProg}/D:{dlDecomp}]", L("DownloadUi.DownloadStatus", "{0} [W:{1}/Q:{2}/P:{3}/D:{4}]", item.Key.Name, dlSlot, dlQueue, dlProg, dlDecomp),
ImGuiColors.DalamudWhite, new Vector4(0, 0, 0, 255), 1); ImGuiColors.DalamudWhite, new Vector4(0, 0, 0, 255), 1);
ImGui.NewLine(); ImGui.NewLine();
ImGui.SameLine(xDistance); ImGui.SameLine(xDistance);
@@ -191,7 +193,7 @@ public class DownloadUi : WindowMediatorSubscriberBase
try try
{ {
using var _ = _uiShared.UidFont.Push(); using var _ = _uiShared.UidFont.Push();
var uploadText = "Uploading"; var uploadText = L("DownloadUi.UploadingLabel", "Uploading");
var textSize = ImGui.CalcTextSize(uploadText); var textSize = ImGui.CalcTextSize(uploadText);

View File

@@ -11,6 +11,8 @@ using MareSynchronos.WebAPI;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using MareSynchronos.Localization;
using System.Globalization;
namespace MareSynchronos.UI; namespace MareSynchronos.UI;
@@ -46,6 +48,13 @@ public sealed class DtrEntry : IDisposable, IHostedService
private string? _tooltip; private string? _tooltip;
private Colors _colors; private Colors _colors;
private static string L(string key, string fallback, params object[] args)
{
var safeArgs = args ?? Array.Empty<object>();
return LocalizationService.Instance?.GetString(key, fallback, safeArgs)
?? string.Format(CultureInfo.CurrentCulture, fallback, safeArgs);
}
public DtrEntry(ILogger<DtrEntry> logger, IDtrBar dtrBar, MareConfigService configService, MareMediator mareMediator, PairManager pairManager, ApiController apiController) public DtrEntry(ILogger<DtrEntry> logger, IDtrBar dtrBar, MareConfigService configService, MareMediator mareMediator, PairManager pairManager, ApiController apiController)
{ {
_logger = logger; _logger = logger;
@@ -106,7 +115,7 @@ public sealed class DtrEntry : IDisposable, IHostedService
private IDtrBarEntry CreateEntry() private IDtrBarEntry CreateEntry()
{ {
_logger.LogTrace("Creating new DtrBar entry"); _logger.LogTrace("Creating new DtrBar entry");
var entry = _dtrBar.Get("Umbra"); var entry = _dtrBar.Get(L("DtrEntry.EntryName", "Umbra"));
entry.OnClick = _ => _mareMediator.Publish(new UiToggleMessage(typeof(CompactUi))); entry.OnClick = _ => _mareMediator.Publish(new UiToggleMessage(typeof(CompactUi)));
return entry; return entry;
@@ -165,19 +174,20 @@ public sealed class DtrEntry : IDisposable, IHostedService
.Select(x => string.Format("{0}", _configService.Current.PreferNoteInDtrTooltip ? x.GetNoteOrName() : x.PlayerName)); .Select(x => string.Format("{0}", _configService.Current.PreferNoteInDtrTooltip ? x.GetNoteOrName() : x.PlayerName));
} }
tooltip = $"Umbra: Connected{Environment.NewLine}----------{Environment.NewLine}{string.Join(Environment.NewLine, visiblePairs)}"; var header = L("DtrEntry.Tooltip.Connected", "Umbra: Connected");
tooltip = header + Environment.NewLine + "----------" + Environment.NewLine + string.Join(Environment.NewLine, visiblePairs);
colors = _configService.Current.DtrColorsPairsInRange; colors = _configService.Current.DtrColorsPairsInRange;
} }
else else
{ {
tooltip = "Umbra: Connected"; tooltip = L("DtrEntry.Tooltip.Connected", "Umbra: Connected");
colors = _configService.Current.DtrColorsDefault; colors = _configService.Current.DtrColorsDefault;
} }
} }
else else
{ {
text = RenderDtrStyle(_configService.Current.DtrStyle, "\uE04C"); text = RenderDtrStyle(_configService.Current.DtrStyle, "\uE04C");
tooltip = "Umbra: Not Connected"; tooltip = L("DtrEntry.Tooltip.Disconnected", "Umbra: Not Connected");
colors = _configService.Current.DtrColorsNotConnected; colors = _configService.Current.DtrColorsNotConnected;
} }

View File

@@ -35,7 +35,7 @@ public class EditProfileUi : WindowMediatorSubscriberBase
ApiController apiController, UiSharedService uiSharedService, FileDialogManager fileDialogManager, ApiController apiController, UiSharedService uiSharedService, FileDialogManager fileDialogManager,
ServerConfigurationManager serverConfigurationManager, ServerConfigurationManager serverConfigurationManager,
MareProfileManager mareProfileManager, PerformanceCollectorService performanceCollectorService) MareProfileManager mareProfileManager, PerformanceCollectorService performanceCollectorService)
: base(logger, mediator, "Umbra Edit Profile###UmbraSyncEditProfileUI", performanceCollectorService) : base(logger, mediator, uiSharedService.Localize("EditProfile.WindowTitle", "Umbra Edit Profile") + "###UmbraSyncEditProfileUI", performanceCollectorService)
{ {
IsOpen = false; IsOpen = false;
this.SizeConstraints = new() this.SizeConstraints = new()
@@ -62,9 +62,11 @@ public class EditProfileUi : WindowMediatorSubscriberBase
}); });
} }
private string L(string key, string fallback, params object[] args) => _uiSharedService.Localize(key, fallback, args);
protected override void DrawInternal() protected override void DrawInternal()
{ {
_uiSharedService.BigText("Current Profile (as saved on server)"); _uiSharedService.BigText(L("EditProfile.CurrentProfile", "Current Profile (as saved on server)"));
var profile = _mareProfileManager.GetMareProfile(new UserData(_apiController.UID)); var profile = _mareProfileManager.GetMareProfile(new UserData(_apiController.UID));
@@ -125,9 +127,9 @@ public class EditProfileUi : WindowMediatorSubscriberBase
ImGui.Separator(); ImGui.Separator();
_uiSharedService.BigText("Profile Settings"); _uiSharedService.BigText("Profile Settings");
if (_uiSharedService.IconTextButton(FontAwesomeIcon.FileUpload, "Upload new profile picture")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.FileUpload, L("EditProfile.Button.UploadPicture", "Upload new profile picture")))
{ {
_fileDialogManager.OpenFileDialog("Select new Profile picture", ".png", (success, file) => _fileDialogManager.OpenFileDialog(L("EditProfile.Dialog.PictureTitle", "Select new Profile picture"), ".png", (success, file) =>
{ {
if (!success) return; if (!success) return;
_ = Task.Run(async () => _ = Task.Run(async () =>
@@ -148,29 +150,29 @@ public class EditProfileUi : WindowMediatorSubscriberBase
}); });
}); });
} }
UiSharedService.AttachToolTip("Select and upload a new profile picture"); UiSharedService.AttachToolTip(L("EditProfile.Tooltip.UploadPicture", "Select and upload a new profile picture"));
ImGui.SameLine(); ImGui.SameLine();
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear uploaded profile picture")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, L("EditProfile.Button.ClearPicture", "Clear uploaded profile picture")))
{ {
_ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, "", Description: null)); _ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, "", Description: null));
} }
UiSharedService.AttachToolTip("Clear your currently uploaded profile picture"); UiSharedService.AttachToolTip(L("EditProfile.Tooltip.ClearPicture", "Clear your currently uploaded profile picture"));
if (_showFileDialogError) 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); UiSharedService.ColorTextWrapped(L("EditProfile.Error.PictureTooLarge", "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; var isNsfw = profile.IsNSFW;
if (ImGui.Checkbox("Profile is NSFW", ref isNsfw)) if (ImGui.Checkbox(L("EditProfile.Checkbox.Nsfw", "Profile is NSFW"), ref isNsfw))
{ {
_ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, isNsfw, ProfilePictureBase64: null, Description: null)); _ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, isNsfw, ProfilePictureBase64: null, Description: null));
} }
_uiSharedService.DrawHelpText("If your profile description or image can be considered NSFW, toggle this to ON"); _uiSharedService.DrawHelpText(L("EditProfile.Help.Nsfw", "If your profile description or image can be considered NSFW, toggle this to ON"));
var widthTextBox = 400; var widthTextBox = 400;
var posX = ImGui.GetCursorPosX(); var posX = ImGui.GetCursorPosX();
ImGui.TextUnformatted($"Description {_descriptionText.Length}/1500"); ImGui.TextUnformatted(L("EditProfile.DescriptionCounter", "Description {0}/1500", _descriptionText.Length));
ImGui.SetCursorPosX(posX); ImGui.SetCursorPosX(posX);
ImGuiHelpers.ScaledRelativeSameLine(widthTextBox, ImGui.GetStyle().ItemSpacing.X); ImGuiHelpers.ScaledRelativeSameLine(widthTextBox, ImGui.GetStyle().ItemSpacing.X);
ImGui.TextUnformatted("Preview (approximate)"); ImGui.TextUnformatted(L("EditProfile.PreviewLabel", "Preview (approximate)"));
using (_uiSharedService.GameFont.Push()) using (_uiSharedService.GameFont.Push())
ImGui.InputTextMultiline("##description", ref _descriptionText, 1500, ImGuiHelpers.ScaledVector2(widthTextBox, 200)); ImGui.InputTextMultiline("##description", ref _descriptionText, 1500, ImGuiHelpers.ScaledVector2(widthTextBox, 200));
@@ -199,17 +201,17 @@ public class EditProfileUi : WindowMediatorSubscriberBase
ImGui.EndChildFrame(); ImGui.EndChildFrame();
} }
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, "Save Description")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, L("EditProfile.Button.SaveDescription", "Save Description")))
{ {
_ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, ProfilePictureBase64: null, _descriptionText)); _ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, ProfilePictureBase64: null, _descriptionText));
} }
UiSharedService.AttachToolTip("Sets your profile description text"); UiSharedService.AttachToolTip(L("EditProfile.Tooltip.SaveDescription", "Sets your profile description text"));
ImGui.SameLine(); ImGui.SameLine();
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear Description")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, L("EditProfile.Button.ClearDescription", "Clear Description")))
{ {
_ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, ProfilePictureBase64: null, "")); _ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, ProfilePictureBase64: null, ""));
} }
UiSharedService.AttachToolTip("Clears your profile description text"); UiSharedService.AttachToolTip(L("EditProfile.Tooltip.ClearDescription", "Clears your profile description text"));
} }
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)

View File

@@ -40,7 +40,7 @@ internal class EventViewerUI : WindowMediatorSubscriberBase
public EventViewerUI(ILogger<EventViewerUI> logger, MareMediator mediator, public EventViewerUI(ILogger<EventViewerUI> logger, MareMediator mediator,
EventAggregator eventAggregator, UiSharedService uiSharedService, MareConfigService configService, EventAggregator eventAggregator, UiSharedService uiSharedService, MareConfigService configService,
PerformanceCollectorService performanceCollectorService) PerformanceCollectorService performanceCollectorService)
: base(logger, mediator, "Event Viewer", performanceCollectorService) : base(logger, mediator, uiSharedService.Localize("EventViewer.WindowTitle", "Event Viewer"), performanceCollectorService)
{ {
_eventAggregator = eventAggregator; _eventAggregator = eventAggregator;
_uiSharedService = uiSharedService; _uiSharedService = uiSharedService;
@@ -52,6 +52,8 @@ internal class EventViewerUI : WindowMediatorSubscriberBase
_filteredEvents = RecreateFilter(); _filteredEvents = RecreateFilter();
} }
private string L(string key, string fallback, params object[] args) => _uiSharedService.Localize(key, fallback, args);
private Lazy<List<Event>> RecreateFilter() private Lazy<List<Event>> RecreateFilter()
{ {
return new(() => return new(() =>
@@ -81,20 +83,22 @@ internal class EventViewerUI : WindowMediatorSubscriberBase
{ {
var newEventsAvailable = _eventAggregator.NewEventsAvailable; var newEventsAvailable = _eventAggregator.NewEventsAvailable;
var freezeSize = _uiSharedService.GetIconTextButtonSize(FontAwesomeIcon.PlayCircle, "Unfreeze View"); var unfreezeLabel = L("EventViewer.Button.Unfreeze", "Unfreeze View");
var freezeLabel = L("EventViewer.Button.Freeze", "Freeze View");
var freezeSize = _uiSharedService.GetIconTextButtonSize(FontAwesomeIcon.PlayCircle, unfreezeLabel);
if (_isPaused) if (_isPaused)
{ {
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, newEventsAvailable)) using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, newEventsAvailable))
{ {
if (_uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Unfreeze View")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, unfreezeLabel))
_isPaused = false; _isPaused = false;
if (newEventsAvailable) if (newEventsAvailable)
UiSharedService.AttachToolTip("New events are available. Click to resume updating."); UiSharedService.AttachToolTip(L("EventViewer.Tooltip.NewEvents", "New events are available. Click to resume updating."));
} }
} }
else else
{ {
if (_uiSharedService.IconTextButton(FontAwesomeIcon.PauseCircle, "Freeze View")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.PauseCircle, freezeLabel))
_isPaused = true; _isPaused = true;
} }
@@ -105,7 +109,7 @@ internal class EventViewerUI : WindowMediatorSubscriberBase
bool changedFilter = false; bool changedFilter = false;
ImGui.SetNextItemWidth(200); ImGui.SetNextItemWidth(200);
changedFilter |= ImGui.InputText("Filter lines", ref _filterFreeText, 50); changedFilter |= ImGui.InputText(L("EventViewer.FilterLabel", "Filter lines"), ref _filterFreeText, 50);
if (changedFilter) _filteredEvents = RecreateFilter(); if (changedFilter) _filteredEvents = RecreateFilter();
using (ImRaii.Disabled(_filterFreeText.IsNullOrEmpty())) using (ImRaii.Disabled(_filterFreeText.IsNullOrEmpty()))
@@ -120,10 +124,11 @@ internal class EventViewerUI : WindowMediatorSubscriberBase
if (_configService.Current.LogEvents) if (_configService.Current.LogEvents)
{ {
var buttonSize = _uiSharedService.GetIconTextButtonSize(FontAwesomeIcon.FolderOpen, "Open EventLog Folder"); var openLogLabel = L("EventViewer.Button.OpenLog", "Open EventLog folder");
var buttonSize = _uiSharedService.GetIconTextButtonSize(FontAwesomeIcon.FolderOpen, openLogLabel);
var dist = ImGui.GetWindowContentRegionMax().X - buttonSize; var dist = ImGui.GetWindowContentRegionMax().X - buttonSize;
ImGui.SameLine(dist); ImGui.SameLine(dist);
if (_uiSharedService.IconTextButton(FontAwesomeIcon.FolderOpen, "Open EventLog folder")) if (_uiSharedService.IconTextButton(FontAwesomeIcon.FolderOpen, openLogLabel))
{ {
ProcessStartInfo ps = new() ProcessStartInfo ps = new()
{ {
@@ -152,11 +157,11 @@ internal class EventViewerUI : WindowMediatorSubscriberBase
{ {
ImGui.TableSetupScrollFreeze(0, 1); ImGui.TableSetupScrollFreeze(0, 1);
ImGui.TableSetupColumn(string.Empty, ImGuiTableColumnFlags.NoSort); ImGui.TableSetupColumn(string.Empty, ImGuiTableColumnFlags.NoSort);
ImGui.TableSetupColumn("Time", ImGuiTableColumnFlags.None, timeColWidth); ImGui.TableSetupColumn(L("EventViewer.Column.Time", "Time"), ImGuiTableColumnFlags.None, timeColWidth);
ImGui.TableSetupColumn("Source", ImGuiTableColumnFlags.None, sourceColWidth); ImGui.TableSetupColumn(L("EventViewer.Column.Source", "Source"), ImGuiTableColumnFlags.None, sourceColWidth);
ImGui.TableSetupColumn("UID", ImGuiTableColumnFlags.None, uidColWidth); ImGui.TableSetupColumn(L("EventViewer.Column.Uid", "UID"), ImGuiTableColumnFlags.None, uidColWidth);
ImGui.TableSetupColumn("Character", ImGuiTableColumnFlags.None, characterColWidth); ImGui.TableSetupColumn(L("EventViewer.Column.Character", "Character"), ImGuiTableColumnFlags.None, characterColWidth);
ImGui.TableSetupColumn("Event", ImGuiTableColumnFlags.None); ImGui.TableSetupColumn(L("EventViewer.Column.Event", "Event"), ImGuiTableColumnFlags.None);
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
int i = 0; int i = 0;
foreach (var ev in _filteredEvents.Value) foreach (var ev in _filteredEvents.Value)
@@ -181,7 +186,7 @@ internal class EventViewerUI : WindowMediatorSubscriberBase
ImGui.TableNextColumn(); ImGui.TableNextColumn();
_uiSharedService.IconText(icon, iconColor == new Vector4() ? null : iconColor); _uiSharedService.IconText(icon, iconColor == new Vector4() ? null : iconColor);
UiSharedService.AttachToolTip(ev.EventSeverity.ToString()); UiSharedService.AttachToolTip(L($"EventViewer.Severity.{ev.EventSeverity}", ev.EventSeverity.ToString()));
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(ev.EventTime.ToString("T", CultureInfo.CurrentCulture)); ImGui.TextUnformatted(ev.EventTime.ToString("T", CultureInfo.CurrentCulture));
@@ -200,7 +205,7 @@ internal class EventViewerUI : WindowMediatorSubscriberBase
} }
else else
{ {
ImGui.TextUnformatted("--"); ImGui.TextUnformatted(L("EventViewer.NoValue", "--"));
} }
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
@@ -214,7 +219,7 @@ internal class EventViewerUI : WindowMediatorSubscriberBase
} }
else else
{ {
ImGui.TextUnformatted("--"); ImGui.TextUnformatted(L("EventViewer.NoValue", "--"));
} }
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();

View File

@@ -1,11 +1,13 @@
using Dalamud.Bindings.ImGui; using Dalamud.Bindings.ImGui;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Utility.Raii;
using MareSynchronos.Localization;
using MareSynchronos.MareConfiguration; using MareSynchronos.MareConfiguration;
using MareSynchronos.PlayerData.Pairs; using MareSynchronos.PlayerData.Pairs;
using MareSynchronos.Services.Mediator; using MareSynchronos.Services.Mediator;
using MareSynchronos.Services.ServerConfiguration; using MareSynchronos.Services.ServerConfiguration;
using MareSynchronos.UI.Components; using MareSynchronos.UI.Components;
using System.Globalization;
namespace MareSynchronos.UI.Handlers; namespace MareSynchronos.UI.Handlers;
@@ -22,6 +24,13 @@ public class UidDisplayHandler
private bool _popupShown = false; private bool _popupShown = false;
private DateTime? _popupTime; private DateTime? _popupTime;
private static string L(string key, string fallback, params object[] args)
{
var safeArgs = args ?? Array.Empty<object>();
return LocalizationService.Instance?.GetString(key, fallback, safeArgs)
?? string.Format(CultureInfo.CurrentCulture, fallback, safeArgs);
}
public UidDisplayHandler(MareMediator mediator, PairManager pairManager, public UidDisplayHandler(MareMediator mediator, PairManager pairManager,
ServerConfigurationManager serverManager, MareConfigService mareConfigService) ServerConfigurationManager serverManager, MareConfigService mareConfigService)
{ {
@@ -77,9 +86,7 @@ public class UidDisplayHandler
if (_popupTime > DateTime.UtcNow || !_mareConfigService.Current.ProfilesShow) if (_popupTime > DateTime.UtcNow || !_mareConfigService.Current.ProfilesShow)
{ {
ImGui.SetTooltip("Left click to switch between UID display and nick" + Environment.NewLine ImGui.SetTooltip(L("UidDisplay.Tooltip", "Left click to switch between UID display and nick\nRight click to change nick for {0}\nMiddle Mouse Button to open their profile in a separate window", pair.UserData.AliasOrUID));
+ "Right click to change nick for " + pair.UserData.AliasOrUID + Environment.NewLine
+ "Middle Mouse Button to open their profile in a separate window");
} }
else if (_popupTime < DateTime.UtcNow && !_popupShown) else if (_popupTime < DateTime.UtcNow && !_popupShown)
{ {
@@ -125,7 +132,7 @@ public class UidDisplayHandler
ImGui.SetCursorPosY(originalY); ImGui.SetCursorPosY(originalY);
ImGui.SetNextItemWidth(editBoxWidth.Invoke()); ImGui.SetNextItemWidth(editBoxWidth.Invoke());
if (ImGui.InputTextWithHint("##" + pair.UserData.UID, "Nick/Notes", ref _editUserComment, 255, ImGuiInputTextFlags.EnterReturnsTrue)) if (ImGui.InputTextWithHint("##" + pair.UserData.UID, L("UidDisplay.EditNotes.Hint", "Nick/Notes"), ref _editUserComment, 255, ImGuiInputTextFlags.EnterReturnsTrue))
{ {
_serverManager.SetNoteForUid(pair.UserData.UID, _editUserComment); _serverManager.SetNoteForUid(pair.UserData.UID, _editUserComment);
_serverManager.SaveNotes(); _serverManager.SaveNotes();
@@ -136,7 +143,7 @@ public class UidDisplayHandler
{ {
_editNickEntry = string.Empty; _editNickEntry = string.Empty;
} }
UiSharedService.AttachToolTip("Hit ENTER to save\nRight click to cancel"); UiSharedService.AttachToolTip(L("GroupPanel.CommentTooltip", "Hit ENTER to save\nRight click to cancel"));
} }
} }

View File

@@ -5,6 +5,7 @@ using Dalamud.Interface.Utility.Raii;
using Dalamud.Utility; using Dalamud.Utility;
using MareSynchronos.API.Dto.Account; using MareSynchronos.API.Dto.Account;
using MareSynchronos.FileCache; using MareSynchronos.FileCache;
using MareSynchronos.Localization;
using MareSynchronos.MareConfiguration; using MareSynchronos.MareConfiguration;
using MareSynchronos.MareConfiguration.Models; using MareSynchronos.MareConfiguration.Models;
using MareSynchronos.Services; using MareSynchronos.Services;
@@ -36,6 +37,8 @@ public partial class IntroUi : WindowMediatorSubscriberBase
private string? _registrationMessage; private string? _registrationMessage;
private RegisterReplyDto? _registrationReply; private RegisterReplyDto? _registrationReply;
private string L(string key, string fallback, params object[] args) => _uiShared.Localize(key, fallback, args);
public IntroUi(ILogger<IntroUi> logger, UiSharedService uiShared, MareConfigService configService, public IntroUi(ILogger<IntroUi> logger, UiSharedService uiShared, MareConfigService configService,
CacheMonitor fileCacheManager, ServerConfigurationManager serverConfigurationManager, MareMediator mareMediator, CacheMonitor fileCacheManager, ServerConfigurationManager serverConfigurationManager, MareMediator mareMediator,
PerformanceCollectorService performanceCollectorService, DalamudUtilService dalamudUtilService, AccountRegistrationService registerService) : base(logger, mareMediator, "Umbra Setup", performanceCollectorService) PerformanceCollectorService performanceCollectorService, DalamudUtilService dalamudUtilService, AccountRegistrationService registerService) : base(logger, mareMediator, "Umbra Setup", performanceCollectorService)
@@ -87,17 +90,17 @@ public partial class IntroUi : WindowMediatorSubscriberBase
{ {
return _uiShared.ApiController.ServerState switch return _uiShared.ApiController.ServerState switch
{ {
ServerState.Reconnecting => "Reconnecting", ServerState.Reconnecting => L("Compact.UidText.Reconnecting", "Reconnecting"),
ServerState.Connecting => "Connecting", ServerState.Connecting => L("Compact.UidText.Connecting", "Connecting"),
ServerState.Disconnected => "Disconnected", ServerState.Disconnected => L("Compact.UidText.Disconnected", "Disconnected"),
ServerState.Disconnecting => "Disconnecting", ServerState.Disconnecting => L("Compact.UidText.Disconnecting", "Disconnecting"),
ServerState.Unauthorized => "Unauthorized", ServerState.Unauthorized => L("Compact.UidText.Unauthorized", "Unauthorized"),
ServerState.VersionMisMatch => "Version mismatch", ServerState.VersionMisMatch => L("Compact.UidText.VersionMismatch", "Version mismatch"),
ServerState.Offline => "Unavailable", ServerState.Offline => L("Compact.UidText.Offline", "Unavailable"),
ServerState.RateLimited => "Rate Limited", ServerState.RateLimited => L("Compact.UidText.RateLimited", "Rate Limited"),
ServerState.NoSecretKey => "No Secret Key", ServerState.NoSecretKey => L("Compact.UidText.NoSecretKey", "No Secret Key"),
ServerState.MultiChara => "Duplicate Characters", ServerState.MultiChara => L("Compact.UidText.MultiChara", "Duplicate Characters"),
ServerState.Connected => "Connected", ServerState.Connected => L("Intro.ConnectionStatus.Connected", "Connected"),
_ => string.Empty _ => string.Empty
}; };
} }
@@ -108,18 +111,15 @@ public partial class IntroUi : WindowMediatorSubscriberBase
if (!_configService.Current.AcceptedAgreement && !_readFirstPage) if (!_configService.Current.AcceptedAgreement && !_readFirstPage)
{ {
_uiShared.BigText("Welcome to Umbra"); _uiShared.BigText(L("Intro.Welcome.Title", "Welcome to Umbra"));
ImGui.Separator(); ImGui.Separator();
UiSharedService.TextWrapped("Umbra is a plugin that will replicate your full current character state including all Penumbra mods to other paired users. " + UiSharedService.TextWrapped(L("Intro.Welcome.Paragraph1", "Umbra is a plugin that will replicate your full current character state including all Penumbra mods to other paired 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."); UiSharedService.TextWrapped(L("Intro.Welcome.Paragraph2", "We will have to setup a few things first before you can start using this plugin. Click on next to continue."));
UiSharedService.TextWrapped("We will have to setup a few things first before you can start using this plugin. Click on next to continue.");
UiSharedService.ColorTextWrapped("Note: Any modifications you have applied through anything but Penumbra cannot be shared and your character state on other clients " + UiSharedService.ColorTextWrapped(L("Intro.Welcome.Note", "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 or others players mods might not apply on your end altogether. If you want to use this plugin you will have to move your mods to Penumbra."), ImGuiColors.DalamudYellow);
"might look broken because of this or others players mods might not apply on your end altogether. " +
"If you want to use this plugin you will have to move your mods to Penumbra.", ImGuiColors.DalamudYellow);
if (!_uiShared.DrawOtherPluginState(intro: true)) return; if (!_uiShared.DrawOtherPluginState(intro: true)) return;
ImGui.Separator(); ImGui.Separator();
if (ImGui.Button("Next##toAgreement")) if (ImGui.Button(L("Intro.Welcome.Next", "Next") + "##toAgreement"))
{ {
_readFirstPage = true; _readFirstPage = true;
#if !DEBUG #if !DEBUG
@@ -127,7 +127,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase
{ {
for (int i = 10; i > 0; i--) for (int i = 10; i > 0; i--)
{ {
_timeoutLabel = $"'I agree' button will be available in {i}s"; _timeoutLabel = L("Intro.Agreement.Timeout", "'I agree' button will be available in {0}s", i);
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
} }
}); });
@@ -140,52 +140,40 @@ public partial class IntroUi : WindowMediatorSubscriberBase
{ {
using (_uiShared.UidFont.Push()) using (_uiShared.UidFont.Push())
{ {
ImGui.TextUnformatted("Agreement of Usage of Service"); ImGui.TextUnformatted(L("Intro.Agreement.Title", "Agreement of Usage of Service"));
} }
ImGui.Separator(); ImGui.Separator();
ImGui.SetWindowFontScale(1.5f); ImGui.SetWindowFontScale(1.5f);
string readThis = "READ THIS CAREFULLY"; string readThis = L("Intro.Agreement.Callout", "READ THIS CAREFULLY");
Vector2 textSize = ImGui.CalcTextSize(readThis); Vector2 textSize = ImGui.CalcTextSize(readThis);
ImGui.SetCursorPosX(ImGui.GetWindowSize().X / 2 - textSize.X / 2); ImGui.SetCursorPosX(ImGui.GetWindowSize().X / 2 - textSize.X / 2);
UiSharedService.ColorText(readThis, ImGuiColors.DalamudRed); UiSharedService.ColorText(readThis, ImGuiColors.DalamudRed);
ImGui.SetWindowFontScale(1.0f); ImGui.SetWindowFontScale(1.0f);
ImGui.Separator(); ImGui.Separator();
UiSharedService.TextWrapped(""" var agreementParagraphs = new[]
To use Umbra, you must be over the age of 18, or 21 in some jurisdictions. {
"""); L("Intro.Agreement.Paragraph1", "To use Umbra, you must be over the age of 18, or 21 in some jurisdictions."),
UiSharedService.TextWrapped(""" L("Intro.Agreement.Paragraph2", "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."),
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. L("Intro.Agreement.Paragraph3", "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. Files present on the service that already represent your active mod files will not be uploaded again."),
"""); L("Intro.Agreement.Paragraph4", "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. Locally cached mod files will have arbitrary file names to discourage attempts at replicating the original mod."),
UiSharedService.TextWrapped(""" L("Intro.Agreement.Paragraph5", "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."),
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. Files present on the service that already represent your active mod files will not be uploaded again. L("Intro.Agreement.Paragraph6", "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."),
"""); L("Intro.Agreement.Paragraph7", "Accounts that are inactive for ninety (90) days will be deleted for privacy reasons."),
UiSharedService.TextWrapped(""" L("Intro.Agreement.Paragraph8", "Umbra is operated from servers located in the European Union. You agree not to upload any content to the service that violates EU law; and more specifically, German law."),
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. Locally cached mod files will have arbitrary file names to discourage attempts at replicating the original mod. L("Intro.Agreement.Paragraph9", "You may delete your account at any time from within the Settings panel of the plugin. Any mods unique to you will then be removed from the server within 14 days."),
"""); L("Intro.Agreement.Paragraph10", "This service is provided as-is."),
UiSharedService.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.
"""); foreach (var paragraph in agreementParagraphs)
UiSharedService.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. UiSharedService.TextWrapped(paragraph);
"""); }
UiSharedService.TextWrapped("""
Accounts that are inactive for ninety (90) days will be deleted for privacy reasons.
""");
UiSharedService.TextWrapped("""
Umbra is operated from servers located in the European Union. You agree not to upload any content to the service that violates EU law; and more specifically, German law.
""");
UiSharedService.TextWrapped("""
You may delete your account at any time from within the Settings panel of the plugin. Any mods unique to you will then be removed from the server within 14 days.
""");
UiSharedService.TextWrapped("""
This service is provided as-is.
""");
ImGui.Separator(); ImGui.Separator();
if (_timeoutTask?.IsCompleted ?? true) if (_timeoutTask?.IsCompleted ?? true)
{ {
if (ImGui.Button("I agree##toSetup")) if (ImGui.Button(L("Intro.Agreement.Accept", "I agree") + "##toSetup"))
{ {
_configService.Current.AcceptedAgreement = true; _configService.Current.AcceptedAgreement = true;
_configService.Save(); _configService.Save();
@@ -202,29 +190,26 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|| !Directory.Exists(_configService.Current.CacheFolder))) || !Directory.Exists(_configService.Current.CacheFolder)))
{ {
using (_uiShared.UidFont.Push()) using (_uiShared.UidFont.Push())
ImGui.TextUnformatted("File Storage Setup"); ImGui.TextUnformatted(L("Intro.Storage.Title", "File Storage Setup"));
ImGui.Separator(); ImGui.Separator();
if (!_uiShared.HasValidPenumbraModPath) if (!_uiShared.HasValidPenumbraModPath)
{ {
UiSharedService.ColorTextWrapped("You do not have a valid Penumbra path set. Open Penumbra and set up a valid path for the mod directory.", ImGuiColors.DalamudRed); UiSharedService.ColorTextWrapped(L("Intro.Storage.NoPenumbra", "You do not have a valid Penumbra path set. Open Penumbra and set up a valid path for the mod directory."), ImGuiColors.DalamudRed);
} }
else else
{ {
UiSharedService.TextWrapped("To not unnecessary download files already present on your computer, Umbra will have to scan your Penumbra mod directory. " + UiSharedService.TextWrapped(L("Intro.Storage.Description", "To not unnecessarily download files already present on your computer, Umbra will have to scan your Penumbra mod directory. Additionally, a local storage folder must be set where Umbra will download other character files to. Once the storage folder is set and the scan complete, this page will automatically forward to registration at a service."));
"Additionally, a local storage folder must be set where Umbra will download other character files to. " + UiSharedService.TextWrapped(L("Intro.Storage.ScanNote", "Note: The initial scan, depending on the amount of mods you have, might take a while. Please wait until it is completed."));
"Once the storage folder is set and the scan complete, this page will automatically forward to registration at a service."); UiSharedService.ColorTextWrapped(L("Intro.Storage.Warning.FileCache", "Warning: once past this step you should not delete the FileCache.csv of Umbra in the Plugin Configurations folder of Dalamud. Otherwise on the next launch a full re-scan of the file cache database will be initiated."), ImGuiColors.DalamudYellow);
UiSharedService.TextWrapped("Note: The initial scan, depending on the amount of mods you have, might take a while. Please wait until it is completed."); UiSharedService.ColorTextWrapped(L("Intro.Storage.Warning.ScanHang", "Warning: if the scan is hanging and does nothing for a long time, chances are high your Penumbra folder is not set up properly."), ImGuiColors.DalamudYellow);
UiSharedService.ColorTextWrapped("Warning: once past this step you should not delete the FileCache.csv of Umbra in the Plugin Configurations folder of Dalamud. " +
"Otherwise on the next launch a full re-scan of the file cache database will be initiated.", ImGuiColors.DalamudYellow);
UiSharedService.ColorTextWrapped("Warning: if the scan is hanging and does nothing for a long time, chances are high your Penumbra folder is not set up properly.", ImGuiColors.DalamudYellow);
_uiShared.DrawCacheDirectorySetting(); _uiShared.DrawCacheDirectorySetting();
} }
if (!_cacheMonitor.IsScanRunning && !string.IsNullOrEmpty(_configService.Current.CacheFolder) && _uiShared.HasValidPenumbraModPath && Directory.Exists(_configService.Current.CacheFolder)) if (!_cacheMonitor.IsScanRunning && !string.IsNullOrEmpty(_configService.Current.CacheFolder) && _uiShared.HasValidPenumbraModPath && Directory.Exists(_configService.Current.CacheFolder))
{ {
if (ImGui.Button("Start Scan##startScan")) if (ImGui.Button(L("Intro.Storage.StartScan", "Start Scan") + "##startScan"))
{ {
_cacheMonitor.InvokeScan(); _cacheMonitor.InvokeScan();
} }
@@ -236,22 +221,21 @@ public partial class IntroUi : WindowMediatorSubscriberBase
if (!_dalamudUtilService.IsWine) if (!_dalamudUtilService.IsWine)
{ {
var useFileCompactor = _configService.Current.UseCompactor; var useFileCompactor = _configService.Current.UseCompactor;
if (ImGui.Checkbox("Use File Compactor", ref useFileCompactor)) if (ImGui.Checkbox(L("Intro.Storage.UseCompactor", "Use File Compactor"), ref useFileCompactor))
{ {
_configService.Current.UseCompactor = useFileCompactor; _configService.Current.UseCompactor = useFileCompactor;
_configService.Save(); _configService.Save();
} }
UiSharedService.ColorTextWrapped("The File Compactor can save a tremendeous amount of space on the hard disk for downloads through Umbra. It will incur a minor CPU penalty on download but can speed up " + UiSharedService.ColorTextWrapped(L("Intro.Storage.CompactorDescription", "The File Compactor can save a tremendous amount of space on the hard disk for downloads through Umbra. It will incur a minor CPU penalty on download but can speed up loading of other characters. It is recommended to keep it enabled. You can change this setting later anytime in the Umbra settings."), ImGuiColors.DalamudYellow);
"loading of other characters. It is recommended to keep it enabled. You can change this setting later anytime in the Umbra settings.", ImGuiColors.DalamudYellow);
} }
} }
else if (!_uiShared.ApiController.IsConnected) else if (!_uiShared.ApiController.IsConnected)
{ {
using (_uiShared.UidFont.Push()) using (_uiShared.UidFont.Push())
ImGui.TextUnformatted("Service Registration"); ImGui.TextUnformatted(L("Intro.Registration.Title", "Service Registration"));
ImGui.Separator(); ImGui.Separator();
UiSharedService.TextWrapped("To be able to use Umbra you will have to register an account."); UiSharedService.TextWrapped(L("Intro.Registration.Description", "To be able to use Umbra you will have to register an account."));
UiSharedService.TextWrapped("Refer to the instructions at the location you obtained this plugin for more information or support."); UiSharedService.TextWrapped(L("Intro.Registration.Support", "Refer to the instructions at the location you obtained this plugin for more information or support."));
ImGui.Separator(); ImGui.Separator();
@@ -262,8 +246,8 @@ public partial class IntroUi : WindowMediatorSubscriberBase
{ {
ImGui.BeginDisabled(_registrationInProgress || _registrationSuccess || _secretKey.Length > 0); ImGui.BeginDisabled(_registrationInProgress || _registrationSuccess || _secretKey.Length > 0);
ImGui.Separator(); ImGui.Separator();
ImGui.TextUnformatted("If you have not used Umbra before, click below to register a new account."); ImGui.TextUnformatted(L("Intro.Registration.NewAccountInfo", "If you have not used Umbra before, click below to register a new account."));
if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, "Register a new Umbra account")) if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, L("Intro.Registration.RegisterButton", "Register a new Umbra account")))
{ {
_registrationInProgress = true; _registrationInProgress = true;
_ = Task.Run(async () => { _ = Task.Run(async () => {
@@ -273,12 +257,12 @@ public partial class IntroUi : WindowMediatorSubscriberBase
if (!reply.Success) if (!reply.Success)
{ {
_logger.LogWarning("Registration failed: {err}", reply.ErrorMessage); _logger.LogWarning("Registration failed: {err}", reply.ErrorMessage);
_registrationMessage = reply.ErrorMessage; _registrationMessage = string.IsNullOrEmpty(reply.ErrorMessage)
if (_registrationMessage.IsNullOrEmpty()) ? L("Intro.Registration.UnknownError", "An unknown error occured. Please try again later.")
_registrationMessage = "An unknown error occured. Please try again later."; : reply.ErrorMessage;
return; return;
} }
_registrationMessage = "New account registered.\nPlease keep a copy of your secret key in case you need to reset your plugins, or to use it on another PC."; _registrationMessage = L("Intro.Registration.Success", "New account registered.\nPlease keep a copy of your secret key in case you need to reset your plugins, or to use it on another PC.");
_secretKey = reply.SecretKey ?? ""; _secretKey = reply.SecretKey ?? "";
_registrationReply = reply; _registrationReply = reply;
_registrationSuccess = true; _registrationSuccess = true;
@@ -287,7 +271,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase
{ {
_logger.LogWarning(ex, "Registration failed"); _logger.LogWarning(ex, "Registration failed");
_registrationSuccess = false; _registrationSuccess = false;
_registrationMessage = "An unknown error occured. Please try again later."; _registrationMessage = L("Intro.Registration.UnknownError", "An unknown error occured. Please try again later.");
} }
finally finally
{ {
@@ -298,7 +282,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase
ImGui.EndDisabled(); // _registrationInProgress || _registrationSuccess ImGui.EndDisabled(); // _registrationInProgress || _registrationSuccess
if (_registrationInProgress) if (_registrationInProgress)
{ {
ImGui.TextUnformatted("Sending request..."); ImGui.TextUnformatted(L("Intro.Registration.SendingRequest", "Sending request..."));
} }
else if (!_registrationMessage.IsNullOrEmpty()) else if (!_registrationMessage.IsNullOrEmpty())
{ {
@@ -311,42 +295,40 @@ public partial class IntroUi : WindowMediatorSubscriberBase
ImGui.Separator(); ImGui.Separator();
var text = "Enter Secret Key"; var secretKeyLabel = _registrationSuccess
? L("Intro.Registration.SecretKeyLabelRegistered", "Secret Key")
: L("Intro.Registration.SecretKeyLabel", "Enter Secret Key");
if (_registrationSuccess) if (!_registrationSuccess)
{ {
text = "Secret Key"; ImGui.TextUnformatted(L("Intro.Registration.SecretKeyInstructions", "If you already have a registered account, you can enter its secret key below to use it instead."));
}
else
{
ImGui.TextUnformatted("If you already have a registered account, you can enter its secret key below to use it instead.");
} }
var textSize = ImGui.CalcTextSize(text); var textSize = ImGui.CalcTextSize(secretKeyLabel);
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(text); ImGui.TextUnformatted(secretKeyLabel);
ImGui.SameLine(); ImGui.SameLine();
ImGui.SetNextItemWidth(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X - textSize.X); ImGui.SetNextItemWidth(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X - textSize.X);
ImGui.InputText("", ref _secretKey, 64); ImGui.InputText("", ref _secretKey, 64);
if (_secretKey.Length > 0 && _secretKey.Length != 64) if (_secretKey.Length > 0 && _secretKey.Length != 64)
{ {
UiSharedService.ColorTextWrapped("Your secret key must be exactly 64 characters long.", ImGuiColors.DalamudRed); UiSharedService.ColorTextWrapped(L("Intro.Registration.SecretKeyLength", "Your secret key must be exactly 64 characters long."), ImGuiColors.DalamudRed);
} }
else if (_secretKey.Length == 64 && !HexRegex().IsMatch(_secretKey)) else if (_secretKey.Length == 64 && !HexRegex().IsMatch(_secretKey))
{ {
UiSharedService.ColorTextWrapped("Your secret key can only contain ABCDEF and the numbers 0-9.", ImGuiColors.DalamudRed); UiSharedService.ColorTextWrapped(L("Intro.Registration.SecretKeyCharacters", "Your secret key can only contain ABCDEF and the numbers 0-9."), ImGuiColors.DalamudRed);
} }
else if (_secretKey.Length == 64) else if (_secretKey.Length == 64)
{ {
using var saveDisabled = ImRaii.Disabled(_uiShared.ApiController.ServerState == ServerState.Connecting || _uiShared.ApiController.ServerState == ServerState.Reconnecting); using var saveDisabled = ImRaii.Disabled(_uiShared.ApiController.ServerState == ServerState.Connecting || _uiShared.ApiController.ServerState == ServerState.Reconnecting);
if (ImGui.Button("Save and Connect")) if (ImGui.Button(L("Intro.Registration.SaveAndConnect", "Save and Connect")))
{ {
string keyName; string keyName;
if (_serverConfigurationManager.CurrentServer == null) _serverConfigurationManager.SelectServer(0); if (_serverConfigurationManager.CurrentServer == null) _serverConfigurationManager.SelectServer(0);
if (_registrationReply != null && _secretKey.Equals(_registrationReply.SecretKey, StringComparison.Ordinal)) if (_registrationReply != null && _secretKey.Equals(_registrationReply.SecretKey, StringComparison.Ordinal))
keyName = _registrationReply.UID + $" (registered {DateTime.Now:yyyy-MM-dd})"; keyName = _registrationReply.UID + " " + L("Intro.Registration.SavedKeyRegistered", "(registered {0})", DateTime.Now.ToString("yyyy-MM-dd"));
else else
keyName = $"Secret Key added on Setup ({DateTime.Now:yyyy-MM-dd})"; keyName = L("Intro.Registration.SavedKeySetup", "Secret Key added on Setup ({0})", DateTime.Now.ToString("yyyy-MM-dd"));
_serverConfigurationManager.CurrentServer!.SecretKeys.Add(_serverConfigurationManager.CurrentServer.SecretKeys.Select(k => k.Key).LastOrDefault() + 1, new SecretKey() _serverConfigurationManager.CurrentServer!.SecretKeys.Add(_serverConfigurationManager.CurrentServer.SecretKeys.Select(k => k.Key).LastOrDefault() + 1, new SecretKey()
{ {
FriendlyName = keyName, FriendlyName = keyName,

View File

@@ -22,7 +22,9 @@ public class PermissionWindowUI : WindowMediatorSubscriberBase
public PermissionWindowUI(ILogger<PermissionWindowUI> logger, Pair pair, MareMediator mediator, UiSharedService uiSharedService, public PermissionWindowUI(ILogger<PermissionWindowUI> logger, Pair pair, MareMediator mediator, UiSharedService uiSharedService,
ApiController apiController, PerformanceCollectorService performanceCollectorService) ApiController apiController, PerformanceCollectorService performanceCollectorService)
: base(logger, mediator, "Permissions for " + pair.UserData.AliasOrUID + "###UmbraSyncPermissions" + pair.UserData.UID, performanceCollectorService) : base(logger, mediator,
uiSharedService.Localize("PermissionWindow.Title", "Permissions for {0}", pair.UserData.AliasOrUID) + "###UmbraSyncPermissions" + pair.UserData.UID,
performanceCollectorService)
{ {
Pair = pair; Pair = pair;
_uiSharedService = uiSharedService; _uiSharedService = uiSharedService;
@@ -37,6 +39,8 @@ public class PermissionWindowUI : WindowMediatorSubscriberBase
IsOpen = true; IsOpen = true;
} }
private string L(string key, string fallback, params object[] args) => _uiSharedService.Localize(key, fallback, args);
protected override void DrawInternal() protected override void DrawInternal()
{ {
var paused = _ownPermissions.IsPaused(); var paused = _ownPermissions.IsPaused();
@@ -46,18 +50,19 @@ public class PermissionWindowUI : WindowMediatorSubscriberBase
var style = ImGui.GetStyle(); var style = ImGui.GetStyle();
var indentSize = ImGui.GetFrameHeight() + style.ItemSpacing.X; var indentSize = ImGui.GetFrameHeight() + style.ItemSpacing.X;
_uiSharedService.BigText("Permissions for " + Pair.UserData.AliasOrUID); _uiSharedService.BigText(L("PermissionWindow.Title", "Permissions for {0}", Pair.UserData.AliasOrUID));
ImGuiHelpers.ScaledDummy(1f); ImGuiHelpers.ScaledDummy(1f);
if (Pair.UserPair == null) if (Pair.UserPair == null)
return; return;
if (ImGui.Checkbox("Pause Sync", ref paused)) if (ImGui.Checkbox(L("PermissionWindow.Pause.Label", "Pause Sync"), ref paused))
{ {
_ownPermissions.SetPaused(paused); _ownPermissions.SetPaused(paused);
} }
_uiSharedService.DrawHelpText("Pausing will completely cease any sync with this user." + UiSharedService.TooltipSeparator _uiSharedService.DrawHelpText(L("PermissionWindow.Pause.HelpMain", "Pausing will completely cease any sync with this user.")
+ "Note: this is bidirectional, either user pausing will cease sync completely."); + UiSharedService.TooltipSeparator
+ L("PermissionWindow.Pause.HelpNote", "Note: this is bidirectional, either user pausing will cease sync completely."));
var otherPerms = Pair.UserPair.OtherPermissions; var otherPerms = Pair.UserPair.OtherPermissions;
var otherIsPaused = otherPerms.IsPaused(); var otherIsPaused = otherPerms.IsPaused();
@@ -70,53 +75,68 @@ public class PermissionWindowUI : WindowMediatorSubscriberBase
_uiSharedService.BooleanToColoredIcon(!otherIsPaused, false); _uiSharedService.BooleanToColoredIcon(!otherIsPaused, false);
ImGui.SameLine(); ImGui.SameLine();
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(Pair.UserData.AliasOrUID + " has " + (!otherIsPaused ? "not " : string.Empty) + "paused you"); var pausedText = otherIsPaused
? L("PermissionWindow.OtherPaused.True", "{0} has paused you", Pair.UserData.AliasOrUID)
: L("PermissionWindow.OtherPaused.False", "{0} has not paused you", Pair.UserData.AliasOrUID);
ImGui.TextUnformatted(pausedText);
} }
ImGuiHelpers.ScaledDummy(0.5f); ImGuiHelpers.ScaledDummy(0.5f);
ImGui.Separator(); ImGui.Separator();
ImGuiHelpers.ScaledDummy(0.5f); ImGuiHelpers.ScaledDummy(0.5f);
if (ImGui.Checkbox("Disable Sounds", ref disableSounds)) if (ImGui.Checkbox(L("PermissionWindow.Sounds.Label", "Disable Sounds"), ref disableSounds))
{ {
_ownPermissions.SetDisableSounds(disableSounds); _ownPermissions.SetDisableSounds(disableSounds);
} }
_uiSharedService.DrawHelpText("Disabling sounds will remove all sounds synced with this user on both sides." + UiSharedService.TooltipSeparator _uiSharedService.DrawHelpText(L("PermissionWindow.Sounds.HelpMain", "Disabling sounds will remove all sounds synced with this user on both sides.")
+ "Note: this is bidirectional, either user disabling sound sync will stop sound sync on both sides."); + UiSharedService.TooltipSeparator
+ L("PermissionWindow.Sounds.HelpNote", "Note: this is bidirectional, either user disabling sound sync will stop sound sync on both sides."));
using (ImRaii.PushIndent(indentSize, false)) using (ImRaii.PushIndent(indentSize, false))
{ {
_uiSharedService.BooleanToColoredIcon(!otherDisableSounds, false); _uiSharedService.BooleanToColoredIcon(!otherDisableSounds, false);
ImGui.SameLine(); ImGui.SameLine();
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(Pair.UserData.AliasOrUID + " has " + (!otherDisableSounds ? "not " : string.Empty) + "disabled sound sync with you"); var soundText = otherDisableSounds
? L("PermissionWindow.OtherSoundDisabled.True", "{0} has disabled sound sync with you", Pair.UserData.AliasOrUID)
: L("PermissionWindow.OtherSoundDisabled.False", "{0} has not disabled sound sync with you", Pair.UserData.AliasOrUID);
ImGui.TextUnformatted(soundText);
} }
if (ImGui.Checkbox("Disable Animations", ref disableAnimations)) if (ImGui.Checkbox(L("PermissionWindow.Animations.Label", "Disable Animations"), ref disableAnimations))
{ {
_ownPermissions.SetDisableAnimations(disableAnimations); _ownPermissions.SetDisableAnimations(disableAnimations);
} }
_uiSharedService.DrawHelpText("Disabling sounds will remove all animations synced with this user on both sides." + UiSharedService.TooltipSeparator _uiSharedService.DrawHelpText(L("PermissionWindow.Animations.HelpMain", "Disabling sounds will remove all animations synced with this user on both sides.")
+ "Note: this is bidirectional, either user disabling animation sync will stop animation sync on both sides."); + UiSharedService.TooltipSeparator
+ L("PermissionWindow.Animations.HelpNote", "Note: this is bidirectional, either user disabling animation sync will stop animation sync on both sides."));
using (ImRaii.PushIndent(indentSize, false)) using (ImRaii.PushIndent(indentSize, false))
{ {
_uiSharedService.BooleanToColoredIcon(!otherDisableAnimations, false); _uiSharedService.BooleanToColoredIcon(!otherDisableAnimations, false);
ImGui.SameLine(); ImGui.SameLine();
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(Pair.UserData.AliasOrUID + " has " + (!otherDisableAnimations ? "not " : string.Empty) + "disabled animation sync with you"); var animText = otherDisableAnimations
? L("PermissionWindow.OtherAnimationDisabled.True", "{0} has disabled animation sync with you", Pair.UserData.AliasOrUID)
: L("PermissionWindow.OtherAnimationDisabled.False", "{0} has not disabled animation sync with you", Pair.UserData.AliasOrUID);
ImGui.TextUnformatted(animText);
} }
if (ImGui.Checkbox("Disable VFX", ref disableVfx)) if (ImGui.Checkbox(L("PermissionWindow.Vfx.Label", "Disable VFX"), ref disableVfx))
{ {
_ownPermissions.SetDisableVFX(disableVfx); _ownPermissions.SetDisableVFX(disableVfx);
} }
_uiSharedService.DrawHelpText("Disabling sounds will remove all VFX synced with this user on both sides." + UiSharedService.TooltipSeparator _uiSharedService.DrawHelpText(L("PermissionWindow.Vfx.HelpMain", "Disabling sounds will remove all VFX synced with this user on both sides.")
+ "Note: this is bidirectional, either user disabling VFX sync will stop VFX sync on both sides."); + UiSharedService.TooltipSeparator
+ L("PermissionWindow.Vfx.HelpNote", "Note: this is bidirectional, either user disabling VFX sync will stop VFX sync on both sides."));
using (ImRaii.PushIndent(indentSize, false)) using (ImRaii.PushIndent(indentSize, false))
{ {
_uiSharedService.BooleanToColoredIcon(!otherDisableVFX, false); _uiSharedService.BooleanToColoredIcon(!otherDisableVFX, false);
ImGui.SameLine(); ImGui.SameLine();
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(Pair.UserData.AliasOrUID + " has " + (!otherDisableVFX ? "not " : string.Empty) + "disabled VFX sync with you"); var vfxText = otherDisableVFX
? L("PermissionWindow.OtherVfxDisabled.True", "{0} has disabled VFX sync with you", Pair.UserData.AliasOrUID)
: L("PermissionWindow.OtherVfxDisabled.False", "{0} has not disabled VFX sync with you", Pair.UserData.AliasOrUID);
ImGui.TextUnformatted(vfxText);
} }
ImGuiHelpers.ScaledDummy(0.5f); ImGuiHelpers.ScaledDummy(0.5f);
@@ -126,27 +146,27 @@ public class PermissionWindowUI : WindowMediatorSubscriberBase
bool hasChanges = _ownPermissions != Pair.UserPair.OwnPermissions; bool hasChanges = _ownPermissions != Pair.UserPair.OwnPermissions;
using (ImRaii.Disabled(!hasChanges)) using (ImRaii.Disabled(!hasChanges))
if (_uiSharedService.IconTextButton(Dalamud.Interface.FontAwesomeIcon.Save, "Save")) if (_uiSharedService.IconTextButton(Dalamud.Interface.FontAwesomeIcon.Save, L("PermissionWindow.Button.Save", "Save")))
{ {
_ = _apiController.UserSetPairPermissions(new(Pair.UserData, _ownPermissions)); _ = _apiController.UserSetPairPermissions(new(Pair.UserData, _ownPermissions));
} }
UiSharedService.AttachToolTip("Save and apply all changes"); UiSharedService.AttachToolTip(L("PermissionWindow.Tooltip.Save", "Save and apply all changes"));
var rightSideButtons = _uiSharedService.GetIconTextButtonSize(Dalamud.Interface.FontAwesomeIcon.Undo, "Revert") + var rightSideButtons = _uiSharedService.GetIconTextButtonSize(Dalamud.Interface.FontAwesomeIcon.Undo, L("PermissionWindow.Button.Revert", "Revert")) +
_uiSharedService.GetIconTextButtonSize(Dalamud.Interface.FontAwesomeIcon.ArrowsSpin, "Reset to Default"); _uiSharedService.GetIconTextButtonSize(Dalamud.Interface.FontAwesomeIcon.ArrowsSpin, L("PermissionWindow.Button.Reset", "Reset to Default"));
var availableWidth = ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X; var availableWidth = ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X;
ImGui.SameLine(availableWidth - rightSideButtons); ImGui.SameLine(availableWidth - rightSideButtons);
using (ImRaii.Disabled(!hasChanges)) using (ImRaii.Disabled(!hasChanges))
if (_uiSharedService.IconTextButton(Dalamud.Interface.FontAwesomeIcon.Undo, "Revert")) if (_uiSharedService.IconTextButton(Dalamud.Interface.FontAwesomeIcon.Undo, L("PermissionWindow.Button.Revert", "Revert")))
{ {
_ownPermissions = Pair.UserPair.OwnPermissions.DeepClone(); _ownPermissions = Pair.UserPair.OwnPermissions.DeepClone();
} }
UiSharedService.AttachToolTip("Revert all changes"); UiSharedService.AttachToolTip(L("PermissionWindow.Tooltip.Revert", "Revert all changes"));
ImGui.SameLine(); ImGui.SameLine();
if (_uiSharedService.IconTextButton(Dalamud.Interface.FontAwesomeIcon.ArrowsSpin, "Reset to Default")) if (_uiSharedService.IconTextButton(Dalamud.Interface.FontAwesomeIcon.ArrowsSpin, L("PermissionWindow.Button.Reset", "Reset to Default")))
{ {
_ownPermissions.SetPaused(false); _ownPermissions.SetPaused(false);
_ownPermissions.SetDisableVFX(false); _ownPermissions.SetDisableVFX(false);
@@ -154,7 +174,7 @@ public class PermissionWindowUI : WindowMediatorSubscriberBase
_ownPermissions.SetDisableAnimations(false); _ownPermissions.SetDisableAnimations(false);
_ = _apiController.UserSetPairPermissions(new(Pair.UserData, _ownPermissions)); _ = _apiController.UserSetPairPermissions(new(Pair.UserData, _ownPermissions));
} }
UiSharedService.AttachToolTip("This will set all permissions to their default setting"); UiSharedService.AttachToolTip(L("PermissionWindow.Tooltip.Reset", "This will set all permissions to their default setting"));
var ySize = ImGui.GetCursorPosY() + style.FramePadding.Y * ImGuiHelpers.GlobalScale + style.FrameBorderSize; var ySize = ImGui.GetCursorPosY() + style.FramePadding.Y * ImGuiHelpers.GlobalScale + style.FrameBorderSize;
ImGui.SetWindowSize(new(400, ySize)); ImGui.SetWindowSize(new(400, ySize));

View File

@@ -143,16 +143,16 @@ public class SettingsUi : WindowMediatorSubscriberBase
private void DrawBlockedTransfers() private void DrawBlockedTransfers()
{ {
_lastTab = "BlockedTransfers"; _lastTab = "BlockedTransfers";
UiSharedService.ColorTextWrapped("Files that you attempted to upload or download that were forbidden to be transferred by their creators will appear here. " + UiSharedService.ColorTextWrapped(L("Settings.Transfers.Blocked.Description",
"Files that you attempted to upload or download that were forbidden to be transferred by their creators will appear here. " +
"If you see file paths from your drive here, then those files were not allowed to be uploaded. If you see hashes, those files were not allowed to be downloaded. " + "If you see file paths from your drive here, then those files were not allowed to be uploaded. If you see hashes, those files were not allowed to be downloaded. " +
"Ask your paired friend to send you the mod in question through other means or acquire the mod yourself.", "Ask your paired friend to send you the mod in question through other means or acquire the mod yourself."),
ImGuiColors.DalamudGrey); ImGuiColors.DalamudGrey);
if (ImGui.BeginTable("TransfersTable", 2, ImGuiTableFlags.SizingStretchProp)) if (ImGui.BeginTable("TransfersTable", 2, ImGuiTableFlags.SizingStretchProp))
{ {
ImGui.TableSetupColumn( ImGui.TableSetupColumn(L("Settings.Transfers.Blocked.Column.Hash", "Hash/Filename"));
$"Hash/Filename"); ImGui.TableSetupColumn(L("Settings.Transfers.Blocked.Column.ForbiddenBy", "Forbidden by"));
ImGui.TableSetupColumn($"Forbidden by");
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
@@ -358,18 +358,19 @@ public class SettingsUi : WindowMediatorSubscriberBase
if (!showTransferBars) ImGui.EndDisabled(); if (!showTransferBars) ImGui.EndDisabled();
ImGui.Separator(); ImGui.Separator();
_uiShared.BigText("Current Transfers"); _uiShared.BigText(L("Settings.Transfers.Current.Heading", "Current Transfers"));
if (ImGui.BeginTabBar("TransfersTabBar")) if (ImGui.BeginTabBar("TransfersTabBar"))
{ {
if (ApiController.ServerState is ServerState.Connected && ImGui.BeginTabItem("Transfers")) var currentTransfersTabTitle = L("Settings.Transfers.Current.Tab", "Transfers");
if (ApiController.ServerState is ServerState.Connected && ImGui.BeginTabItem(currentTransfersTabTitle + "###currentTransfersTab"))
{ {
ImGui.TextUnformatted("Uploads"); ImGui.TextUnformatted(L("Settings.Transfers.Current.Uploads", "Uploads"));
if (ImGui.BeginTable("UploadsTable", 3)) if (ImGui.BeginTable("UploadsTable", 3))
{ {
ImGui.TableSetupColumn("File"); ImGui.TableSetupColumn(L("Settings.Transfers.Current.Uploads.Column.File", "File"));
ImGui.TableSetupColumn("Uploaded"); ImGui.TableSetupColumn(L("Settings.Transfers.Current.Uploads.Column.Uploaded", "Uploaded"));
ImGui.TableSetupColumn("Size"); ImGui.TableSetupColumn(L("Settings.Transfers.Current.Uploads.Column.Size", "Size"));
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
foreach (var transfer in _fileTransferManager.CurrentUploads.ToArray()) foreach (var transfer in _fileTransferManager.CurrentUploads.ToArray())
{ {
@@ -388,13 +389,13 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.EndTable(); ImGui.EndTable();
} }
ImGui.Separator(); ImGui.Separator();
ImGui.TextUnformatted("Downloads"); ImGui.TextUnformatted(L("Settings.Transfers.Current.Downloads", "Downloads"));
if (ImGui.BeginTable("DownloadsTable", 4)) if (ImGui.BeginTable("DownloadsTable", 4))
{ {
ImGui.TableSetupColumn("User"); ImGui.TableSetupColumn(L("Settings.Transfers.Current.Downloads.Column.User", "User"));
ImGui.TableSetupColumn("Server"); ImGui.TableSetupColumn(L("Settings.Transfers.Current.Downloads.Column.Server", "Server"));
ImGui.TableSetupColumn("Files"); ImGui.TableSetupColumn(L("Settings.Transfers.Current.Downloads.Column.Files", "Files"));
ImGui.TableSetupColumn("Download"); ImGui.TableSetupColumn(L("Settings.Transfers.Current.Downloads.Column.Download", "Download"));
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
foreach (var transfer in _currentDownloads.ToArray()) foreach (var transfer in _currentDownloads.ToArray())
@@ -423,8 +424,8 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.EndTabItem(); ImGui.EndTabItem();
} }
var blockedTransfersTabTitle = L("Settings.Transfers.Blocked.Tab", "Blocked Transfers");
if (ImGui.BeginTabItem("Blocked Transfers")) if (ImGui.BeginTabItem(blockedTransfersTabTitle + "###blockedTransfersTab"))
{ {
DrawBlockedTransfers(); DrawBlockedTransfers();
ImGui.EndTabItem(); ImGui.EndTabItem();
@@ -634,53 +635,51 @@ public class SettingsUi : WindowMediatorSubscriberBase
{ {
_lastTab = "Advanced"; _lastTab = "Advanced";
_uiShared.BigText("Advanced"); _uiShared.BigText(L("Settings.Advanced.Heading", "Advanced"));
bool mareApi = _configService.Current.MareAPI; bool mareApi = _configService.Current.MareAPI;
if (ImGui.Checkbox("Enable Umbra Sync API", ref mareApi)) if (ImGui.Checkbox(L("Settings.Advanced.Api.Enable", "Enable Umbra Sync API"), ref mareApi))
{ {
_configService.Current.MareAPI = mareApi; _configService.Current.MareAPI = mareApi;
_configService.Save(); _configService.Save();
_ipcProvider.HandleMareImpersonation(); _ipcProvider.HandleMareImpersonation();
} }
_uiShared.DrawHelpText("Enables handling of the Umbra Sync API. This currently includes:\n\n" + _uiShared.DrawHelpText(L("Settings.Advanced.Api.Description",
" - MCDF loading support for other plugins\n" + "Enables handling of the Umbra Sync API. This currently includes:\n\n - MCDF loading support for other plugins\n - Blocking Moodles applications to paired users\n\nIf the Umbra Sync plugin is loaded while this option is enabled, control of its API will be relinquished."));
" - Blocking Moodles applications to paired users\n\n" +
"If the Umbra Sync plugin is loaded while this option is enabled, control of its API will be relinquished.");
using (_ = ImRaii.PushIndent()) using (_ = ImRaii.PushIndent())
{ {
ImGui.SameLine(300.0f * ImGuiHelpers.GlobalScale); ImGui.SameLine(300.0f * ImGuiHelpers.GlobalScale);
if (_ipcProvider.ImpersonationActive) if (_ipcProvider.ImpersonationActive)
{ {
UiSharedService.ColorTextWrapped("Umbra API active!", UiSharedService.AccentColor); UiSharedService.ColorTextWrapped(L("Settings.Advanced.Api.Status.Active", "Umbra API active!"), UiSharedService.AccentColor);
} }
else else
{ {
if (!mareApi) if (!mareApi)
UiSharedService.ColorTextWrapped("Umbra API inactive: Option is disabled", ImGuiColors.DalamudYellow); UiSharedService.ColorTextWrapped(L("Settings.Advanced.Api.Status.Disabled", "Umbra API inactive: Option is disabled"), ImGuiColors.DalamudYellow);
else if (_ipcProvider.MarePluginEnabled) else if (_ipcProvider.MarePluginEnabled)
UiSharedService.ColorTextWrapped("Umbra API inactive: Umbra plugin is loaded", ImGuiColors.DalamudYellow); UiSharedService.ColorTextWrapped(L("Settings.Advanced.Api.Status.PluginLoaded", "Umbra API inactive: Umbra plugin is loaded"), ImGuiColors.DalamudYellow);
else else
UiSharedService.ColorTextWrapped("Umbra API inactive: Unknown reason", ImGuiColors.DalamudRed); UiSharedService.ColorTextWrapped(L("Settings.Advanced.Api.Status.Unknown", "Umbra API inactive: Unknown reason"), ImGuiColors.DalamudRed);
} }
} }
bool logEvents = _configService.Current.LogEvents; bool logEvents = _configService.Current.LogEvents;
if (ImGui.Checkbox("Log Event Viewer data to disk", ref logEvents)) if (ImGui.Checkbox(L("Settings.Advanced.EventViewer.LogToDisk", "Log Event Viewer data to disk"), ref logEvents))
{ {
_configService.Current.LogEvents = logEvents; _configService.Current.LogEvents = logEvents;
_configService.Save(); _configService.Save();
} }
ImGui.SameLine(300.0f * ImGuiHelpers.GlobalScale); ImGui.SameLine(300.0f * ImGuiHelpers.GlobalScale);
if (_uiShared.IconTextButton(FontAwesomeIcon.NotesMedical, "Open Event Viewer")) if (_uiShared.IconTextButton(FontAwesomeIcon.NotesMedical, L("Settings.Advanced.EventViewer.Open", "Open Event Viewer")))
{ {
Mediator.Publish(new UiToggleMessage(typeof(EventViewerUI))); Mediator.Publish(new UiToggleMessage(typeof(EventViewerUI)));
} }
bool holdCombatApplication = _configService.Current.HoldCombatApplication; bool holdCombatApplication = _configService.Current.HoldCombatApplication;
if (ImGui.Checkbox("Hold application during combat", ref holdCombatApplication)) if (ImGui.Checkbox(L("Settings.Advanced.HoldCombat", "Hold application during combat"), ref holdCombatApplication))
{ {
if (!holdCombatApplication) if (!holdCombatApplication)
Mediator.Publish(new CombatOrPerformanceEndMessage()); Mediator.Publish(new CombatOrPerformanceEndMessage());
@@ -689,17 +688,17 @@ public class SettingsUi : WindowMediatorSubscriberBase
} }
bool serializedApplications = _configService.Current.SerialApplication; bool serializedApplications = _configService.Current.SerialApplication;
if (ImGui.Checkbox("Serialized player applications", ref serializedApplications)) if (ImGui.Checkbox(L("Settings.Advanced.SerializedApplications", "Serialized player applications"), ref serializedApplications))
{ {
_configService.Current.SerialApplication = serializedApplications; _configService.Current.SerialApplication = serializedApplications;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("Experimental - May reduce issues in crowded areas"); _uiShared.DrawHelpText(L("Settings.Advanced.SerializedApplications.Description", "Experimental - May reduce issues in crowded areas"));
ImGui.Separator(); ImGui.Separator();
_uiShared.BigText("Debug"); _uiShared.BigText(L("Settings.Advanced.DebugHeading", "Debug"));
#if DEBUG #if DEBUG
if (LastCreatedCharacterData != null && ImGui.TreeNode("Last created character data")) if (LastCreatedCharacterData != null && ImGui.TreeNode(L("Settings.Advanced.Debug.LastCreatedTree", "Last created character data")))
{ {
foreach (var l in JsonSerializer.Serialize(LastCreatedCharacterData, new JsonSerializerOptions() { WriteIndented = true }).Split('\n')) foreach (var l in JsonSerializer.Serialize(LastCreatedCharacterData, new JsonSerializerOptions() { WriteIndented = true }).Split('\n'))
{ {
@@ -709,7 +708,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.TreePop(); ImGui.TreePop();
} }
#endif #endif
if (_uiShared.IconTextButton(FontAwesomeIcon.Copy, "[DEBUG] Copy Last created Character Data to clipboard")) if (_uiShared.IconTextButton(FontAwesomeIcon.Copy, L("Settings.Advanced.Debug.CopyButton", "[DEBUG] Copy Last created Character Data to clipboard")))
{ {
if (LastCreatedCharacterData != null) if (LastCreatedCharacterData != null)
{ {
@@ -717,39 +716,39 @@ public class SettingsUi : WindowMediatorSubscriberBase
} }
else else
{ {
ImGui.SetClipboardText("ERROR: No created character data, cannot copy."); ImGui.SetClipboardText(L("Settings.Advanced.Debug.CopyError", "ERROR: No created character data, cannot copy."));
} }
} }
UiSharedService.AttachToolTip("Use this when reporting mods being rejected from the server."); UiSharedService.AttachToolTip(L("Settings.Advanced.Debug.CopyTooltip", "Use this when reporting mods being rejected from the server."));
_uiShared.DrawCombo("Log Level", Enum.GetValues<LogLevel>(), (l) => l.ToString(), (l) => _uiShared.DrawCombo(L("Settings.Advanced.LogLevel", "Log Level"), Enum.GetValues<LogLevel>(), (l) => l.ToString(), (l) =>
{ {
_configService.Current.LogLevel = l; _configService.Current.LogLevel = l;
_configService.Save(); _configService.Save();
}, _configService.Current.LogLevel); }, _configService.Current.LogLevel);
bool logPerformance = _configService.Current.LogPerformance; bool logPerformance = _configService.Current.LogPerformance;
if (ImGui.Checkbox("Log Performance Counters", ref logPerformance)) if (ImGui.Checkbox(L("Settings.Advanced.Performance.LogCounters", "Log Performance Counters"), ref logPerformance))
{ {
_configService.Current.LogPerformance = logPerformance; _configService.Current.LogPerformance = logPerformance;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("Enabling this can incur a (slight) performance impact. Enabling this for extended periods of time is not recommended."); _uiShared.DrawHelpText(L("Settings.Advanced.Performance.LogCounters.Description", "Enabling this can incur a (slight) performance impact. Enabling this for extended periods of time is not recommended."));
using (ImRaii.Disabled(!logPerformance)) using (ImRaii.Disabled(!logPerformance))
{ {
if (_uiShared.IconTextButton(FontAwesomeIcon.StickyNote, "Print Performance Stats to /xllog")) if (_uiShared.IconTextButton(FontAwesomeIcon.StickyNote, L("Settings.Advanced.Performance.PrintStats", "Print Performance Stats to /xllog")))
{ {
_performanceCollector.PrintPerformanceStats(); _performanceCollector.PrintPerformanceStats();
} }
ImGui.SameLine(); ImGui.SameLine();
if (_uiShared.IconTextButton(FontAwesomeIcon.StickyNote, "Print Performance Stats (last 60s) to /xllog")) if (_uiShared.IconTextButton(FontAwesomeIcon.StickyNote, L("Settings.Advanced.Performance.PrintStatsRecent", "Print Performance Stats (last 60s) to /xllog")))
{ {
_performanceCollector.PrintPerformanceStats(60); _performanceCollector.PrintPerformanceStats(60);
} }
} }
if (ImGui.TreeNode("Active Character Blocks")) if (ImGui.TreeNode(L("Settings.Advanced.ActiveBlocks", "Active Character Blocks")))
{ {
var onlinePairs = _pairManager.GetOnlineUserPairs(); var onlinePairs = _pairManager.GetOnlineUserPairs();
foreach (var pair in onlinePairs) foreach (var pair in onlinePairs)
@@ -782,10 +781,10 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.Separator(); ImGui.Separator();
_uiShared.BigText("Storage"); _uiShared.BigText(L("Settings.Storage.Heading", "Storage"));
UiSharedService.TextWrapped("Umbra stores downloaded files from paired people permanently. This is to improve loading performance and requiring less downloads. " + UiSharedService.TextWrapped(L("Settings.Storage.Description",
"The storage governs itself by clearing data beyond the set storage size. Please set the storage size accordingly. It is not necessary to manually clear the storage."); "Umbra stores downloaded files from paired people permanently. This is to improve loading performance and requiring less downloads. The storage governs itself by clearing data beyond the set storage size. Please set the storage size accordingly. It is not necessary to manually clear the storage."));
_uiShared.DrawFileScanState(); _uiShared.DrawFileScanState();
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
@@ -1563,29 +1562,32 @@ public class SettingsUi : WindowMediatorSubscriberBase
_lastTab = "Service Settings"; _lastTab = "Service Settings";
if (ApiController.ServerAlive) if (ApiController.ServerAlive)
{ {
_uiShared.BigText("Service Actions"); var serviceActionsHeading = L("Settings.Service.ActionsHeading", "Service Actions");
_uiShared.BigText(serviceActionsHeading);
ImGuiHelpers.ScaledDummy(new Vector2(5, 5)); ImGuiHelpers.ScaledDummy(new Vector2(5, 5));
if (ImGui.Button("Delete account")) var deleteAccountLabel = L("Settings.Service.Actions.DeleteAccount", "Delete account");
var deleteAccountPopupTitle = L("Settings.Service.Actions.DeleteAccountPopup", "Delete your account?");
if (ImGui.Button(deleteAccountLabel))
{ {
_deleteAccountPopupModalShown = true; _deleteAccountPopupModalShown = true;
ImGui.OpenPopup("Delete your account?"); ImGui.OpenPopup(deleteAccountPopupTitle);
} }
_uiShared.DrawHelpText("Completely deletes your currently connected account."); _uiShared.DrawHelpText(L("Settings.Service.Actions.DeleteAccount.Description", "Completely deletes your currently connected account."));
if (ImGui.BeginPopupModal("Delete your account?", ref _deleteAccountPopupModalShown, UiSharedService.PopupWindowFlags)) if (ImGui.BeginPopupModal(deleteAccountPopupTitle, ref _deleteAccountPopupModalShown, UiSharedService.PopupWindowFlags))
{ {
UiSharedService.TextWrapped( UiSharedService.TextWrapped(
"Your account and all associated files and data on the service will be deleted."); L("Settings.Service.Actions.DeleteAccount.Popup.Body1", "Your account and all associated files and data on the service will be deleted."));
UiSharedService.TextWrapped("Your UID will be removed from all pairing lists."); UiSharedService.TextWrapped(L("Settings.Service.Actions.DeleteAccount.Popup.Body2", "Your UID will be removed from all pairing lists."));
ImGui.TextUnformatted("Are you sure you want to continue?"); ImGui.TextUnformatted(L("Settings.Service.Actions.DeleteAccount.Popup.Confirm", "Are you sure you want to continue?"));
ImGui.Separator(); ImGui.Separator();
ImGui.Spacing(); ImGui.Spacing();
var buttonSize = (ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - var buttonSize = (ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X -
ImGui.GetStyle().ItemSpacing.X) / 2; ImGui.GetStyle().ItemSpacing.X) / 2;
var deleteAccountConfirmLabel = deleteAccountLabel + "###deleteAccountConfirm";
if (ImGui.Button("Delete account", new Vector2(buttonSize, 0))) if (ImGui.Button(deleteAccountConfirmLabel, new Vector2(buttonSize, 0)))
{ {
_ = Task.Run(ApiController.UserDelete); _ = Task.Run(ApiController.UserDelete);
_deleteAccountPopupModalShown = false; _deleteAccountPopupModalShown = false;
@@ -1594,7 +1596,8 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.SameLine(); ImGui.SameLine();
if (ImGui.Button("Cancel##cancelDelete", new Vector2(buttonSize, 0))) var cancelDeleteLabel = L("Settings.Service.Actions.DeleteAccount.Popup.Cancel", "Cancel") + "##cancelDelete";
if (ImGui.Button(cancelDeleteLabel, new Vector2(buttonSize, 0)))
{ {
_deleteAccountPopupModalShown = false; _deleteAccountPopupModalShown = false;
} }
@@ -1605,7 +1608,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.Separator(); ImGui.Separator();
} }
_uiShared.BigText("Service & Character Settings"); _uiShared.BigText(L("Settings.Service.SettingsHeading", "Service & Character Settings"));
var idx = _uiShared.DrawServiceSelection(); var idx = _uiShared.DrawServiceSelection();
var playerName = _dalamudUtilService.GetPlayerName(); var playerName = _dalamudUtilService.GetPlayerName();
@@ -1619,12 +1622,16 @@ public class SettingsUi : WindowMediatorSubscriberBase
if (selectedServer == _serverConfigurationManager.CurrentServer) if (selectedServer == _serverConfigurationManager.CurrentServer)
{ {
if (_apiController.IsConnected) if (_apiController.IsConnected)
UiSharedService.ColorTextWrapped("For any changes to be applied to the current service you need to reconnect to the service.", ImGuiColors.DalamudYellow); UiSharedService.ColorTextWrapped(L("Settings.Service.ReconnectWarning", "For any changes to be applied to the current service you need to reconnect to the service."), ImGuiColors.DalamudYellow);
} }
var characterAssignmentsTab = L("Settings.Service.Tabs.CharacterAssignments", "Character Assignments");
var secretKeyManagementTab = L("Settings.Service.Tabs.SecretKey", "Secret Key Management");
var serviceSettingsTab = L("Settings.Service.Tabs.ServiceSettings", "Service Settings");
if (ImGui.BeginTabBar("serverTabBar")) if (ImGui.BeginTabBar("serverTabBar"))
{ {
if (ImGui.BeginTabItem("Character Assignments")) if (ImGui.BeginTabItem(characterAssignmentsTab))
{ {
if (selectedServer.SecretKeys.Count > 0) if (selectedServer.SecretKeys.Count > 0)
{ {
@@ -1638,7 +1645,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
using (_ = _uiShared.IconFont.Push()) using (_ = _uiShared.IconFont.Push())
iconWidth = ImGui.CalcTextSize(FontAwesomeIcon.Trash.ToIconString()).X; iconWidth = ImGui.CalcTextSize(FontAwesomeIcon.Trash.ToIconString()).X;
UiSharedService.ColorTextWrapped("Characters listed here will connect with the specified secret key.", ImGuiColors.DalamudYellow); UiSharedService.ColorTextWrapped(L("Settings.Service.Character.Assignments.Description", "Characters listed here will connect with the specified secret key."), ImGuiColors.DalamudYellow);
int i = 0; int i = 0;
foreach (var item in selectedServer.Authentications.ToList()) foreach (var item in selectedServer.Authentications.ToList())
{ {
@@ -1653,7 +1660,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_uiShared.IconText(thisIsYou ? FontAwesomeIcon.Star : FontAwesomeIcon.None); _uiShared.IconText(thisIsYou ? FontAwesomeIcon.Star : FontAwesomeIcon.None);
if (thisIsYou) if (thisIsYou)
UiSharedService.AttachToolTip("Current character"); UiSharedService.AttachToolTip(L("Settings.Service.Character.Assignments.TooltipCurrent", "Current character"));
ImGui.SameLine(windowPadding + iconWidth + itemSpacing); ImGui.SameLine(windowPadding + iconWidth + itemSpacing);
float beforeName = ImGui.GetCursorPosX(); float beforeName = ImGui.GetCursorPosX();
@@ -1693,7 +1700,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
if (_uiShared.IconButton(FontAwesomeIcon.Trash)) if (_uiShared.IconButton(FontAwesomeIcon.Trash))
_serverConfigurationManager.RemoveCharacterFromServer(idx, item); _serverConfigurationManager.RemoveCharacterFromServer(idx, item);
UiSharedService.AttachToolTip("Delete character assignment"); UiSharedService.AttachToolTip(L("Settings.Service.Character.Assignments.DeleteTooltip", "Delete character assignment"));
i++; i++;
} }
@@ -1704,7 +1711,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
&& c.WorldId == _uiShared.WorldId && c.WorldId == _uiShared.WorldId
))) )))
{ {
if (_uiShared.IconTextButton(FontAwesomeIcon.User, "Add current character")) if (_uiShared.IconTextButton(FontAwesomeIcon.User, L("Settings.Service.Character.Assignments.AddCurrent", "Add current character")))
{ {
_serverConfigurationManager.AddCurrentCharacterToServer(idx); _serverConfigurationManager.AddCurrentCharacterToServer(idx);
} }
@@ -1713,19 +1720,19 @@ public class SettingsUi : WindowMediatorSubscriberBase
} }
else else
{ {
UiSharedService.ColorTextWrapped("You need to add a Secret Key first before adding Characters.", ImGuiColors.DalamudYellow); UiSharedService.ColorTextWrapped(L("Settings.Service.Character.Assignments.NoKeys", "You need to add a Secret Key first before adding Characters."), ImGuiColors.DalamudYellow);
} }
ImGui.EndTabItem(); ImGui.EndTabItem();
} }
if (ImGui.BeginTabItem("Secret Key Management")) if (ImGui.BeginTabItem(secretKeyManagementTab))
{ {
foreach (var item in selectedServer.SecretKeys.ToList()) foreach (var item in selectedServer.SecretKeys.ToList())
{ {
using var id = ImRaii.PushId("key" + item.Key); using var id = ImRaii.PushId("key" + item.Key);
var friendlyName = item.Value.FriendlyName; var friendlyName = item.Value.FriendlyName;
if (ImGui.InputText("Secret Key Display Name", ref friendlyName, 255)) if (ImGui.InputText(L("Settings.Service.SecretKey.DisplayName", "Secret Key Display Name"), ref friendlyName, 255))
{ {
item.Value.FriendlyName = friendlyName; item.Value.FriendlyName = friendlyName;
_serverConfigurationManager.Save(); _serverConfigurationManager.Save();
@@ -1733,7 +1740,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
var key = item.Value.Key; var key = item.Value.Key;
var keyInUse = selectedServer.Authentications.Exists(p => p.SecretKeyIdx == item.Key); var keyInUse = selectedServer.Authentications.Exists(p => p.SecretKeyIdx == item.Key);
if (keyInUse) ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3); if (keyInUse) ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3);
if (ImGui.InputText("Secret Key", ref key, 64, keyInUse ? ImGuiInputTextFlags.ReadOnly : default)) if (ImGui.InputText(L("Settings.Service.SecretKey.Value", "Secret Key"), ref key, 64, keyInUse ? ImGuiInputTextFlags.ReadOnly : default))
{ {
item.Value.Key = key; item.Value.Key = key;
_serverConfigurationManager.Save(); _serverConfigurationManager.Save();
@@ -1750,7 +1757,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
using (_ = ImRaii.Disabled(disableAssignment)) using (_ = ImRaii.Disabled(disableAssignment))
{ {
if (_uiShared.IconTextButton(FontAwesomeIcon.User, "Assign current character")) if (_uiShared.IconTextButton(FontAwesomeIcon.User, L("Settings.Service.SecretKey.AssignCurrent", "Assign current character")))
{ {
var currentAssignment = selectedServer.Authentications.Find(a => var currentAssignment = selectedServer.Authentications.Find(a =>
string.Equals(a.CharacterName, _uiShared.PlayerName, StringComparison.OrdinalIgnoreCase) string.Equals(a.CharacterName, _uiShared.PlayerName, StringComparison.OrdinalIgnoreCase)
@@ -1772,22 +1779,22 @@ public class SettingsUi : WindowMediatorSubscriberBase
} }
} }
if (!disableAssignment) if (!disableAssignment)
UiSharedService.AttachToolTip($"Use this secret key for {playerName} @ {playerWorldName}"); UiSharedService.AttachToolTip(L("Settings.Service.SecretKey.AssignTooltip", "Use this secret key for {0} @ {1}", playerName, playerWorldName));
} }
ImGui.SameLine(); ImGui.SameLine();
using var disableDelete = ImRaii.Disabled(keyInUse); using var disableDelete = ImRaii.Disabled(keyInUse);
if (_uiShared.IconTextButton(FontAwesomeIcon.Trash, "Delete Secret Key") && UiSharedService.CtrlPressed()) if (_uiShared.IconTextButton(FontAwesomeIcon.Trash, L("Settings.Service.SecretKey.Delete", "Delete Secret Key")) && UiSharedService.CtrlPressed())
{ {
selectedServer.SecretKeys.Remove(item.Key); selectedServer.SecretKeys.Remove(item.Key);
_serverConfigurationManager.Save(); _serverConfigurationManager.Save();
} }
if (!keyInUse) if (!keyInUse)
UiSharedService.AttachToolTip("Hold CTRL to delete this secret key entry"); UiSharedService.AttachToolTip(L("Settings.Service.SecretKey.DeleteTooltip", "Hold CTRL to delete this secret key entry"));
if (keyInUse) if (keyInUse)
{ {
UiSharedService.ColorTextWrapped("This key is currently assigned to a character and cannot be edited or deleted.", ImGuiColors.DalamudYellow); UiSharedService.ColorTextWrapped(L("Settings.Service.SecretKey.InUse", "This key is currently assigned to a character and cannot be edited or deleted."), ImGuiColors.DalamudYellow);
} }
if (item.Key != selectedServer.SecretKeys.Keys.LastOrDefault()) if (item.Key != selectedServer.SecretKeys.Keys.LastOrDefault())
@@ -1795,11 +1802,11 @@ public class SettingsUi : WindowMediatorSubscriberBase
} }
ImGui.Separator(); ImGui.Separator();
if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, "Add new Secret Key")) if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, L("Settings.Service.SecretKey.Add", "Add new Secret Key")))
{ {
selectedServer.SecretKeys.Add(selectedServer.SecretKeys.Any() ? selectedServer.SecretKeys.Max(p => p.Key) + 1 : 0, new SecretKey() selectedServer.SecretKeys.Add(selectedServer.SecretKeys.Any() ? selectedServer.SecretKeys.Max(p => p.Key) + 1 : 0, new SecretKey()
{ {
FriendlyName = "New Secret Key", FriendlyName = L("Settings.Service.SecretKey.NewFriendlyName", "New Secret Key"),
}); });
_serverConfigurationManager.Save(); _serverConfigurationManager.Save();
} }
@@ -1807,7 +1814,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
if (true) // Enable registration button for all servers if (true) // Enable registration button for all servers
{ {
ImGui.SameLine(); ImGui.SameLine();
if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, "Register a new Umbra account")) if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, L("Settings.Service.SecretKey.RegisterAccount", "Register a new Umbra account")))
{ {
_registrationInProgress = true; _registrationInProgress = true;
_ = Task.Run(async () => { _ = Task.Run(async () => {
@@ -1819,14 +1826,14 @@ public class SettingsUi : WindowMediatorSubscriberBase
_logger.LogWarning("Registration failed: {err}", reply.ErrorMessage); _logger.LogWarning("Registration failed: {err}", reply.ErrorMessage);
_registrationMessage = reply.ErrorMessage; _registrationMessage = reply.ErrorMessage;
if (_registrationMessage.IsNullOrEmpty()) if (_registrationMessage.IsNullOrEmpty())
_registrationMessage = "An unknown error occured. Please try again later."; _registrationMessage = L("Settings.Service.SecretKey.RegisterFailed", "An unknown error occured. Please try again later.");
return; return;
} }
_registrationMessage = "New account registered.\nPlease keep a copy of your secret key in case you need to reset your plugins, or to use it on another PC."; _registrationMessage = L("Settings.Service.SecretKey.RegisterSuccess", "New account registered.\nPlease keep a copy of your secret key in case you need to reset your plugins, or to use it on another PC.");
_registrationSuccess = true; _registrationSuccess = true;
selectedServer.SecretKeys.Add(selectedServer.SecretKeys.Any() ? selectedServer.SecretKeys.Max(p => p.Key) + 1 : 0, new SecretKey() selectedServer.SecretKeys.Add(selectedServer.SecretKeys.Any() ? selectedServer.SecretKeys.Max(p => p.Key) + 1 : 0, new SecretKey()
{ {
FriendlyName = reply.UID + $" (registered {DateTime.Now:yyyy-MM-dd})", FriendlyName = L("Settings.Service.SecretKey.RegisteredFriendlyName", "{0} (registered {1})", reply.UID, DateTime.Now.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)),
Key = reply.SecretKey ?? "" Key = reply.SecretKey ?? ""
}); });
_serverConfigurationManager.Save(); _serverConfigurationManager.Save();
@@ -1835,7 +1842,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
{ {
_logger.LogWarning(ex, "Registration failed"); _logger.LogWarning(ex, "Registration failed");
_registrationSuccess = false; _registrationSuccess = false;
_registrationMessage = "An unknown error occured. Please try again later."; _registrationMessage = L("Settings.Service.SecretKey.RegisterFailed", "An unknown error occured. Please try again later.");
} }
finally finally
{ {
@@ -1845,7 +1852,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
} }
if (_registrationInProgress) if (_registrationInProgress)
{ {
ImGui.TextUnformatted("Sending request..."); ImGui.TextUnformatted(L("Settings.Service.SecretKey.Registering", "Sending request..."));
} }
else if (!_registrationMessage.IsNullOrEmpty()) else if (!_registrationMessage.IsNullOrEmpty())
{ {
@@ -1859,39 +1866,39 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.EndTabItem(); ImGui.EndTabItem();
} }
if (ImGui.BeginTabItem("Service Settings")) if (ImGui.BeginTabItem(serviceSettingsTab + "###serviceSettingsInnerTab"))
{ {
var serverName = selectedServer.ServerName; var serverName = selectedServer.ServerName;
var serverUri = selectedServer.ServerUri; var serverUri = selectedServer.ServerUri;
var isMain = string.Equals(serverName, ApiController.UmbraServer, StringComparison.OrdinalIgnoreCase); var isMain = string.Equals(serverName, ApiController.UmbraServer, StringComparison.OrdinalIgnoreCase);
var flags = isMain ? ImGuiInputTextFlags.ReadOnly : ImGuiInputTextFlags.None; var flags = isMain ? ImGuiInputTextFlags.ReadOnly : ImGuiInputTextFlags.None;
if (ImGui.InputText("Service URI", ref serverUri, 255, flags)) if (ImGui.InputText(L("Settings.Service.ServiceTab.Uri", "Service URI"), ref serverUri, 255, flags))
{ {
selectedServer.ServerUri = serverUri; selectedServer.ServerUri = serverUri;
} }
if (isMain) if (isMain)
{ {
_uiShared.DrawHelpText("You cannot edit the URI of the main service."); _uiShared.DrawHelpText(L("Settings.Service.ServiceTab.UriReadOnlyHint", "You cannot edit the URI of the main service."));
} }
if (ImGui.InputText("Service Name", ref serverName, 255, flags)) if (ImGui.InputText(L("Settings.Service.ServiceTab.Name", "Service Name"), ref serverName, 255, flags))
{ {
selectedServer.ServerName = serverName; selectedServer.ServerName = serverName;
_serverConfigurationManager.Save(); _serverConfigurationManager.Save();
} }
if (isMain) if (isMain)
{ {
_uiShared.DrawHelpText("You cannot edit the name of the main service."); _uiShared.DrawHelpText(L("Settings.Service.ServiceTab.NameReadOnlyHint", "You cannot edit the name of the main service."));
} }
if (!isMain && selectedServer != _serverConfigurationManager.CurrentServer) if (!isMain && selectedServer != _serverConfigurationManager.CurrentServer)
{ {
if (_uiShared.IconTextButton(FontAwesomeIcon.Trash, "Delete Service") && UiSharedService.CtrlPressed()) if (_uiShared.IconTextButton(FontAwesomeIcon.Trash, L("Settings.Service.ServiceTab.Delete", "Delete Service")) && UiSharedService.CtrlPressed())
{ {
_serverConfigurationManager.DeleteServer(selectedServer); _serverConfigurationManager.DeleteServer(selectedServer);
} }
_uiShared.DrawHelpText("Hold CTRL to delete this service"); _uiShared.DrawHelpText(L("Settings.Service.ServiceTab.DeleteHint", "Hold CTRL to delete this service"));
} }
ImGui.EndTabItem(); ImGui.EndTabItem();
} }
@@ -1942,13 +1949,15 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.EndTabItem(); ImGui.EndTabItem();
} }
if (ImGui.BeginTabItem("Transfers")) var transfersTabLabel = L("Settings.Transfers.Current.Tab", "Transfers");
if (ImGui.BeginTabItem(transfersTabLabel + "###mainTransfersTab"))
{ {
DrawCurrentTransfers(); DrawCurrentTransfers();
ImGui.EndTabItem(); ImGui.EndTabItem();
} }
if (ImGui.BeginTabItem("Service Settings")) var serviceSettingsTabLabel = L("Settings.Service.Tabs.ServiceSettings", "Service Settings");
if (ImGui.BeginTabItem(serviceSettingsTabLabel + "###mainServiceSettingsTab"))
{ {
ImGui.BeginDisabled(_registrationInProgress); ImGui.BeginDisabled(_registrationInProgress);
DrawServerConfiguration(); DrawServerConfiguration();
@@ -1956,7 +1965,8 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.EndDisabled(); ImGui.EndDisabled();
} }
if (ImGui.BeginTabItem("Advanced")) var advancedTabLabel = L("Settings.Advanced.Tab", "Advanced");
if (ImGui.BeginTabItem(advancedTabLabel + "###advancedTab"))
{ {
DrawAdvanced(); DrawAdvanced();
ImGui.EndTabItem(); ImGui.EndTabItem();

View File

@@ -21,6 +21,7 @@ using MareSynchronos.Services.Mediator;
using MareSynchronos.Services.ServerConfiguration; using MareSynchronos.Services.ServerConfiguration;
using MareSynchronos.WebAPI; using MareSynchronos.WebAPI;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Globalization;
using System.Numerics; using System.Numerics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
@@ -768,15 +769,19 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
var check = FontAwesomeIcon.Check; var check = FontAwesomeIcon.Check;
var cross = FontAwesomeIcon.SquareXmark; var cross = FontAwesomeIcon.SquareXmark;
var availableTemplate = Localize("Settings.Plugins.Tooltip.Available", "{0} is available and up to date.");
var unavailableTemplate = Localize("Settings.Plugins.Tooltip.Unavailable", "{0} is unavailable or not up to date.");
string FormatTooltip(bool exists, string pluginName) => string.Format(CultureInfo.CurrentCulture, exists ? availableTemplate : unavailableTemplate, pluginName);
if (intro) if (intro)
{ {
ImGui.SetWindowFontScale(0.8f); ImGui.SetWindowFontScale(0.8f);
BigText("Mandatory Plugins"); BigText(Localize("Settings.Plugins.MandatoryHeading", "Mandatory Plugins"));
ImGui.SetWindowFontScale(1.0f); ImGui.SetWindowFontScale(1.0f);
} }
else else
{ {
ImGui.TextUnformatted("Mandatory Plugins:"); ImGui.TextUnformatted(Localize("Settings.Plugins.MandatoryLabel", "Mandatory Plugins:"));
ImGui.SameLine(); ImGui.SameLine();
} }
@@ -784,23 +789,23 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
ImGui.SameLine(); ImGui.SameLine();
IconText(_penumbraExists ? check : cross, GetBoolColor(_penumbraExists)); IconText(_penumbraExists ? check : cross, GetBoolColor(_penumbraExists));
ImGui.SameLine(); ImGui.SameLine();
AttachToolTip($"Penumbra is " + (_penumbraExists ? "available and up to date." : "unavailable or not up to date.")); AttachToolTip(FormatTooltip(_penumbraExists, "Penumbra"));
ImGui.TextUnformatted("Glamourer"); ImGui.TextUnformatted("Glamourer");
ImGui.SameLine(); ImGui.SameLine();
IconText(_glamourerExists ? check : cross, GetBoolColor(_glamourerExists)); IconText(_glamourerExists ? check : cross, GetBoolColor(_glamourerExists));
AttachToolTip($"Glamourer is " + (_glamourerExists ? "available and up to date." : "unavailable or not up to date.")); AttachToolTip(FormatTooltip(_glamourerExists, "Glamourer"));
if (intro) if (intro)
{ {
ImGui.SetWindowFontScale(0.8f); ImGui.SetWindowFontScale(0.8f);
BigText("Optional Addons"); BigText(Localize("Settings.Plugins.OptionalHeading", "Optional Addons"));
ImGui.SetWindowFontScale(1.0f); ImGui.SetWindowFontScale(1.0f);
UiSharedService.TextWrapped("These addons are not required for basic operation, but without them you may not see others as intended."); UiSharedService.TextWrapped(Localize("Settings.Plugins.OptionalDescription", "These addons are not required for basic operation, but without them you may not see others as intended."));
} }
else else
{ {
ImGui.TextUnformatted("Optional Addons:"); ImGui.TextUnformatted(Localize("Settings.Plugins.OptionalLabel", "Optional Addons:"));
ImGui.SameLine(); ImGui.SameLine();
} }
@@ -810,7 +815,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
ImGui.SameLine(); ImGui.SameLine();
IconText(_heelsExists ? check : cross, GetBoolColor(_heelsExists)); IconText(_heelsExists ? check : cross, GetBoolColor(_heelsExists));
ImGui.SameLine(); ImGui.SameLine();
AttachToolTip($"SimpleHeels is " + (_heelsExists ? "available and up to date." : "unavailable or not up to date.")); AttachToolTip(FormatTooltip(_heelsExists, "SimpleHeels"));
ImGui.Spacing(); ImGui.Spacing();
ImGui.SameLine(); ImGui.SameLine();
@@ -818,7 +823,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
ImGui.SameLine(); ImGui.SameLine();
IconText(_customizePlusExists ? check : cross, GetBoolColor(_customizePlusExists)); IconText(_customizePlusExists ? check : cross, GetBoolColor(_customizePlusExists));
ImGui.SameLine(); ImGui.SameLine();
AttachToolTip($"Customize+ is " + (_customizePlusExists ? "available and up to date." : "unavailable or not up to date.")); AttachToolTip(FormatTooltip(_customizePlusExists, "Customize+"));
ImGui.Spacing(); ImGui.Spacing();
ImGui.SameLine(); ImGui.SameLine();
@@ -826,7 +831,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
ImGui.SameLine(); ImGui.SameLine();
IconText(_honorificExists ? check : cross, GetBoolColor(_honorificExists)); IconText(_honorificExists ? check : cross, GetBoolColor(_honorificExists));
ImGui.SameLine(); ImGui.SameLine();
AttachToolTip($"Honorific is " + (_honorificExists ? "available and up to date." : "unavailable or not up to date.")); AttachToolTip(FormatTooltip(_honorificExists, "Honorific"));
ImGui.Spacing(); ImGui.Spacing();
ImGui.SameLine(); ImGui.SameLine();
@@ -834,7 +839,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
ImGui.SameLine(); ImGui.SameLine();
IconText(_petNamesExists ? check : cross, GetBoolColor(_petNamesExists)); IconText(_petNamesExists ? check : cross, GetBoolColor(_petNamesExists));
ImGui.SameLine(); ImGui.SameLine();
AttachToolTip($"PetNicknames is " + (_petNamesExists ? "available and up to date." : "unavailable or not up to date.")); AttachToolTip(FormatTooltip(_petNamesExists, "PetNicknames"));
ImGui.Spacing(); ImGui.Spacing();
ImGui.SetCursorPosX(alignPos); ImGui.SetCursorPosX(alignPos);
@@ -842,7 +847,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
ImGui.SameLine(); ImGui.SameLine();
IconText(_moodlesExists ? check : cross, GetBoolColor(_moodlesExists)); IconText(_moodlesExists ? check : cross, GetBoolColor(_moodlesExists));
ImGui.SameLine(); ImGui.SameLine();
AttachToolTip($"Moodles is " + (_moodlesExists ? "available and up to date." : "unavailable or not up to date.")); AttachToolTip(FormatTooltip(_moodlesExists, "Moodles"));
ImGui.Spacing(); ImGui.Spacing();
ImGui.SameLine(); ImGui.SameLine();
@@ -850,12 +855,12 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
ImGui.SameLine(); ImGui.SameLine();
IconText(_brioExists ? check : cross, GetBoolColor(_brioExists)); IconText(_brioExists ? check : cross, GetBoolColor(_brioExists));
ImGui.SameLine(); ImGui.SameLine();
AttachToolTip($"Brio is " + (_moodlesExists ? "available and up to date." : "unavailable or not up to date.")); AttachToolTip(FormatTooltip(_brioExists, "Brio"));
ImGui.Spacing(); ImGui.Spacing();
if (!_penumbraExists || !_glamourerExists) if (!_penumbraExists || !_glamourerExists)
{ {
ImGui.TextColored(ImGuiColors.DalamudRed, "You need to install both Penumbra and Glamourer and keep them up to date to use Umbra."); ImGui.TextColored(ImGuiColors.DalamudRed, Localize("Settings.Plugins.WarningMandatoryMissing", "You need to install both Penumbra and Glamourer and keep them up to date to use Umbra."));
return false; return false;
} }