using System; using System.Collections.Generic; using System.Linq; using UnityEditor.Localization; using UnityEngine; using Crowdin.Plugin.Models.Settings; using Crowdin.Plugin.Server_API.Helpers; namespace Crowdin.Editor { public class TableSelector : IDisposable { public bool AllTablesSelected => currentIndex is 0; private int currentIndex; private Vector2 scrollPosition; private readonly Dictionary tableStates = new(); private readonly TablesSelection rawSettings; private readonly List allTableNames; private TableSelector( TablesSelection settings, IEnumerable allTableNames) { rawSettings = settings; this.allTableNames = allTableNames.ToList(); currentIndex = settings.allSelected ? 0 : 1; var existingTableNames = new HashSet(this.allTableNames); foreach (string selectedTable in settings.selectedTables) { // A table saved in "Selected tables" may have since been renamed or removed from the // project. Skip it so it can't linger as an unchecked, un-removable selection that // later operations still try to resolve against a now-missing table. if (existingTableNames.Contains(selectedTable)) { tableStates[selectedTable] = true; } } } public static TableSelector CreateForStringTables() { return new TableSelector( SettingsHelper.GetStringTablesSelection(), LocalizationEditorSettings .GetStringTableCollections() .Select(collection => collection.TableCollectionName)); } public static TableSelector CreateForAssetTables() { return new TableSelector( SettingsHelper.GetAssetTablesSelection(), LocalizationEditorSettings .GetAssetTableCollections() .Select(collection => collection.TableCollectionName)); } public void DrawLayout() { const int WidthForText = 60; const int MaxElementsNoScrolling = 10; GUILayout.Space(10); currentIndex = GUILayout.SelectionGrid(currentIndex, new[] { " All tables", " Selected tables" }, 1, "radio"); if (currentIndex is 1) { if (allTableNames.Count > MaxElementsNoScrolling) { scrollPosition = GUILayout.BeginScrollView(scrollPosition); } foreach (string tableName in allTableNames) { bool currentState = tableStates.TryGetValue(tableName, out bool state) && state; GUILayout.BeginHorizontal(); GUILayout.Space(23); tableStates[tableName] = GUILayout.Toggle(currentState, LimitString(tableName, WidthForText)); GUILayout.EndHorizontal(); } if (allTableNames.Count > MaxElementsNoScrolling) { GUILayout.EndScrollView(); } } GUILayout.Space(10); } private static string LimitString(string text, int limit) { if (text.Length <= limit) return text; return text[..limit] + "..."; } public IEnumerable GetSelectedTables() { return tableStates .Where(kvPair => kvPair.Value) .Select(kvPair => kvPair.Key); } /// The concrete list of table names an operation should act on: every known table when /// "All tables" is selected, otherwise just the checked ones. Filtered against /// allTableNames so a selection saved before a table was renamed or removed can't resolve /// to a table that no longer exists. public IReadOnlyList ResolveTables() { IEnumerable tables = AllTablesSelected ? allTableNames : GetSelectedTables(); return tables.Where(allTableNames.Contains).ToList(); } public void SaveSettings() { rawSettings.allSelected = AllTablesSelected; rawSettings.selectedTables = GetSelectedTables().ToList(); } public void Dispose() { SaveSettings(); } } }