mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
fix(avalonia): fix enum translation in settings pages
- Add DropdownDataGeneric<T> helper for translated enum dropdowns - Fix GeneralSettingsViewModel to use DropdownDataGeneric for enums: - SearchWindowScreens, SearchWindowAligns, SearchPrecisionScore, LastQueryMode - Fix ThemeSettingsViewModel to use DropdownDataGeneric for ColorSchemes - Fix PluginsSettingsViewModel DisplayMode to use correct translation keys: - DisplayModeOnOff, DisplayModePriority, DisplayModeSearchDelay, DisplayModeHomeOnOff - Add missing translation keys to en.xaml for plugin types and display modes - Update XAML bindings to use DisplayMemberPath/SelectedValuePath pattern
This commit is contained in:
parent
8ee32dfab7
commit
830023513f
8 changed files with 166 additions and 85 deletions
|
|
@ -0,0 +1,48 @@
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Flow.Launcher.Avalonia.ViewModel.SettingPages;
|
||||
|
||||
public partial class DropdownDataGeneric<T> : ObservableObject where T : struct, Enum
|
||||
{
|
||||
private readonly string _keyPrefix;
|
||||
private readonly Func<T, string> _getData;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _display = string.Empty;
|
||||
|
||||
public T Value { get; }
|
||||
|
||||
public DropdownDataGeneric(T value, string keyPrefix, Func<T, string> getData)
|
||||
{
|
||||
Value = value;
|
||||
_keyPrefix = keyPrefix;
|
||||
_getData = getData;
|
||||
UpdateLabels();
|
||||
}
|
||||
|
||||
public void UpdateLabels()
|
||||
{
|
||||
var key = _keyPrefix + _getData(Value);
|
||||
Display = App.API?.GetTranslation(key) ?? key;
|
||||
}
|
||||
|
||||
public static List<DropdownDataGeneric<T>> GetEnumData(string keyPrefix, Func<T, string>? getData = null)
|
||||
{
|
||||
getData ??= (v => v.ToString());
|
||||
return Enum.GetValues<T>()
|
||||
.Select(v => new DropdownDataGeneric<T>(v, keyPrefix, getData))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public static class DropdownDataGeneric
|
||||
{
|
||||
public static List<DropdownDataGeneric<T>> GetEnumData<T>(string keyPrefix, Func<T, string>? getData = null) where T : struct, Enum
|
||||
{
|
||||
return DropdownDataGeneric<T>.GetEnumData(keyPrefix, getData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -47,10 +47,20 @@ public partial class GeneralSettingsViewModel : ObservableObject
|
|||
_settings.Language = value.LanguageCode;
|
||||
_i18n.ChangeLanguage(value.LanguageCode);
|
||||
OnPropertyChanged();
|
||||
UpdateLabels();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLabels()
|
||||
{
|
||||
SearchWindowScreens.ForEach(x => x.UpdateLabels());
|
||||
SearchWindowAligns.ForEach(x => x.UpdateLabels());
|
||||
SearchPrecisionScores.ForEach(x => x.UpdateLabels());
|
||||
LastQueryModes.ForEach(x => x.UpdateLabels());
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Startup Settings
|
||||
|
|
@ -168,7 +178,7 @@ public partial class GeneralSettingsViewModel : ObservableObject
|
|||
#region Search Window Position
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<EnumDisplayItem<SearchWindowScreens>> _searchWindowScreens = new();
|
||||
private List<DropdownDataGeneric<SearchWindowScreens>> _searchWindowScreens = new();
|
||||
|
||||
public SearchWindowScreens SelectedSearchWindowScreen
|
||||
{
|
||||
|
|
@ -181,7 +191,7 @@ public partial class GeneralSettingsViewModel : ObservableObject
|
|||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<EnumDisplayItem<SearchWindowAligns>> _searchWindowAligns = new();
|
||||
private List<DropdownDataGeneric<SearchWindowAligns>> _searchWindowAligns = new();
|
||||
|
||||
public SearchWindowAligns SelectedSearchWindowAlign
|
||||
{
|
||||
|
|
@ -198,7 +208,7 @@ public partial class GeneralSettingsViewModel : ObservableObject
|
|||
#region Query Settings
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<EnumDisplayItem<SearchPrecisionScore>> _searchPrecisionScores = new();
|
||||
private List<DropdownDataGeneric<SearchPrecisionScore>> _searchPrecisionScores = new();
|
||||
|
||||
public SearchPrecisionScore SelectedSearchPrecision
|
||||
{
|
||||
|
|
@ -211,7 +221,8 @@ public partial class GeneralSettingsViewModel : ObservableObject
|
|||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<EnumDisplayItem<LastQueryMode>> _lastQueryModes = new();
|
||||
private List<DropdownDataGeneric<LastQueryMode>> _lastQueryModes = new();
|
||||
|
||||
|
||||
public LastQueryMode SelectedLastQueryMode
|
||||
{
|
||||
|
|
@ -361,39 +372,20 @@ public partial class GeneralSettingsViewModel : ObservableObject
|
|||
|
||||
private void LoadSearchWindowOptions()
|
||||
{
|
||||
SearchWindowScreens = new ObservableCollection<EnumDisplayItem<SearchWindowScreens>>(
|
||||
Enum.GetValues<SearchWindowScreens>().Select(v => new EnumDisplayItem<SearchWindowScreens>(v, v.ToString())));
|
||||
|
||||
SearchWindowAligns = new ObservableCollection<EnumDisplayItem<SearchWindowAligns>>(
|
||||
Enum.GetValues<SearchWindowAligns>().Select(v => new EnumDisplayItem<SearchWindowAligns>(v, v.ToString())));
|
||||
SearchWindowScreens = DropdownDataGeneric<SearchWindowScreens>.GetEnumData("SearchWindowScreen");
|
||||
SearchWindowAligns = DropdownDataGeneric<SearchWindowAligns>.GetEnumData("SearchWindowAlign");
|
||||
}
|
||||
|
||||
private void LoadSearchPrecisionOptions()
|
||||
{
|
||||
SearchPrecisionScores = new ObservableCollection<EnumDisplayItem<SearchPrecisionScore>>(
|
||||
Enum.GetValues<SearchPrecisionScore>().Select(v => new EnumDisplayItem<SearchPrecisionScore>(v, v.ToString())));
|
||||
SearchPrecisionScores = DropdownDataGeneric<SearchPrecisionScore>.GetEnumData("SearchPrecision");
|
||||
}
|
||||
|
||||
private void LoadLastQueryModeOptions()
|
||||
{
|
||||
LastQueryModes = new ObservableCollection<EnumDisplayItem<LastQueryMode>>(
|
||||
Enum.GetValues<LastQueryMode>().Select(v => new EnumDisplayItem<LastQueryMode>(v, v.ToString())));
|
||||
LastQueryModes = DropdownDataGeneric<LastQueryMode>.GetEnumData("LastQuery");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for displaying enum values in ComboBoxes
|
||||
/// </summary>
|
||||
public class EnumDisplayItem<T> where T : Enum
|
||||
{
|
||||
public T Value { get; }
|
||||
public string Display { get; }
|
||||
|
||||
public EnumDisplayItem(T value, string display)
|
||||
{
|
||||
Value = value;
|
||||
Display = display;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,11 +31,23 @@ public partial class PluginsSettingsViewModel : ObservableObject
|
|||
|
||||
LoadDisplayModes();
|
||||
LoadPlugins();
|
||||
|
||||
_settings.PropertyChanged += (s, e) =>
|
||||
{
|
||||
if (e.PropertyName == nameof(Settings.Language))
|
||||
{
|
||||
foreach (var item in DisplayModes)
|
||||
{
|
||||
item.UpdateLabels();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<PluginItemViewModel> _plugins = new();
|
||||
|
||||
|
||||
[ObservableProperty]
|
||||
private string _searchText = string.Empty;
|
||||
|
||||
|
|
@ -69,18 +81,35 @@ public partial class PluginsSettingsViewModel : ObservableObject
|
|||
HomeOnOff
|
||||
}
|
||||
|
||||
public class DisplayModeItem
|
||||
public partial class DisplayModeItem : ObservableObject
|
||||
{
|
||||
private readonly Internationalization _i18n;
|
||||
public DisplayMode Value { get; }
|
||||
public string Display { get; }
|
||||
|
||||
public DisplayModeItem(DisplayMode value, string display)
|
||||
[ObservableProperty]
|
||||
private string _display;
|
||||
|
||||
public DisplayModeItem(DisplayMode value, Internationalization i18n)
|
||||
{
|
||||
Value = value;
|
||||
Display = display;
|
||||
_i18n = i18n;
|
||||
UpdateLabels();
|
||||
}
|
||||
|
||||
public void UpdateLabels()
|
||||
{
|
||||
Display = Value switch
|
||||
{
|
||||
DisplayMode.OnOff => _i18n.GetTranslation("DisplayModeOnOff"),
|
||||
DisplayMode.Priority => _i18n.GetTranslation("DisplayModePriority"),
|
||||
DisplayMode.SearchDelay => _i18n.GetTranslation("DisplayModeSearchDelay"),
|
||||
DisplayMode.HomeOnOff => _i18n.GetTranslation("DisplayModeHomeOnOff"),
|
||||
_ => Value.ToString()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[ObservableProperty]
|
||||
private List<DisplayModeItem> _displayModes = new();
|
||||
|
||||
|
|
@ -109,16 +138,17 @@ public partial class PluginsSettingsViewModel : ObservableObject
|
|||
{
|
||||
DisplayModes = new List<DisplayModeItem>
|
||||
{
|
||||
new(DisplayMode.OnOff, _i18n.GetTranslation("pluginDisplayOnOff")),
|
||||
new(DisplayMode.Priority, _i18n.GetTranslation("pluginDisplayPriority")),
|
||||
new(DisplayMode.SearchDelay, _i18n.GetTranslation("pluginDisplaySearchDelay")),
|
||||
new(DisplayMode.HomeOnOff, _i18n.GetTranslation("pluginDisplayHomeOnOff"))
|
||||
new(DisplayMode.OnOff, _i18n),
|
||||
new(DisplayMode.Priority, _i18n),
|
||||
new(DisplayMode.SearchDelay, _i18n),
|
||||
new(DisplayMode.HomeOnOff, _i18n)
|
||||
};
|
||||
|
||||
// Set default
|
||||
SelectedDisplayModeItem = DisplayModes[0];
|
||||
}
|
||||
|
||||
|
||||
private void UpdateDisplayModeFlags(DisplayMode mode)
|
||||
{
|
||||
IsOnOffSelected = mode == DisplayMode.OnOff;
|
||||
|
|
|
|||
|
|
@ -2,45 +2,59 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
|||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Avalonia.Resource;
|
||||
using FluentAvalonia.Styling;
|
||||
using Avalonia;
|
||||
using Avalonia.Styling;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using AvaloniaI18n = Flow.Launcher.Avalonia.Resource.Internationalization;
|
||||
|
||||
namespace Flow.Launcher.Avalonia.ViewModel.SettingPages;
|
||||
|
||||
public partial class ThemeSettingsViewModel : ObservableObject
|
||||
{
|
||||
private readonly Settings _settings;
|
||||
private readonly AvaloniaI18n _i18n;
|
||||
|
||||
public ThemeSettingsViewModel()
|
||||
{
|
||||
_settings = Ioc.Default.GetRequiredService<Settings>();
|
||||
_i18n = Ioc.Default.GetRequiredService<AvaloniaI18n>();
|
||||
ColorSchemeOptions = DropdownDataGeneric<ColorSchemes>.GetEnumData("ColorScheme");
|
||||
|
||||
_settings.PropertyChanged += (s, e) =>
|
||||
{
|
||||
if (e.PropertyName == nameof(Settings.Language))
|
||||
{
|
||||
UpdateLabels();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public List<string> ThemeVariants => new() { "System", "Light", "Dark" };
|
||||
public List<DropdownDataGeneric<ColorSchemes>> ColorSchemeOptions { get; }
|
||||
|
||||
public string SelectedThemeVariant
|
||||
public ColorSchemes SelectedColorScheme
|
||||
{
|
||||
get => _settings.Theme switch
|
||||
{
|
||||
"Light" => "Light",
|
||||
"Dark" => "Dark",
|
||||
_ => "System"
|
||||
};
|
||||
get => Enum.TryParse<ColorSchemes>(_settings.Theme, out var result) ? result : ColorSchemes.System;
|
||||
set
|
||||
{
|
||||
if (value != SelectedThemeVariant)
|
||||
if (SelectedColorScheme != value)
|
||||
{
|
||||
_settings.Theme = value;
|
||||
ApplyTheme(value);
|
||||
var themeString = value.ToString();
|
||||
_settings.Theme = themeString;
|
||||
ApplyTheme(themeString);
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLabels()
|
||||
{
|
||||
ColorSchemeOptions.ForEach(x => x.UpdateLabels());
|
||||
}
|
||||
|
||||
private void ApplyTheme(string variant)
|
||||
|
||||
{
|
||||
if (Application.Current == null) return;
|
||||
|
||||
|
|
|
|||
|
|
@ -72,26 +72,20 @@
|
|||
IsExpanded="False">
|
||||
<ui:SettingsExpander.Footer>
|
||||
<ComboBox ItemsSource="{Binding SearchWindowScreens}"
|
||||
SelectedItem="{Binding SelectedSearchWindowScreen, Mode=TwoWay}"
|
||||
MinWidth="200">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:EnumDisplayItem`1">
|
||||
<TextBlock Text="{Binding Display}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
SelectedValue="{Binding SelectedSearchWindowScreen, Mode=TwoWay}"
|
||||
SelectedValueBinding="{Binding Value}"
|
||||
DisplayMemberBinding="{Binding Display}"
|
||||
MinWidth="200" />
|
||||
|
||||
</ui:SettingsExpander.Footer>
|
||||
<ui:SettingsExpanderItem Content="{i18n:Localize SearchWindowAlign}">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ComboBox ItemsSource="{Binding SearchWindowAligns}"
|
||||
SelectedItem="{Binding SelectedSearchWindowAlign, Mode=TwoWay}"
|
||||
MinWidth="160">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:EnumDisplayItem`1">
|
||||
<TextBlock Text="{Binding Display}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
SelectedValue="{Binding SelectedSearchWindowAlign, Mode=TwoWay}"
|
||||
SelectedValueBinding="{Binding Value}"
|
||||
DisplayMemberBinding="{Binding Display}"
|
||||
MinWidth="160" />
|
||||
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
</ui:SettingsExpander>
|
||||
|
|
@ -138,27 +132,21 @@
|
|||
IsExpanded="False">
|
||||
<ui:SettingsExpander.Footer>
|
||||
<ComboBox ItemsSource="{Binding SearchPrecisionScores}"
|
||||
SelectedItem="{Binding SelectedSearchPrecision, Mode=TwoWay}"
|
||||
MinWidth="150">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:EnumDisplayItem`1">
|
||||
<TextBlock Text="{Binding Display}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
SelectedValue="{Binding SelectedSearchPrecision, Mode=TwoWay}"
|
||||
SelectedValueBinding="{Binding Value}"
|
||||
DisplayMemberBinding="{Binding Display}"
|
||||
MinWidth="150" />
|
||||
|
||||
</ui:SettingsExpander.Footer>
|
||||
<ui:SettingsExpanderItem Content="{i18n:Localize lastQueryMode}"
|
||||
Description="{i18n:Localize lastQueryModeToolTip}">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ComboBox ItemsSource="{Binding LastQueryModes}"
|
||||
SelectedItem="{Binding SelectedLastQueryMode, Mode=TwoWay}"
|
||||
MinWidth="180">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:EnumDisplayItem`1">
|
||||
<TextBlock Text="{Binding Display}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
SelectedValue="{Binding SelectedLastQueryMode, Mode=TwoWay}"
|
||||
SelectedValueBinding="{Binding Value}"
|
||||
DisplayMemberBinding="{Binding Display}"
|
||||
MinWidth="180" />
|
||||
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
</ui:SettingsExpander>
|
||||
|
|
|
|||
|
|
@ -33,12 +33,13 @@
|
|||
<!-- Filters and Search -->
|
||||
<Grid Grid.Row="1" ColumnDefinitions="Auto,*,Auto" Margin="0,0,0,10">
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="15" VerticalAlignment="Center">
|
||||
<CheckBox IsChecked="{Binding ShowDotNet}" Content="C# / .Net" />
|
||||
<CheckBox IsChecked="{Binding ShowPython}" Content="Python" />
|
||||
<CheckBox IsChecked="{Binding ShowNodeJs}" Content="Node.js" />
|
||||
<CheckBox IsChecked="{Binding ShowExecutable}" Content="Executable" />
|
||||
<CheckBox IsChecked="{Binding ShowDotNet}" Content="{i18n:Localize pluginType_CSharp}" />
|
||||
<CheckBox IsChecked="{Binding ShowPython}" Content="{i18n:Localize pluginType_Python}" />
|
||||
<CheckBox IsChecked="{Binding ShowNodeJs}" Content="{i18n:Localize pluginType_Nodejs}" />
|
||||
<CheckBox IsChecked="{Binding ShowExecutable}" Content="{i18n:Localize pluginType_Executable}" />
|
||||
</StackPanel>
|
||||
|
||||
|
||||
<TextBox Grid.Column="2"
|
||||
Width="250"
|
||||
Text="{Binding FilterText, Mode=TwoWay}"
|
||||
|
|
|
|||
|
|
@ -16,12 +16,15 @@
|
|||
<ui:SettingsExpander Header="{i18n:Localize theme}"
|
||||
IconSource="DarkTheme">
|
||||
<ui:SettingsExpander.Footer>
|
||||
<ComboBox ItemsSource="{Binding ThemeVariants}"
|
||||
SelectedItem="{Binding SelectedThemeVariant}"
|
||||
<ComboBox ItemsSource="{Binding ColorSchemeOptions}"
|
||||
SelectedValue="{Binding SelectedColorScheme}"
|
||||
DisplayMemberBinding="{Binding Display}"
|
||||
SelectedValueBinding="{Binding Value}"
|
||||
MinWidth="150" />
|
||||
</ui:SettingsExpander.Footer>
|
||||
</ui:SettingsExpander>
|
||||
|
||||
|
||||
<!-- Glyph Icons -->
|
||||
<ui:SettingsExpander Header="{i18n:Localize useGlyphUI}"
|
||||
Description="{i18n:Localize useGlyphUIEffect}"
|
||||
|
|
|
|||
|
|
@ -226,6 +226,11 @@
|
|||
<system:String x:Key="pluginStore_RecentlyUpdated">Recently Updated</system:String>
|
||||
<system:String x:Key="pluginStore_None">Plugins</system:String>
|
||||
<system:String x:Key="pluginStore_Installed">Installed</system:String>
|
||||
<system:String x:Key="pluginType_CSharp">C# / .Net</system:String>
|
||||
<system:String x:Key="pluginType_Python">Python</system:String>
|
||||
<system:String x:Key="pluginType_Nodejs">Node.js</system:String>
|
||||
<system:String x:Key="pluginType_Executable">Executable</system:String>
|
||||
|
||||
<system:String x:Key="refresh">Refresh</system:String>
|
||||
<system:String x:Key="installbtn">Install</system:String>
|
||||
<system:String x:Key="uninstallbtn">Uninstall</system:String>
|
||||
|
|
|
|||
Loading…
Reference in a new issue