Browse Source

Avalonia Updates

Ruben 1 year ago
parent
commit
bbd885e9b2
46 changed files with 1158 additions and 117 deletions
  1. 1 2
      src/PicView.Avalonia.Win32/App.axaml
  2. 0 1
      src/PicView.Avalonia.Win32/PicView.Avalonia.Win32.csproj
  3. BIN
      src/PicView.Avalonia/Assets/Fonts/Roboto-Black.ttf
  4. BIN
      src/PicView.Avalonia/Assets/Fonts/Roboto-Bold.ttf
  5. BIN
      src/PicView.Avalonia/Assets/Fonts/Roboto-Italic.ttf
  6. BIN
      src/PicView.Avalonia/Assets/Fonts/Roboto-Light.ttf
  7. BIN
      src/PicView.Avalonia/Assets/Fonts/Roboto-LightItalic.ttf
  8. BIN
      src/PicView.Avalonia/Assets/Fonts/Roboto-Medium.ttf
  9. BIN
      src/PicView.Avalonia/Assets/Fonts/Roboto-MediumItalic.ttf
  10. BIN
      src/PicView.Avalonia/Assets/Fonts/Roboto-Regular.ttf
  11. BIN
      src/PicView.Avalonia/Assets/Fonts/Roboto-Thin.ttf
  12. BIN
      src/PicView.Avalonia/Assets/Fonts/Roboto-ThinItalic.ttf
  13. BIN
      src/PicView.Avalonia/Assets/Fonts/texgyreheros-bold.otf
  14. BIN
      src/PicView.Avalonia/Assets/Fonts/texgyreheros-italic.otf
  15. BIN
      src/PicView.Avalonia/Assets/Fonts/texgyreheros-regular.otf
  16. 22 0
      src/PicView.Avalonia/DarkTheme/Controls/Border.axaml
  17. 87 0
      src/PicView.Avalonia/DarkTheme/Controls/Button.axaml
  18. 19 0
      src/PicView.Avalonia/DarkTheme/Controls/ItemsControl.axaml
  19. 41 0
      src/PicView.Avalonia/DarkTheme/Controls/PathIcon.axaml
  20. 184 0
      src/PicView.Avalonia/DarkTheme/Controls/Scrollbar.axaml
  21. 18 0
      src/PicView.Avalonia/DarkTheme/Controls/TextBlock.axaml
  22. 26 0
      src/PicView.Avalonia/DarkTheme/Controls/ToolTip.axaml
  23. 47 0
      src/PicView.Avalonia/DarkTheme/Controls/Window.axaml
  24. 66 0
      src/PicView.Avalonia/DarkTheme/Main.axaml
  25. BIN
      src/PicView.Avalonia/DarkTheme/Resources/noisy-texture-200x200-o4-d31-c-161616-t0.png
  26. 3 1
      src/PicView.Avalonia/PicView.Avalonia.csproj
  27. 129 32
      src/PicView.Avalonia/ViewModels/MainViewModel.cs
  28. 2 1
      src/PicView.Avalonia/Views/UC/BottomBar.axaml
  29. 100 4
      src/PicView.Avalonia/Views/UC/Menus/FileMenu.axaml
  30. 1 1
      src/PicView.Avalonia/Views/UC/TitleTextBox.axaml
  31. 1 1
      src/PicView.Core/Config/AppSettings.cs
  32. 5 5
      src/PicView.Core/Config/Languages/da.json
  33. 5 5
      src/PicView.Core/Config/Languages/de.json
  34. 5 5
      src/PicView.Core/Config/Languages/en.json
  35. 5 5
      src/PicView.Core/Config/Languages/es.json
  36. 5 5
      src/PicView.Core/Config/Languages/fr.json
  37. 5 5
      src/PicView.Core/Config/Languages/it.json
  38. 6 6
      src/PicView.Core/Config/Languages/ko.json
  39. 5 5
      src/PicView.Core/Config/Languages/pl.json
  40. 5 5
      src/PicView.Core/Config/Languages/ro.json
  41. 5 5
      src/PicView.Core/Config/Languages/ru.json
  42. 5 5
      src/PicView.Core/Config/Languages/zh-CN.json
  43. 5 5
      src/PicView.Core/Config/Languages/zh-TW.json
  44. 315 0
      src/PicView.Core/Localization/LanguageModel.cs
  45. 35 7
      src/PicView.Core/Localization/TranslationHelper.cs
  46. 0 6
      src/PicView.sln

+ 1 - 2
src/PicView.Avalonia.Win32/App.axaml

@@ -2,11 +2,10 @@
     x:Class="PicView.Avalonia.Win32.App"
     x:Class="PicView.Avalonia.Win32.App"
     xmlns="https://github.com/avaloniaui"
     xmlns="https://github.com/avaloniaui"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:theme="clr-namespace:PicView.Avalonia.Theme;assembly=PicView.Avalonia.Theme"
     RequestedThemeVariant="Default">
     RequestedThemeVariant="Default">
 
 
     <Application.Styles>
     <Application.Styles>
         <SimpleTheme />
         <SimpleTheme />
-        <theme:DarkTheme />
+        <StyleInclude Source="avares://PicView.Avalonia/DarkTheme/Main.axaml" />
     </Application.Styles>
     </Application.Styles>
 </Application>
 </Application>

+ 0 - 1
src/PicView.Avalonia.Win32/PicView.Avalonia.Win32.csproj

@@ -33,7 +33,6 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\PicView.Avalonia.Theme\PicView.Avalonia.Theme.csproj" />
     <ProjectReference Include="..\PicView.Avalonia\PicView.Avalonia.csproj" />
     <ProjectReference Include="..\PicView.Avalonia\PicView.Avalonia.csproj" />
     <ProjectReference Include="..\PicView.Core\PicView.Core.csproj" />
     <ProjectReference Include="..\PicView.Core\PicView.Core.csproj" />
     <ProjectReference Include="..\PicView.Windows\PicView.Windows.csproj" />
     <ProjectReference Include="..\PicView.Windows\PicView.Windows.csproj" />

BIN
src/PicView.Avalonia/Assets/Fonts/Roboto-Black.ttf


BIN
src/PicView.Avalonia/Assets/Fonts/Roboto-Bold.ttf


BIN
src/PicView.Avalonia/Assets/Fonts/Roboto-Italic.ttf


BIN
src/PicView.Avalonia/Assets/Fonts/Roboto-Light.ttf


BIN
src/PicView.Avalonia/Assets/Fonts/Roboto-LightItalic.ttf


BIN
src/PicView.Avalonia/Assets/Fonts/Roboto-Medium.ttf


BIN
src/PicView.Avalonia/Assets/Fonts/Roboto-MediumItalic.ttf


BIN
src/PicView.Avalonia/Assets/Fonts/Roboto-Regular.ttf


BIN
src/PicView.Avalonia/Assets/Fonts/Roboto-Thin.ttf


BIN
src/PicView.Avalonia/Assets/Fonts/Roboto-ThinItalic.ttf


BIN
src/PicView.Avalonia/Assets/Fonts/texgyreheros-bold.otf


BIN
src/PicView.Avalonia/Assets/Fonts/texgyreheros-italic.otf


BIN
src/PicView.Avalonia/Assets/Fonts/texgyreheros-regular.otf


+ 22 - 0
src/PicView.Avalonia/DarkTheme/Controls/Border.axaml

@@ -0,0 +1,22 @@
+<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+    <Design.PreviewWith>
+        <Border />
+    </Design.PreviewWith>
+
+    <ControlTheme x:Key="{x:Type Border}" TargetType="Border">
+
+        <Setter Property="Button.Template">
+            <ControlTemplate TargetType="Border">
+                <ContentPresenter
+                    x:Name="PART_ContentPresenter"
+                    Padding="{TemplateBinding Padding}"
+                    Background="{TemplateBinding Background}"
+                    BorderBrush="{TemplateBinding BorderBrush}"
+                    BorderThickness="{TemplateBinding BorderThickness}"
+                    CornerRadius="{TemplateBinding CornerRadius}"
+                    RecognizesAccessKey="True"
+                    UseLayoutRounding="False" />
+            </ControlTemplate>
+        </Setter>
+    </ControlTheme>
+</ResourceDictionary>

+ 87 - 0
src/PicView.Avalonia/DarkTheme/Controls/Button.axaml

@@ -0,0 +1,87 @@
+<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+    <Design.PreviewWith>
+        <Button />
+    </Design.PreviewWith>
+
+    <ControlTheme x:Key="{x:Type Button}" TargetType="Button">
+
+        <Setter Property="Button.Template">
+            <ControlTemplate TargetType="Button">
+                <ContentPresenter
+                    Name="PART_ContentPresenter"
+                    Padding="{TemplateBinding Padding}"
+                    HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+                    VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+                    Background="{TemplateBinding Background}"
+                    BorderBrush="{TemplateBinding BorderBrush}"
+                    BorderThickness="{TemplateBinding BorderThickness}"
+                    Content="{TemplateBinding Content}"
+                    ContentTemplate="{TemplateBinding ContentTemplate}"
+                    CornerRadius="{TemplateBinding CornerRadius}"
+                    RecognizesAccessKey="True"
+                    TextElement.Foreground="{TemplateBinding Foreground}" />
+            </ControlTemplate>
+        </Setter>
+
+        <Style Selector="^.hover:pointerover /template/ ContentPresenter#PART_ContentPresenter">
+            <Style.Animations>
+                <Animation IterationCount="1" Duration=".35">
+                    <KeyFrame>
+                        <Setter Property="Background">
+                            <SolidColorBrush Color="{StaticResource SecondaryBackgroundColor}" />
+                        </Setter>
+                    </KeyFrame>
+                    <KeyFrame Cue="1">
+                        <Setter Property="Background">
+                            <SolidColorBrush Color="{DynamicResource AccentColor}" />
+                        </Setter>
+                    </KeyFrame>
+                </Animation>
+            </Style.Animations>
+            <Setter Property="Background" Value="{DynamicResource AccentColor}" />
+        </Style>
+        <Style Selector="^.altHover:pointerover /template/ ContentPresenter#PART_ContentPresenter">
+            <Style.Animations>
+                <Animation IterationCount="1" Duration=".35">
+                    <KeyFrame>
+                        <Setter Property="Background">
+                            <SolidColorBrush Color="{StaticResource SecondaryBackgroundColor}" />
+                        </Setter>
+                    </KeyFrame>
+                    <KeyFrame Cue="1">
+                        <Setter Property="Background">
+                            <SolidColorBrush Color="{StaticResource BackgroundHoverColor}" />
+                        </Setter>
+                    </KeyFrame>
+                </Animation>
+            </Style.Animations>
+            <Setter Property="Background" Value="{StaticResource BackgroundHoverColor}" />
+        </Style>
+        <Style Selector="^.alphaHover:pointerover /template/ ContentPresenter#PART_ContentPresenter">
+            <Style.Animations>
+                <Animation IterationCount="1" Duration=".35">
+                    <KeyFrame>
+                        <Setter Property="Background">
+                            <SolidColorBrush Color="Transparent" />
+                        </Setter>
+                    </KeyFrame>
+                    <KeyFrame Cue="1">
+                        <Setter Property="Background">
+                            <SolidColorBrush Color="{StaticResource AltBackgroundHoverColor}" />
+                        </Setter>
+                    </KeyFrame>
+                </Animation>
+            </Style.Animations>
+            <Setter Property="Background" Value="{StaticResource AltBackgroundHoverColor}" />
+        </Style>
+        <Style Selector="^.hover:pressed  /template/ ContentPresenter#PART_ContentPresenter">
+            <Setter Property="Background" Value="{DynamicResource SecondaryAccentColor}" />
+        </Style>
+        <Style Selector="^.alphaHover:pressed  /template/ ContentPresenter#PART_ContentPresenter">
+            <Setter Property="Background" Value="{DynamicResource SecondaryAccentColor}" />
+        </Style>
+        <Style Selector="^:disabled">
+            <Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}" />
+        </Style>
+    </ControlTheme>
+</ResourceDictionary>

+ 19 - 0
src/PicView.Avalonia/DarkTheme/Controls/ItemsControl.axaml

@@ -0,0 +1,19 @@
+<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+    <Design.PreviewWith>
+        <ItemsControl />
+    </Design.PreviewWith>
+    <ControlTheme x:Key="{x:Type ItemsControl}" TargetType="ItemsControl">
+        <Setter Property="Template">
+            <ControlTemplate>
+                <Border
+                    Padding="{TemplateBinding Padding}"
+                    Background="{TemplateBinding Background}"
+                    BorderBrush="{TemplateBinding BorderBrush}"
+                    BorderThickness="{TemplateBinding BorderThickness}"
+                    CornerRadius="{TemplateBinding CornerRadius}">
+                    <ItemsPresenter Name="PART_ItemsPresenter" ItemsPanel="{TemplateBinding ItemsPanel}" />
+                </Border>
+            </ControlTemplate>
+        </Setter>
+    </ControlTheme>
+</ResourceDictionary>

+ 41 - 0
src/PicView.Avalonia/DarkTheme/Controls/PathIcon.axaml

@@ -0,0 +1,41 @@
+<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+    <Design.PreviewWith>
+        <PathIcon />
+    </Design.PreviewWith>
+    <ControlTheme x:Key="{x:Type PathIcon}" TargetType="PathIcon">
+        <Setter Property="Foreground" Value="{TemplateBinding Foreground}" />
+        <Setter Property="Background" Value="Transparent" />
+        <Setter Property="Height" Value="{TemplateBinding Height}" />
+        <Setter Property="Width" Value="{TemplateBinding Width}" />
+        <Setter Property="Template">
+            <ControlTemplate>
+                <Border Background="{TemplateBinding Background}">
+                    <Viewbox Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
+                        <Path
+                            Name="PART_ContentPresenter"
+                            Data="{TemplateBinding Data}"
+                            Fill="{TemplateBinding Foreground}"
+                            Stretch="Uniform" />
+                    </Viewbox>
+                </Border>
+            </ControlTemplate>
+        </Setter>
+        <Style Selector="^.iconHover:pointerover /template/ Path#PART_ContentPresenter">
+            <Style.Animations>
+                <Animation IterationCount="1" Duration=".35">
+                    <KeyFrame>
+                        <Setter Property="Fill">
+                            <SolidColorBrush Color="{StaticResource MainIconColor}" />
+                        </Setter>
+                    </KeyFrame>
+                    <KeyFrame Cue="1">
+                        <Setter Property="Fill">
+                            <SolidColorBrush Color="{DynamicResource AccentColor}" />
+                        </Setter>
+                    </KeyFrame>
+                </Animation>
+            </Style.Animations>
+            <Setter Property="Fill" Value="{DynamicResource AccentColor}" />
+        </Style>
+    </ControlTheme>
+</ResourceDictionary>

+ 184 - 0
src/PicView.Avalonia/DarkTheme/Controls/Scrollbar.axaml

@@ -0,0 +1,184 @@
+<ResourceDictionary
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    x:ClassModifier="internal">
+    <ControlTheme x:Key="{x:Type ScrollBar}" TargetType="ScrollBar">
+        <Setter Property="Cursor" Value="Arrow" />
+
+        <Style Selector="^:horizontal">
+            <Setter Property="Height" Value="{DynamicResource ScrollBarThickness}" />
+            <Setter Property="Template">
+                <ControlTemplate>
+                    <Border Background="{StaticResource SecondaryBackgroundColor}" UseLayoutRounding="False">
+                        <Grid ColumnDefinitions="Auto,*,Auto">
+                            <RepeatButton
+                                Name="PART_LineUpButton"
+                                Grid.Row="0"
+                                Grid.Column="0"
+                                MinWidth="{DynamicResource ScrollBarThickness}"
+                                VerticalAlignment="Center"
+                                Classes="repeat"
+                                Focusable="False">
+                                <Path Data="M 4 0 L 4 8 L 0 4 Z" />
+                            </RepeatButton>
+                            <Track
+                                Grid.Row="1"
+                                Grid.Column="1"
+                                DeferThumbDrag="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
+                                Maximum="{TemplateBinding Maximum}"
+                                Minimum="{TemplateBinding Minimum}"
+                                Orientation="{TemplateBinding Orientation}"
+                                ViewportSize="{TemplateBinding ViewportSize}"
+                                Value="{TemplateBinding Value,
+                                                        Mode=TwoWay}">
+                                <Track.DecreaseButton>
+                                    <RepeatButton
+                                        Name="PART_PageUpButton"
+                                        Classes="repeattrack"
+                                        Focusable="False" />
+                                </Track.DecreaseButton>
+                                <Track.IncreaseButton>
+                                    <RepeatButton
+                                        Name="PART_PageDownButton"
+                                        Classes="repeattrack"
+                                        Focusable="False" />
+                                </Track.IncreaseButton>
+                                <Thumb Name="thumb" />
+                            </Track>
+                            <RepeatButton
+                                Name="PART_LineDownButton"
+                                Grid.Row="2"
+                                Grid.Column="2"
+                                MinWidth="{DynamicResource ScrollBarThickness}"
+                                VerticalAlignment="Center"
+                                Classes="repeat"
+                                Focusable="False">
+                                <Path Data="M 0 0 L 4 4 L 0 8 Z" />
+                            </RepeatButton>
+                        </Grid>
+                    </Border>
+                </ControlTemplate>
+            </Setter>
+        </Style>
+
+        <Style Selector="^:vertical">
+            <Setter Property="Width" Value="30" />
+            <Setter Property="Template">
+                <ControlTemplate>
+                    <Border Background="{StaticResource SecondaryBackgroundColor}" UseLayoutRounding="False">
+                        <Grid RowDefinitions="Auto,*,Auto">
+                            <RepeatButton
+                                Name="PART_LineUpButton"
+                                Grid.Row="0"
+                                MinHeight="{DynamicResource ScrollBarThickness}"
+                                HorizontalAlignment="Center"
+                                Background="{StaticResource SecondaryBackgroundColor}"
+                                Classes="repeat"
+                                Focusable="False">
+                                <Path
+                                    Width="16"
+                                    Height="16"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Data="F1 M512,512z M0,0z M414,321.94L274.22,158.82A24,24,0,0,0,237.78,158.82L98,321.94C84.66,337.51,95.72,361.56,116.22,361.56L395.82,361.56C416.32,361.56,427.38,337.51,414,321.94z"
+                                    Fill="{StaticResource MainIconColor}"
+                                    Stretch="Fill" />
+                            </RepeatButton>
+                            <Track
+                                Grid.Row="1"
+                                Grid.Column="1"
+                                DeferThumbDrag="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
+                                IsDirectionReversed="True"
+                                Maximum="{TemplateBinding Maximum}"
+                                Minimum="{TemplateBinding Minimum}"
+                                Orientation="{TemplateBinding Orientation}"
+                                ViewportSize="{TemplateBinding ViewportSize}"
+                                Value="{TemplateBinding Value,
+                                                        Mode=TwoWay}">
+                                <Track.DecreaseButton>
+                                    <RepeatButton
+                                        Name="PART_PageUpButton"
+                                        Background="{StaticResource SecondaryBackgroundColor}"
+                                        Classes="repeattrack"
+                                        Focusable="False" />
+                                </Track.DecreaseButton>
+                                <Track.IncreaseButton>
+                                    <RepeatButton
+                                        Name="PART_PageDownButton"
+                                        Background="{StaticResource SecondaryBackgroundColor}"
+                                        Classes="repeattrack"
+                                        Focusable="False" />
+                                </Track.IncreaseButton>
+                                <Thumb Name="thumb" />
+                            </Track>
+                            <RepeatButton
+                                Name="PART_LineDownButton"
+                                Grid.Row="2"
+                                Grid.Column="2"
+                                MinHeight="{DynamicResource ScrollBarThickness}"
+                                HorizontalAlignment="Center"
+                                Background="{StaticResource SecondaryBackgroundColor}"
+                                Classes="repeat"
+                                Focusable="False">
+                                <Path
+                                    Width="16"
+                                    Height="16"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Data="F1 M512,512z M0,0z M98,190.06L237.78,353.18A24,24,0,0,0,274.22,353.18L414,190.06C427.34,174.49,416.28,150.44,395.78,150.44L116.18,150.44C95.6799999999999,150.44,84.6199999999999,174.49,97.9999999999999,190.06z"
+                                    Fill="{StaticResource MainIconColor}"
+                                    Stretch="Fill" />
+                            </RepeatButton>
+                        </Grid>
+                    </Border>
+                </ControlTemplate>
+            </Setter>
+        </Style>
+        <Style Selector="^ /template/ Thumb#thumb">
+            <Setter Property="Background" Value="{StaticResource SecondaryBackgroundColor}" />
+            <Setter Property="Template">
+                <Setter.Value>
+                    <ControlTemplate>
+                        <Border
+                            Background="{TemplateBinding Background}"
+                            BorderBrush="{StaticResource MainBorderColor}"
+                            BorderThickness="1" />
+                    </ControlTemplate>
+                </Setter.Value>
+            </Setter>
+        </Style>
+        <Style Selector="^ /template/ Thumb#thumb:pointerover">
+            <Setter Property="Background" Value="{DynamicResource AccentColor}" />
+        </Style>
+        <Style Selector="^ /template/ Thumb#thumb:pressed">
+            <Setter Property="Background" Value="{DynamicResource SecondaryAccentColor}" />
+        </Style>
+        <Style Selector="^:horizontal /template/ Thumb#thumb">
+            <Setter Property="MinWidth" Value="{DynamicResource ScrollBarThickness}" />
+            <Setter Property="Height" Value="{DynamicResource ScrollBarThumbThickness}" />
+        </Style>
+        <Style Selector="^:vertical /template/ Thumb#thumb">
+            <Setter Property="MinHeight" Value="{DynamicResource ScrollBarThickness}" />
+            <Setter Property="Width" Value="16" />
+        </Style>
+        <Style Selector="^ /template/ RepeatButton.repeat">
+            <Setter Property="Padding" Value="2" />
+            <Setter Property="BorderThickness" Value="0" />
+        </Style>
+        <Style Selector="^ /template/ RepeatButton.repeattrack">
+            <Setter Property="Template">
+                <ControlTemplate>
+                    <Border Background="{TemplateBinding Background}" />
+                </ControlTemplate>
+            </Setter>
+        </Style>
+
+        <Style Selector="^ /template/ RepeatButton > Path">
+            <Setter Property="Fill" Value="{StaticResource MainIconColor}" />
+        </Style>
+
+        <Style Selector="^ /template/ RepeatButton:pointerover > Path">
+            <Setter Property="Fill" Value="{DynamicResource AccentColor}" />
+        </Style>
+    </ControlTheme>
+</ResourceDictionary>

+ 18 - 0
src/PicView.Avalonia/DarkTheme/Controls/TextBlock.axaml

@@ -0,0 +1,18 @@
+<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+    <Design.PreviewWith>
+        <Border />
+    </Design.PreviewWith>
+
+    <ControlTheme x:Key="{x:Type TextBlock}" TargetType="TextBlock">
+
+        <Setter Property="Button.Template">
+            <ControlTemplate TargetType="TextBlock">
+                <ContentPresenter
+                    x:Name="PART_ContentPresenter"
+                    Padding="{TemplateBinding Padding}"
+                    RecognizesAccessKey="True"
+                    UseLayoutRounding="False" />
+            </ControlTemplate>
+        </Setter>
+    </ControlTheme>
+</ResourceDictionary>

+ 26 - 0
src/PicView.Avalonia/DarkTheme/Controls/ToolTip.axaml

@@ -0,0 +1,26 @@
+<ResourceDictionary
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    x:ClassModifier="internal">
+    <ControlTheme x:Key="{x:Type ToolTip}" TargetType="ToolTip">
+        <Setter Property="Background" Value="{DynamicResource SecondaryBackgroundColor}" />
+        <Setter Property="BorderBrush" Value="{StaticResource MainBorderColor}" />
+        <Setter Property="BorderThickness" Value="1" />
+        <Setter Property="FontSize" Value="11" />
+        <Setter Property="FontFamily" Value="/Assets/Fonts/Roboto-Regular.ttf#Roboto" />
+        <Setter Property="Foreground" Value="{StaticResource MainTextColor}" />
+        <Setter Property="Template">
+            <ControlTemplate>
+                <ContentPresenter
+                    Name="PART_ContentPresenter"
+                    Padding="7"
+                    Background="{TemplateBinding Background}"
+                    BorderBrush="{TemplateBinding BorderBrush}"
+                    BorderThickness="{TemplateBinding BorderThickness}"
+                    Content="{TemplateBinding Content}"
+                    ContentTemplate="{TemplateBinding ContentTemplate}"
+                    CornerRadius="5" />
+            </ControlTemplate>
+        </Setter>
+    </ControlTheme>
+</ResourceDictionary>

+ 47 - 0
src/PicView.Avalonia/DarkTheme/Controls/Window.axaml

@@ -0,0 +1,47 @@
+<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+    <Design.PreviewWith>
+        <Window />
+    </Design.PreviewWith>
+    <ControlTheme x:Key="{x:Type Window}" TargetType="Window">
+        <Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
+        <Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}" />
+        <Setter Property="TransparencyBackgroundFallback" Value="{DynamicResource HighlightForegroundColor}" />
+        <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}" />
+        <Setter Property="FontSize" Value="{DynamicResource FontSizeNormal}" />
+        <Setter Property="Template">
+            <ControlTemplate>
+                <Panel>
+                    <Border Name="PART_TransparencyFallback" IsHitTestVisible="False" />
+                    <Border Background="{TemplateBinding Background}" IsHitTestVisible="False" />
+                    <Panel Margin="{TemplateBinding WindowDecorationMargin}" Background="Transparent" />
+                    <VisualLayerManager>
+                        <VisualLayerManager.ChromeOverlayLayer>
+                            <TitleBar />
+                        </VisualLayerManager.ChromeOverlayLayer>
+                        <Panel>
+                            <ExperimentalAcrylicBorder IsHitTestVisible="False">
+                                <ExperimentalAcrylicBorder.Material>
+                                    <ExperimentalAcrylicMaterial
+                                        BackgroundSource="Digger"
+                                        MaterialOpacity="0.1"
+                                        TintColor="Black"
+                                        TintOpacity=".9" />
+                                </ExperimentalAcrylicBorder.Material>
+                            </ExperimentalAcrylicBorder>
+
+                            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
+                                <ContentPresenter
+                                    Name="PART_ContentPresenter"
+                                    Margin="{TemplateBinding Padding}"
+                                    HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+                                    VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+                                    Content="{TemplateBinding Content}"
+                                    ContentTemplate="{TemplateBinding ContentTemplate}" />
+                            </Border>
+                        </Panel>
+                    </VisualLayerManager>
+                </Panel>
+            </ControlTemplate>
+        </Setter>
+    </ControlTheme>
+</ResourceDictionary>

+ 66 - 0
src/PicView.Avalonia/DarkTheme/Main.axaml

@@ -0,0 +1,66 @@
+<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+    <Styles.Resources>
+        <ResourceDictionary>
+            <Color x:Key="AccentColor">#FFDB5B3D</Color>
+            <Color x:Key="SecondaryAccentColor">#e0755a</Color>
+            <Color x:Key="LogoAccentColor">#FFf8af3c</Color>
+
+            <Color x:Key="MainTextColor">#FFf6f4f4</Color>
+            <Color x:Key="MainTextColorFaded">#FFf6f4f4</Color>
+
+            <Color x:Key="MainIconColor">#eeebebeb</Color>
+            <Color x:Key="SecondaryIconColor">#eeebebeb</Color>
+
+            <Color x:Key="MainBackgroundColor">#FF2b2b2b</Color>
+            <Color x:Key="SecondaryBackgroundColor">#F2252525</Color>
+            <Color x:Key="BackgroundHoverColor">#FF4B4B4B</Color>
+            <Color x:Key="AltBackgroundHoverColor">#22FFFFFF</Color>
+
+            <Color x:Key="MainButtonBackgroundColor">#FF2e2e2e</Color>
+
+            <Color x:Key="MainBorderColor">#FF3A3A3A</Color>
+
+            <Color x:Key="ButtonForegroundPointerOver">#FFF</Color>
+
+            <ImageBrush
+                x:Key="NoisyTexture"
+                DestinationRect="0,0,100,100"
+                Opacity=".7"
+                Source="\DarkTheme\Resources\noisy-texture-200x200-o4-d31-c-161616-t0.png"
+                SourceRect="0,0,200,200"
+                Stretch="Fill"
+                TileMode="FlipXY" />
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceInclude Source="/DarkTheme/Controls/Button.axaml" />
+                <ResourceInclude Source="/DarkTheme/Controls/Border.axaml" />
+                <ResourceInclude Source="/DarkTheme/Controls/TextBlock.axaml" />
+                <ResourceInclude Source="/DarkTheme/Controls/PathIcon.axaml" />
+                <ResourceInclude Source="/DarkTheme/Controls/Scrollbar.axaml" />
+                <ResourceInclude Source="/DarkTheme/Controls/ToolTip.axaml" />
+                <ResourceInclude Source="/DarkTheme/Controls/Window.axaml" />
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </Styles.Resources>
+    <Style Selector="Window">
+        <Setter Property="Background" Value="Transparent" />
+        <Setter Property="ExtendClientAreaChromeHints" Value="NoChrome" />
+        <Setter Property="ExtendClientAreaTitleBarHeightHint" Value="32" />
+        <Setter Property="ExtendClientAreaToDecorationsHint" Value="True" />
+        <Setter Property="TransparencyLevelHint" Value="AcrylicBlur" />
+    </Style>
+    <Style Selector="TextBox, Label, Button">
+        <Setter Property="FontSize" Value="14" />
+        <Setter Property="FontFamily" Value="/Assets/Fonts/Roboto-Medium.ttf#Roboto" />
+    </Style>
+    <Style Selector="TextBlock">
+        <Setter Property="FontSize" Value="14" />
+        <Setter Property="Foreground" Value="{StaticResource MainTextColor}" />
+        <Setter Property="FontFamily" Value="/Assets/Fonts/Roboto-Regular.ttf#Roboto" />
+    </Style>
+
+    <Style Selector="Button.hover">
+        <Style Selector="^:pointerover">
+            <Setter Property="Background" Value="{DynamicResource AccentColor}" />
+        </Style>
+    </Style>
+</Styles>

BIN
src/PicView.Avalonia/DarkTheme/Resources/noisy-texture-200x200-o4-d31-c-161616-t0.png


+ 3 - 1
src/PicView.Avalonia/PicView.Avalonia.csproj

@@ -7,12 +7,15 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <ImplicitUsings>enable</ImplicitUsings>
     <Company>Ruben Hyldgaard Negendahl</Company>
     <Company>Ruben Hyldgaard Negendahl</Company>
     <Product>PicView</Product>
     <Product>PicView</Product>
+    <PlatformTarget>x64</PlatformTarget>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
     <IsAotCompatible>True</IsAotCompatible>
     <IsAotCompatible>True</IsAotCompatible>
+    <IsTrimmable>True</IsTrimmable>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
     <IsAotCompatible>True</IsAotCompatible>
     <IsAotCompatible>True</IsAotCompatible>
+    <IsTrimmable>True</IsTrimmable>
   </PropertyGroup>
   </PropertyGroup>
 
 
   
   
@@ -49,7 +52,6 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\PicView.Avalonia.Theme\PicView.Avalonia.Theme.csproj" />
     <ProjectReference Include="..\PicView.Core\PicView.Core.csproj" />
     <ProjectReference Include="..\PicView.Core\PicView.Core.csproj" />
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 129 - 32
src/PicView.Avalonia/ViewModels/MainViewModel.cs

@@ -5,14 +5,13 @@ using Avalonia.Media;
 using PicView.Avalonia.Helpers;
 using PicView.Avalonia.Helpers;
 using PicView.Avalonia.Models;
 using PicView.Avalonia.Models;
 using PicView.Avalonia.Navigation;
 using PicView.Avalonia.Navigation;
+using PicView.Avalonia.Services;
 using PicView.Avalonia.Views.UC;
 using PicView.Avalonia.Views.UC;
-using PicView.Core.Config;
 using PicView.Core.ImageDecoding;
 using PicView.Core.ImageDecoding;
 using PicView.Core.Localization;
 using PicView.Core.Localization;
 using PicView.Core.Navigation;
 using PicView.Core.Navigation;
 using ReactiveUI;
 using ReactiveUI;
 using System.Windows.Input;
 using System.Windows.Input;
-using PicView.Avalonia.Services;
 
 
 namespace PicView.Avalonia.ViewModels;
 namespace PicView.Avalonia.ViewModels;
 
 
@@ -20,36 +19,108 @@ public class MainViewModel : ViewModelBase
 {
 {
     #region Localization
     #region Localization
 
 
-    private string? _currentLanguageKey;
+    private void UpdateLanguage()
+    {
+        SelectFile = TranslationHelper.GetTranslation("OpenFileDialog");
+        OpenLastFile = TranslationHelper.GetTranslation("OpenLastFile");
+        Paste = TranslationHelper.GetTranslation("FilePaste");
+        Copy = TranslationHelper.GetTranslation("Copy");
+        Reload = TranslationHelper.GetTranslation("Reload");
+        Print = TranslationHelper.GetTranslation("Print");
+        DeleteFile = TranslationHelper.GetTranslation("DeleteFile");
+        Save = TranslationHelper.GetTranslation("Save");
+        CopyFile = TranslationHelper.GetTranslation("CopyFile");
+        NewWindow = TranslationHelper.GetTranslation("NewWindow");
+        Close = TranslationHelper.GetTranslation("Close");
+    }
 
 
-    public string CurrentLanguageValue
+    private string? _selectFile;
+
+    public string? SelectFile
     {
     {
-        get => SettingsHelper.Settings.UIProperties.UserLanguage;
+        get => _selectFile;
+        set => this.RaiseAndSetIfChanged(ref _selectFile, value);
     }
     }
 
 
-    public string? CurrentLanguageKey
+    private string? _openLastFile;
+
+    public string? OpenLastFile
     {
     {
-        get => _currentLanguageKey ?? "en";
-        set
-        {
-            if (_currentLanguageKey == value)
-            {
-                return;
-            }
+        get => _openLastFile;
+        set => this.RaiseAndSetIfChanged(ref _openLastFile, value);
+    }
 
 
-            _currentLanguageKey = value;
-            this.RaisePropertyChanged(nameof(CurrentLanguageValue));
-            this.RaisePropertyChanged(nameof(CurrentLanguageValue));
-            this.RaisePropertyChanged(nameof(SelectFile));
-            this.RaisePropertyChanged(nameof(OpenLastFile));
-            this.RaisePropertyChanged(nameof(Paste));
-        }
+    private string? _paste;
+
+    public string? Paste
+    {
+        get => _paste;
+        set => this.RaiseAndSetIfChanged(ref _paste, value);
+    }
+
+    private string? _copy;
+
+    public string? Copy
+    {
+        get => _copy;
+        set => this.RaiseAndSetIfChanged(ref _copy, value);
+    }
+
+    private string? _reload;
+
+    public string? Reload
+    {
+        get => _reload;
+        set => this.RaiseAndSetIfChanged(ref _reload, value);
+    }
+
+    private string? _print;
+
+    public string? Print
+    {
+        get => _print;
+        set => this.RaiseAndSetIfChanged(ref _print, value);
+    }
+
+    private string? _deleteFile;
+
+    public string? DeleteFile
+    {
+        get => _deleteFile;
+        set => this.RaiseAndSetIfChanged(ref _deleteFile, value);
+    }
+
+    private string? _save;
+
+    public string? Save
+    {
+        get => _save;
+        set => this.RaiseAndSetIfChanged(ref _save, value);
+    }
+
+    private string? _copyFile;
+
+    public string? CopyFile
+    {
+        get => _copyFile;
+        set => this.RaiseAndSetIfChanged(ref _copyFile, value);
+    }
+
+    private string? _newWindow;
+
+    public string? NewWindow
+    {
+        get => _newWindow;
+        set => this.RaiseAndSetIfChanged(ref _newWindow, value);
     }
     }
 
 
-    public string SelectFile => TranslationHelper.GetTranslation("OpenFileDialog");
+    private string? _close;
 
 
-    public string OpenLastFile => TranslationHelper.GetTranslation("OpenLastFile");
-    public string Paste => TranslationHelper.GetTranslation("FilePaste");
+    public string? Close
+    {
+        get => _close;
+        set => this.RaiseAndSetIfChanged(ref _close, value);
+    }
 
 
     #endregion Localization
     #endregion Localization
 
 
@@ -62,30 +133,40 @@ public class MainViewModel : ViewModelBase
     public ICommand? PreviousCommand { get; private set; }
     public ICommand? PreviousCommand { get; private set; }
     public ICommand? FirstCommand { get; private set; }
     public ICommand? FirstCommand { get; private set; }
     public ICommand? LastCommand { get; private set; }
     public ICommand? LastCommand { get; private set; }
+    public ICommand? OpenFileCommand { get; private set; }
+    public ICommand? OpenLastFileCommand { get; private set; }
+    public ICommand? PasteCommand { get; private set; }
+    public ICommand? CopyCommand { get; private set; }
+    public ICommand? ReloadCommand { get; private set; }
+    public ICommand? PrintCommand { get; private set; }
+    public ICommand? DeleteFileCommand { get; private set; }
+    public ICommand? SaveCommand { get; private set; }
+    public ICommand? CloseMenuCommand { get; }
+    public ICommand? ToggleFileMenuCommand { get; }
 
 
     #endregion Commands
     #endregion Commands
 
 
     #region Fields
     #region Fields
 
 
-    private string _title = "Loading...";
+    private string? _title = "Loading...";
 
 
-    public string Title
+    public string? Title
     {
     {
         get => _title;
         get => _title;
         set => this.RaiseAndSetIfChanged(ref _title, value);
         set => this.RaiseAndSetIfChanged(ref _title, value);
     }
     }
 
 
-    private string _titleTooltip = "Loading...";
+    private string? _titleTooltip = "Loading...";
 
 
-    public string TitleTooltip
+    public string? TitleTooltip
     {
     {
         get => _titleTooltip;
         get => _titleTooltip;
         set => this.RaiseAndSetIfChanged(ref _titleTooltip, value);
         set => this.RaiseAndSetIfChanged(ref _titleTooltip, value);
     }
     }
 
 
-    private string _windowTitle = "PicView";
+    private string? _windowTitle = "PicView";
 
 
-    public string WindowTitle
+    public string? WindowTitle
     {
     {
         get => _windowTitle;
         get => _windowTitle;
         set => this.RaiseAndSetIfChanged(ref _windowTitle, value);
         set => this.RaiseAndSetIfChanged(ref _windowTitle, value);
@@ -214,6 +295,12 @@ public class MainViewModel : ViewModelBase
         TitleTooltip = titleString[2];
         TitleTooltip = titleString[2];
     }
     }
 
 
+    public void ResetTitle()
+    {
+        WindowTitle = TranslationHelper.GetTranslation("NoImage") + " - PicView";
+        TitleTooltip = Title = TranslationHelper.GetTranslation("NoImage");
+    }
+
     private async Task SetImageModelAsync(NavigateTo navigateTo)
     private async Task SetImageModelAsync(NavigateTo navigateTo)
     {
     {
         ArgumentNullException.ThrowIfNull(ImageIterator);
         ArgumentNullException.ThrowIfNull(ImageIterator);
@@ -254,8 +341,6 @@ public class MainViewModel : ViewModelBase
             return;
             return;
         }
         }
 
 
-        WindowHelper.InitializeWindowSizeAndPosition(desktop);
-
         var args = Environment.GetCommandLineArgs();
         var args = Environment.GetCommandLineArgs();
         if (args.Length > 1)
         if (args.Length > 1)
         {
         {
@@ -270,9 +355,11 @@ public class MainViewModel : ViewModelBase
         {
         {
             // Otherwise, display the menu
             // Otherwise, display the menu
             CurrentView = new StartUpMenu();
             CurrentView = new StartUpMenu();
+            ResetTitle();
         }
         }
 
 
-        IsFileMenuVisible = true;
+        WindowHelper.InitializeWindowSizeAndPosition(desktop);
+        UpdateLanguage();
 
 
         ExitCommand = ReactiveCommand.Create(desktop.MainWindow.Close);
         ExitCommand = ReactiveCommand.Create(desktop.MainWindow.Close);
         MinimizeCommand = ReactiveCommand.Create(() =>
         MinimizeCommand = ReactiveCommand.Create(() =>
@@ -317,5 +404,15 @@ public class MainViewModel : ViewModelBase
             }
             }
             await SetImageModelAsync(NavigateTo.Last).ConfigureAwait(false);
             await SetImageModelAsync(NavigateTo.Last).ConfigureAwait(false);
         });
         });
+
+        CloseMenuCommand = ReactiveCommand.Create(() =>
+        {
+            IsFileMenuVisible = false;
+        });
+
+        ToggleFileMenuCommand = ReactiveCommand.Create(() =>
+        {
+            IsFileMenuVisible = !IsFileMenuVisible;
+        });
     }
     }
 }
 }

+ 2 - 1
src/PicView.Avalonia/Views/UC/BottomBar.axaml

@@ -29,7 +29,8 @@
                     Background="{StaticResource MainButtonBackgroundColor}"
                     Background="{StaticResource MainButtonBackgroundColor}"
                     BorderBrush="{StaticResource MainBorderColor}"
                     BorderBrush="{StaticResource MainBorderColor}"
                     BorderThickness="1,0,1,0"
                     BorderThickness="1,0,1,0"
-                    Classes="altHover">
+                    Classes="altHover"
+                    Command="{Binding ToggleFileMenuCommand}">
                     <Path
                     <Path
                         Width="25.112"
                         Width="25.112"
                         Height="20.091"
                         Height="20.091"

File diff suppressed because it is too large
+ 100 - 4
src/PicView.Avalonia/Views/UC/Menus/FileMenu.axaml


+ 1 - 1
src/PicView.Avalonia/Views/UC/TitleTextBox.axaml

@@ -17,7 +17,7 @@
         Height="30"
         Height="30"
         Padding="3,7,3,5"
         Padding="3,7,3,5"
         VerticalAlignment="Center"
         VerticalAlignment="Center"
-        FontFamily="avares://PicView.Avalonia.Theme/Assets/Fonts/Roboto-Medium.ttf#Roboto"
+        FontFamily="avares://PicView.Avalonia/Assets/Fonts/Roboto-Medium.ttf#Roboto"
         FontSize="13"
         FontSize="13"
         FontWeight="Medium"
         FontWeight="Medium"
         IsTabStop="False"
         IsTabStop="False"

+ 1 - 1
src/PicView.Core/Config/AppSettings.cs

@@ -84,5 +84,5 @@ public class StartUp
     public bool OpenLastFile { get; set; } = false;
     public bool OpenLastFile { get; set; } = false;
     public bool OpenSpecificFile { get; set; } = false;
     public bool OpenSpecificFile { get; set; } = false;
     public string OpenSpecificString { get; set; } = "";
     public string OpenSpecificString { get; set; } = "";
-    public string LastFile { get; set; } = "";
+    public string? LastFile { get; set; } = "";
 }
 }

+ 5 - 5
src/PicView.Core/Config/Languages/da.json

@@ -38,11 +38,11 @@
   "ScrollToTop": "Scroll til toppen",
   "ScrollToTop": "Scroll til toppen",
   "ScrollToBottom": "Scroll til bunden",
   "ScrollToBottom": "Scroll til bunden",
   "SetStarRating": "Angiv stjernevurdering",
   "SetStarRating": "Angiv stjernevurdering",
-  "1Star": "1 stjerne",
-  "2Star": "2 stjerner",
-  "3Star": "3 stjerner",
-  "4Star": "4 stjerner",
-  "5Star": "5 stjerner",
+  "_1Star": "1 stjerne",
+  "_2Star": "2 stjerner",
+  "_3Star": "3 stjerner",
+  "_4Star": "4 stjerner",
+  "_5Star": "5 stjerner",
   "RemoveStarRating": "Fjern vurdering",
   "RemoveStarRating": "Fjern vurdering",
   "WindowScaling": "Skalering af vindue",
   "WindowScaling": "Skalering af vindue",
   "NormalWindow": "Normalt vindue",
   "NormalWindow": "Normalt vindue",

+ 5 - 5
src/PicView.Core/Config/Languages/de.json

@@ -38,11 +38,11 @@
   "ScrollToTop": "Zum Anfang scrollen",
   "ScrollToTop": "Zum Anfang scrollen",
   "ScrollToBottom": "Zum Ende scrollen",
   "ScrollToBottom": "Zum Ende scrollen",
   "SetStarRating": "Sternebewertung festlegen",
   "SetStarRating": "Sternebewertung festlegen",
-  "1Star": "1 Stern",
-  "2Star": "2 Sterne",
-  "3Star": "3 Sterne",
-  "4Star": "4 Sterne",
-  "5Star": "5 Sterne",
+  "_1Star": "1 Stern",
+  "_2Star": "2 Sterne",
+  "_3Star": "3 Sterne",
+  "_4Star": "4 Sterne",
+  "_5Star": "5 Sterne",
   "RemoveStarRating": "Bewertung entfernen",
   "RemoveStarRating": "Bewertung entfernen",
   "WindowScaling": "Fensterskalierung",
   "WindowScaling": "Fensterskalierung",
   "NormalWindow": "Normales Fenster",
   "NormalWindow": "Normales Fenster",

+ 5 - 5
src/PicView.Core/Config/Languages/en.json

@@ -38,11 +38,11 @@
   "ScrollToTop": "Scroll to top",
   "ScrollToTop": "Scroll to top",
   "ScrollToBottom": "Scroll to bottom",
   "ScrollToBottom": "Scroll to bottom",
   "SetStarRating": "Set star rating",
   "SetStarRating": "Set star rating",
-  "1Star": "1 star rating",
-  "2Star": "2 star rating",
-  "3Star": "3 star rating",
-  "4Star": "4 star rating",
-  "5Star": "5 star rating",
+  "_1Star": "1 star rating",
+  "_2Star": "2 star rating",
+  "_3Star": "3 star rating",
+  "_4Star": "4 star rating",
+  "_5Star": "5 star rating",
   "RemoveStarRating": "Remove rating",
   "RemoveStarRating": "Remove rating",
   "WindowScaling": "Window scaling",
   "WindowScaling": "Window scaling",
   "NormalWindow": "Normal window",
   "NormalWindow": "Normal window",

+ 5 - 5
src/PicView.Core/Config/Languages/es.json

@@ -38,11 +38,11 @@
   "ScrollToTop": "Desplazar hacia arriba al tope",
   "ScrollToTop": "Desplazar hacia arriba al tope",
   "ScrollToBottom": "Desplazar hacia abajo al fondo",
   "ScrollToBottom": "Desplazar hacia abajo al fondo",
   "SetStarRating": "Establecer clasificación con estrellas",
   "SetStarRating": "Establecer clasificación con estrellas",
-  "1Star": "Clasificación de 1 estrella",
-  "2Star": "Clasificación de 2 estrella",
-  "3Star": "Clasificación de 3 estrella",
-  "4Star": "Clasificación de 4 estrella",
-  "5Star": "Clasificación de 5 estrella",
+  "_1Star": "Clasificación de 1 estrella",
+  "_2Star": "Clasificación de 2 estrella",
+  "_3Star": "Clasificación de 3 estrella",
+  "_4Star": "Clasificación de 4 estrella",
+  "_5Star": "Clasificación de 5 estrella",
   "RemoveStarRating": "Eliminar clasificación",
   "RemoveStarRating": "Eliminar clasificación",
   "WindowScaling": "Escalado de ventana",
   "WindowScaling": "Escalado de ventana",
   "NormalWindow": "Ventana normal",
   "NormalWindow": "Ventana normal",

+ 5 - 5
src/PicView.Core/Config/Languages/fr.json

@@ -38,11 +38,11 @@
   "ScrollToTop": "Faire défiler vers le haut",
   "ScrollToTop": "Faire défiler vers le haut",
   "ScrollToBottom": "Faire défiler vers le bas",
   "ScrollToBottom": "Faire défiler vers le bas",
   "SetStarRating": "Définir une note avec des étoiles",
   "SetStarRating": "Définir une note avec des étoiles",
-  "1Star": "Note de 1 étoile",
-  "2Star": "Note de 2 étoiles",
-  "3Star": "Note de 3 étoiles",
-  "4Star": "Note de 4 étoiles",
-  "5Star": "Note de 5 étoiles",
+  "_1Star": "Note de 1 étoile",
+  "_2Star": "Note de 2 étoiles",
+  "_3Star": "Note de 3 étoiles",
+  "_4Star": "Note de 4 étoiles",
+  "_5Star": "Note de 5 étoiles",
   "RemoveStarRating": "Supprimer la note",
   "RemoveStarRating": "Supprimer la note",
   "WindowScaling": "Mise à l'échelle de la fenêtre",
   "WindowScaling": "Mise à l'échelle de la fenêtre",
   "NormalWindow": "Fenêtre normale",
   "NormalWindow": "Fenêtre normale",

+ 5 - 5
src/PicView.Core/Config/Languages/it.json

@@ -38,11 +38,11 @@
   "ScrollToTop": "Scorri in alto",
   "ScrollToTop": "Scorri in alto",
   "ScrollToBottom": "Scorri in basso",
   "ScrollToBottom": "Scorri in basso",
   "SetStarRating": "Imposta il rating con le stelle",
   "SetStarRating": "Imposta il rating con le stelle",
-  "1Star": "Rating a 1 stella",
-  "2Star": "Rating a 2 stella",
-  "3Star": "Rating a 3 stella",
-  "4Star": "Rating a 4 stella",
-  "5Star": "Rating a 5 stella",
+  "_1Star": "Rating a 1 stella",
+  "_2Star": "Rating a 2 stella",
+  "_3Star": "Rating a 3 stella",
+  "_4Star": "Rating a 4 stella",
+  "_5Star": "Rating a 5 stella",
   "RemoveStarRating": "Rimuovi il rating",
   "RemoveStarRating": "Rimuovi il rating",
   "WindowScaling": "Ridimensionamento della finestra",
   "WindowScaling": "Ridimensionamento della finestra",
   "NormalWindow": "Finestra normale",
   "NormalWindow": "Finestra normale",

+ 6 - 6
src/PicView.Core/Config/Languages/ko.json

@@ -38,11 +38,11 @@
   "ScrollToTop": "맨 위로 스크롤",
   "ScrollToTop": "맨 위로 스크롤",
   "ScrollToBottom": "맨 아래로 스크롤",
   "ScrollToBottom": "맨 아래로 스크롤",
   "SetStarRating": "별점 설정",
   "SetStarRating": "별점 설정",
-  "1Star": "1별",
-  "2Star": "2별",
-  "3Star": "3별",
-  "4Star": "4별",
-  "5Star": "5별",
+  "_1Star": "1별",
+  "_2Star": "2별",
+  "_3Star": "3별",
+  "_4Star": "4별",
+  "_5Star": "5별",
   "RemoveStarRating": "등급 제거",
   "RemoveStarRating": "등급 제거",
   "WindowScaling": "창 비율",
   "WindowScaling": "창 비율",
   "NormalWindow": "일반 창",
   "NormalWindow": "일반 창",
@@ -309,4 +309,4 @@
   "ApplicationStartup": "응용 프로그램 시작",
   "ApplicationStartup": "응용 프로그램 시작",
   "OpenInSameWindow": "동일한 창에서 파일 열기",
   "OpenInSameWindow": "동일한 창에서 파일 열기",
   "NoChange": "변경 없음"
   "NoChange": "변경 없음"
-}
+}

+ 5 - 5
src/PicView.Core/Config/Languages/pl.json

@@ -38,11 +38,11 @@
   "ScrollToTop": "Przewiń do góry",
   "ScrollToTop": "Przewiń do góry",
   "ScrollToBottom": "Przewiń na dół",
   "ScrollToBottom": "Przewiń na dół",
   "SetStarRating": "Ustawianie oceny gwiazdkowej",
   "SetStarRating": "Ustawianie oceny gwiazdkowej",
-  "1Star": "Ocena 1 gwiazdki",
-  "2Star": "Ocena 2 gwiazdek",
-  "3Star": "Ocena 3 gwiazdek",
-  "4Star": "Ocena 4 gwiazdek",
-  "5Star": "Ocena 5 gwiazdek",
+  "_1Star": "Ocena 1 gwiazdki",
+  "_2Star": "Ocena 2 gwiazdek",
+  "_3Star": "Ocena 3 gwiazdek",
+  "_4Star": "Ocena 4 gwiazdek",
+  "_5Star": "Ocena 5 gwiazdek",
   "RemoveStarRating": "Usuń ocenę",
   "RemoveStarRating": "Usuń ocenę",
   "WindowScaling": "Skalowanie okna",
   "WindowScaling": "Skalowanie okna",
   "NormalWindow": "Normalne okno",
   "NormalWindow": "Normalne okno",

+ 5 - 5
src/PicView.Core/Config/Languages/ro.json

@@ -38,11 +38,11 @@
   "ScrollToTop": "Derulează în partea de sus",
   "ScrollToTop": "Derulează în partea de sus",
   "ScrollToBottom": "Derulează în partea de jos",
   "ScrollToBottom": "Derulează în partea de jos",
   "SetStarRating": "Setare evaluare cu stele",
   "SetStarRating": "Setare evaluare cu stele",
-  "1Star": "Evaluare cu 1 stea",
-  "2Star": "Evaluare cu 2 stele",
-  "3Star": "Evaluare cu 3 stele",
-  "4Star": "Evaluare cu 4 stele",
-  "5Star": "Evaluare cu 5 stele",
+  "_1Star": "Evaluare cu 1 stea",
+  "_2Star": "Evaluare cu 2 stele",
+  "_3Star": "Evaluare cu 3 stele",
+  "_4Star": "Evaluare cu 4 stele",
+  "_5Star": "Evaluare cu 5 stele",
   "RemoveStarRating": "Eliminare evaluare",
   "RemoveStarRating": "Eliminare evaluare",
   "WindowScaling": "Scalare fereastră",
   "WindowScaling": "Scalare fereastră",
   "NormalWindow": "Fereastră normală",
   "NormalWindow": "Fereastră normală",

+ 5 - 5
src/PicView.Core/Config/Languages/ru.json

@@ -38,11 +38,11 @@
   "ScrollToTop": "Прокрутить вверх",
   "ScrollToTop": "Прокрутить вверх",
   "ScrollToBottom": "Прокрутить вниз",
   "ScrollToBottom": "Прокрутить вниз",
   "SetStarRating": "Установить рейтинг звезд",
   "SetStarRating": "Установить рейтинг звезд",
-  "1Star": "1 звезда",
-  "2Star": "2звезды",
-  "3Star": "3звезды",
-  "4Star": "4звезды",
-  "5Star": "5звезды",
+  "_1Star": "1 звезда",
+  "_2Star": "2звезды",
+  "_3Star": "3звезды",
+  "_4Star": "4звезды",
+  "_5Star": "5звезды",
   "RemoveStarRating": "Убрать рейтинг",
   "RemoveStarRating": "Убрать рейтинг",
   "WindowScaling": "Масштабирование окна",
   "WindowScaling": "Масштабирование окна",
   "NormalWindow": "Обычное окно",
   "NormalWindow": "Обычное окно",

+ 5 - 5
src/PicView.Core/Config/Languages/zh-CN.json

@@ -38,11 +38,11 @@
   "ScrollToTop": "滑动到顶部",
   "ScrollToTop": "滑动到顶部",
   "ScrollToBottom": "滑动到底部",
   "ScrollToBottom": "滑动到底部",
   "SetStarRating": "设置星级评分",
   "SetStarRating": "设置星级评分",
-  "1Star": "1星评分",
-  "2Star": "2星评分",
-  "3Star": "3星评分",
-  "4Star": "4星评分",
-  "5Star": "5星评分",
+  "_1Star": "1星评分",
+  "_2Star": "2星评分",
+  "_3Star": "3星评分",
+  "_4Star": "4星评分",
+  "_5Star": "5星评分",
   "RemoveStarRating": "移除评分",
   "RemoveStarRating": "移除评分",
   "WindowScaling": "窗口缩放",
   "WindowScaling": "窗口缩放",
   "NormalWindow": "正常窗口",
   "NormalWindow": "正常窗口",

+ 5 - 5
src/PicView.Core/Config/Languages/zh-TW.json

@@ -38,11 +38,11 @@
   "ScrollToTop": "滑動到頂部",
   "ScrollToTop": "滑動到頂部",
   "ScrollToBottom": "滑動到底部",
   "ScrollToBottom": "滑動到底部",
   "SetStarRating": "設置星級評分",
   "SetStarRating": "設置星級評分",
-  "1Star": "1星評分",
-  "2Star": "2星評分",
-  "3Star": "3星評分",
-  "4Star": "4星評分",
-  "5Star": "5星評分",
+  "_1Star": "1星評分",
+  "_2Star": "2星評分",
+  "_3Star": "3星評分",
+  "_4Star": "4星評分",
+  "_5Star": "5星評分",
   "RemoveStarRating": "移除評分",
   "RemoveStarRating": "移除評分",
   "WindowScaling": "視窗縮放",
   "WindowScaling": "視窗縮放",
   "NormalWindow": "正常視窗",
   "NormalWindow": "正常視窗",

+ 315 - 0
src/PicView.Core/Localization/LanguageModel.cs

@@ -0,0 +1,315 @@
+namespace PicView.Core.Localization;
+
+internal class LanguageModel
+{
+    public string? Loading { get; set; }
+    public string? NoImage { get; set; }
+    public string? Files { get; set; }
+    public string? File { get; set; }
+    public string? PercentComplete { get; set; }
+    public string? CropMessage { get; set; }
+    public string? ClipboardImage { get; set; }
+    public string? Base64Image { get; set; }
+    public string? Close { get; set; }
+    public string? RestoreDown { get; set; }
+    public string? Maximize { get; set; }
+    public string? Minimize { get; set; }
+    public string? Fullscreen { get; set; }
+    public string? NewWindow { get; set; }
+    public string? About { get; set; }
+    public string? InfoWindowTitle { get; set; }
+    public string? ApplicationShortcuts { get; set; }
+    public string? ImageControl { get; set; }
+    public string? FileManagement { get; set; }
+    public string? DragFileTo { get; set; }
+    public string? DragImage { get; set; }
+    public string? AdditionalFunctions { get; set; }
+    public string? Reload { get; set; }
+    public string? Credits { get; set; }
+    public string? IconsUsed { get; set; }
+    public string? GithubRepo { get; set; }
+    public string? ViewLicenseFile { get; set; }
+    public string? Version { get; set; }
+    public string? ChangeKeybindingText { get; set; }
+    public string? ResetButtonText { get; set; }
+    public string? SelectGalleryThumb { get; set; }
+    public string? PressKey { get; set; }
+    public string? ChangeKeybindingTooltip { get; set; }
+    public string? ScrollAndRotate { get; set; }
+    public string? ScrollUp { get; set; }
+    public string? ScrollDown { get; set; }
+    public string? ScrollToTop { get; set; }
+    public string? ScrollToBottom { get; set; }
+    public string? SetStarRating { get; set; }
+    public string? _1Star { get; set; }
+    public string? _2Star { get; set; }
+    public string? _3Star { get; set; }
+    public string? _4Star { get; set; }
+    public string? _5Star { get; set; }
+    public string? RemoveStarRating { get; set; }
+    public string? WindowScaling { get; set; }
+    public string? NormalWindow { get; set; }
+    public string? FillHeight { get; set; }
+    public string? AutoFitWindow { get; set; }
+    public string? InterfaceConfiguration { get; set; }
+    public string? HideShowInterface { get; set; }
+    public string? ToggleFullscreen { get; set; }
+    public string? WindowManagement { get; set; }
+    public string? InfoWindow { get; set; }
+    public string? EscCloseTooltip { get; set; }
+    public string? CloseApp { get; set; }
+    public string? MoveWindow { get; set; }
+    public string? CenterWindow { get; set; }
+    public string? HighlightColor { get; set; }
+    public string? Blue { get; set; }
+    public string? Cyan { get; set; }
+    public string? Aqua { get; set; }
+    public string? Teal { get; set; }
+    public string? Lime { get; set; }
+    public string? Green { get; set; }
+    public string? Golden { get; set; }
+    public string? Orange { get; set; }
+    public string? Red { get; set; }
+    public string? Pink { get; set; }
+    public string? Magenta { get; set; }
+    public string? Purple { get; set; }
+    public string? Theme { get; set; }
+    public string? DarkTheme { get; set; }
+    public string? LightTheme { get; set; }
+    public string? ChangingThemeRequiresRestart { get; set; }
+    public string? SetCurrentImageAsWallpaper { get; set; }
+    public string? Fill { get; set; }
+    public string? Center { get; set; }
+    public string? Fit { get; set; }
+    public string? Tile { get; set; }
+    public string? Stretch { get; set; }
+    public string? Language { get; set; }
+    public string? CtrlToZoom { get; set; }
+    public string? ScrollToZoom { get; set; }
+    public string? HorizontalScroll { get; set; }
+    public string? Reverse { get; set; }
+    public string? Forward { get; set; }
+    public string? GeneralSettings { get; set; }
+    public string? UISettings { get; set; }
+    public string? MiscSettings { get; set; }
+    public string? SearchSubdirectory { get; set; }
+    public string? StayTopMost { get; set; }
+    public string? StayCentered { get; set; }
+    public string? ColoredWindowBorder { get; set; }
+    public string? ShowButtonsInHiddenUI { get; set; }
+    public string? Apply { get; set; }
+    public string? AdjustTimingForSlideshow { get; set; }
+    public string? AdjustTimingForZoom { get; set; }
+    public string? SecAbbreviation { get; set; }
+    public string? RestartApp { get; set; }
+    public string? CheckForUpdates { get; set; }
+    public string? AllowZoomOut { get; set; }
+    public string? AdjustNavSpeed { get; set; }
+    public string? ToggleTaskbarProgress { get; set; }
+    public string? ShowFileSavingDialog { get; set; }
+    public string? ShowBottomToolbar { get; set; }
+    public string? BottomGalleryItemSize { get; set; }
+    public string? ExpandedGalleryItemSize { get; set; }
+    public string? ShowBottomGalleryWhenUiIsHidden { get; set; }
+    public string? ImageAliasing { get; set; }
+    public string? HighQuality { get; set; }
+    public string? NearestNeighbor { get; set; }
+    public string? NegativeColors { get; set; }
+    public string? BlackAndWhite { get; set; }
+    public string? ColorTone { get; set; }
+    public string? OldMovie { get; set; }
+    public string? Bloom { get; set; }
+    public string? Gloom { get; set; }
+    public string? Monochrome { get; set; }
+    public string? WaveWarper { get; set; }
+    public string? Underwater { get; set; }
+    public string? BandedSwirl { get; set; }
+    public string? Ripple { get; set; }
+    public string? RippleAlt { get; set; }
+    public string? Blur { get; set; }
+    public string? DirectionalBlur { get; set; }
+    public string? TelescopicBlur { get; set; }
+    public string? Pixelate { get; set; }
+    public string? Embossed { get; set; }
+    public string? SmoothMagnify { get; set; }
+    public string? Pivot { get; set; }
+    public string? PaperFold { get; set; }
+    public string? PencilSketch { get; set; }
+    public string? Sketch { get; set; }
+    public string? ToneMapping { get; set; }
+    public string? FrostyOutline { get; set; }
+    public string? Bands { get; set; }
+    public string? GlassTile { get; set; }
+    public string? Navigation { get; set; }
+    public string? NextImage { get; set; }
+    public string? PrevImage { get; set; }
+    public string? LastImage { get; set; }
+    public string? FirstImage { get; set; }
+    public string? ToggleLooping { get; set; }
+    public string? Slideshow { get; set; }
+    public string? NextFolder { get; set; }
+    public string? PrevFolder { get; set; }
+    public string? Zoom { get; set; }
+    public string? ZoomIn { get; set; }
+    public string? ZoomOut { get; set; }
+    public string? Pan { get; set; }
+    public string? MouseDrag { get; set; }
+    public string? ResetZoom { get; set; }
+    public string? ToggleScroll { get; set; }
+    public string? Open { get; set; }
+    public string? OpenWith { get; set; }
+    public string? OpenFileDialog { get; set; }
+    public string? OpenLastFile { get; set; }
+    public string? ShowInFolder { get; set; }
+    public string? Save { get; set; }
+    public string? SaveImage { get; set; }
+    public string? Print { get; set; }
+    public string? RecentFiles { get; set; }
+    public string? FileProperties { get; set; }
+    public string? DeleteFile { get; set; }
+    public string? Folder { get; set; }
+    public string? FullPath { get; set; }
+    public string? RenameFile { get; set; }
+    public string? UnsupportedFile { get; set; }
+    public string? SortFilesBy { get; set; }
+    public string? FileName { get; set; }
+    public string? FileSize { get; set; }
+    public string? CreationTime { get; set; }
+    public string? FileExtension { get; set; }
+    public string? LastAccessTime { get; set; }
+    public string? LastWriteTime { get; set; }
+    public string? Random { get; set; }
+    public string? Ascending { get; set; }
+    public string? Descending { get; set; }
+    public string? Settings { get; set; }
+    public string? Scrolling { get; set; }
+    public string? Looping { get; set; }
+    public string? FitToWindow { get; set; }
+    public string? ShowHideUI { get; set; }
+    public string? ChangeBackground { get; set; }
+    public string? ChangeBackgroundTooltip { get; set; }
+    public string? Copy { get; set; }
+    public string? AddedToClipboard { get; set; }
+    public string? CopyFile { get; set; }
+    public string? DuplicateFile { get; set; }
+    public string? FileCopy { get; set; }
+    public string? FileCopyPath { get; set; }
+    public string? FileCopyPathMessage { get; set; }
+    public string? FileCutMessage { get; set; }
+    public string? CopyImage { get; set; }
+    public string? CopiedImage { get; set; }
+    public string? CopyImageTooltip { get; set; }
+    public string? FilePaste { get; set; }
+    public string? FileCut { get; set; }
+    public string? ImageInfo { get; set; }
+    public string? Image { get; set; }
+    public string? Width { get; set; }
+    public string? Height { get; set; }
+    public string? Date { get; set; }
+    public string? Created { get; set; }
+    public string? Modified { get; set; }
+    public string? Size { get; set; }
+    public string? Pixels { get; set; }
+    public string? SizeMp { get; set; }
+    public string? MegaPixels { get; set; }
+    public string? Resolution { get; set; }
+    public string? Dpi { get; set; }
+    public string? DiskSize { get; set; }
+    public string? AspectRatio { get; set; }
+    public string? Portrait { get; set; }
+    public string? Landscape { get; set; }
+    public string? Square { get; set; }
+    public string? PrintSizeIn { get; set; }
+    public string? PrintSizeCm { get; set; }
+    public string? Centimeters { get; set; }
+    public string? Inches { get; set; }
+    public string? BitDepth { get; set; }
+    public string? SizeTooltip { get; set; }
+    public string? Del { get; set; }
+    public string? Ctrl { get; set; }
+    public string? Shift { get; set; }
+    public string? Alt { get; set; }
+    public string? Space { get; set; }
+    public string? Enter { get; set; }
+    public string? Esc { get; set; }
+    public string? NumpadPlus { get; set; }
+    public string? NumpadMinus { get; set; }
+    public string? MouseWheel { get; set; }
+    public string? MouseKeyForward { get; set; }
+    public string? MouseKeyBack { get; set; }
+    public string? DoubleClick { get; set; }
+    public string? Left { get; set; }
+    public string? Right { get; set; }
+    public string? Up { get; set; }
+    public string? Down { get; set; }
+    public string? SavingFileFailed { get; set; }
+    public string? UnexpectedError { get; set; }
+    public string? NoImages { get; set; }
+    public string? UnableToRender { get; set; }
+    public string? DragOverstring { get; set; }
+    public string? SetAs { get; set; }
+    public string? SetAsWallpaper { get; set; }
+    public string? SetAsLockScreenImage { get; set; }
+    public string? Crop { get; set; }
+    public string? RotateRight { get; set; }
+    public string? RotateLeft { get; set; }
+    public string? Flip { get; set; }
+    public string? Unflip { get; set; }
+    public string? BadArchive { get; set; }
+    public string? PasswordArchive { get; set; }
+    public string? SentFileToRecycleBin { get; set; }
+    public string? DeletedFile { get; set; }
+    public string? AnErrorOccuredWhenDeleting { get; set; }
+    public string? AutoFitWindowMessage { get; set; }
+    public string? AutoFitWindowFillHeight { get; set; }
+    public string? NormalWindowBehavior { get; set; }
+    public string? NormalWindowBehaviorFillHeight { get; set; }
+    public string? ScrollingEnabled { get; set; }
+    public string? ScrollingDisabled { get; set; }
+    public string? ConvertedToBase64 { get; set; }
+    public string? LoopingEnabled { get; set; }
+    public string? LoopingDisabled { get; set; }
+    public string? Applying { get; set; }
+    public string? ShowInfoWindow { get; set; }
+    public string? ShowAllSettingsWindow { get; set; }
+    public string? ToggleBackgroundColor { get; set; }
+    public string? ShowImageGallery { get; set; }
+    public string? GoToImageAtSpecifiedIndex { get; set; }
+    public string? AdjustZoomLevel { get; set; }
+    public string? PasteImageFromClipholder { get; set; }
+    public string? SendCurrentImageToRecycleBin { get; set; }
+    public string? StartSlideshow { get; set; }
+    public string? CloseGallery { get; set; }
+    public string? ShowBottomGallery { get; set; }
+    public string? HideBottomGallery { get; set; }
+    public string? StretchImage { get; set; }
+    public string? OptimizeImage { get; set; }
+    public string? Effects { get; set; }
+    public string? EffectsTooltip { get; set; }
+    public string? CropPicture { get; set; }
+    public string? ShowImageInfo { get; set; }
+    public string? ColorPickerTool { get; set; }
+    public string? ColorPickerToolTooltip { get; set; }
+    public string? ShowResizeWindow { get; set; }
+    public string? Resize { get; set; }
+    public string? ResizeImage { get; set; }
+    public string? NoResize { get; set; }
+    public string? BatchResize { get; set; }
+    public string? SourceFolder { get; set; }
+    public string? OutputFolder { get; set; }
+    public string? ConvertTo { get; set; }
+    public string? NoConversion { get; set; }
+    public string? Compression { get; set; }
+    public string? Lossless { get; set; }
+    public string? Lossy { get; set; }
+    public string? Qaulity { get; set; }
+    public string? Percentage { get; set; }
+    public string? GenerateThumbnails { get; set; }
+    public string? Thumbnail { get; set; }
+    public string? Start { get; set; }
+    public string? Cancel { get; set; }
+    public string? None { get; set; }
+    public string? ApplicationStartup { get; set; }
+    public string? OpenInSameWindow { get; set; }
+    public string? NoChange { get; set; }
+}

+ 35 - 7
src/PicView.Core/Localization/TranslationHelper.cs

@@ -1,23 +1,42 @@
 using PicView.Core.Config;
 using PicView.Core.Config;
 using System.Diagnostics;
 using System.Diagnostics;
+using System.IO;
 using System.Text.Json;
 using System.Text.Json;
+using System.Text.Json.Serialization;
 
 
 namespace PicView.Core.Localization;
 namespace PicView.Core.Localization;
 
 
+[JsonSourceGenerationOptions(WriteIndented = true)]
+[JsonSerializable(typeof(LanguageModel))]
+internal partial class LanguageSourceGenerationContext : JsonSerializerContext
+{
+}
+
 /// <summary>
 /// <summary>
 /// Helper class for managing language-related tasks.
 /// Helper class for managing language-related tasks.
 /// </summary>
 /// </summary>
 public static class TranslationHelper
 public static class TranslationHelper
 {
 {
-    public static string GetTranslation(string key)
+    public static string? GetTranslation(string key)
     {
     {
-        return Language is null ? string.Empty : Language.GetValueOrDefault(key, key);
+        if (Language == null)
+        {
+            return string.Empty;
+        }
+
+        var propertyInfo = typeof(LanguageModel).GetProperty(key);
+        if (propertyInfo == null)
+        {
+            return string.Empty;
+        }
+
+        return propertyInfo.GetValue(Language) as string ?? string.Empty;
     }
     }
 
 
     /// <summary>
     /// <summary>
     /// Dictionary to store language key-value pairs.
     /// Dictionary to store language key-value pairs.
     /// </summary>
     /// </summary>
-    internal static Dictionary<string, string>? Language;
+    internal static LanguageModel? Language;
 
 
     /// <summary>
     /// <summary>
     /// Determines the language based on the specified culture and loads the corresponding language file.
     /// Determines the language based on the specified culture and loads the corresponding language file.
@@ -31,8 +50,7 @@ public static class TranslationHelper
         {
         {
             if (File.Exists(jsonLanguageFile))
             if (File.Exists(jsonLanguageFile))
             {
             {
-                var text = await File.ReadAllTextAsync(jsonLanguageFile).ConfigureAwait(false);
-                Language = JsonSerializer.Deserialize<Dictionary<string, string>>(text);
+                await Deserialize(jsonLanguageFile).ConfigureAwait(false);
             }
             }
             else
             else
             {
             {
@@ -41,8 +59,7 @@ public static class TranslationHelper
                 var file = Directory.GetFiles(languagesDirectory, "*.json").FirstOrDefault();
                 var file = Directory.GetFiles(languagesDirectory, "*.json").FirstOrDefault();
                 if (file != null)
                 if (file != null)
                 {
                 {
-                    var text = await File.ReadAllTextAsync(file).ConfigureAwait(false);
-                    Language = JsonSerializer.Deserialize<Dictionary<string, string>>(text);
+                    await Deserialize(file).ConfigureAwait(false);
                 }
                 }
                 else
                 else
                 {
                 {
@@ -56,6 +73,17 @@ public static class TranslationHelper
             Trace.WriteLine($"{nameof(LoadLanguage)} exception:\n{exception.Message}");
             Trace.WriteLine($"{nameof(LoadLanguage)} exception:\n{exception.Message}");
 #endif
 #endif
         }
         }
+
+        return;
+
+        async Task Deserialize(string file)
+        {
+            var jsonString = await File.ReadAllTextAsync(file).ConfigureAwait(false);
+            var language = JsonSerializer.Deserialize(
+                    jsonString, typeof(LanguageModel), LanguageSourceGenerationContext.Default)
+                as LanguageModel;
+            Language = language;
+        }
     }
     }
 
 
     private static string DetermineLanguageFilePath(string isoLanguageCode)
     private static string DetermineLanguageFilePath(string isoLanguageCode)

+ 0 - 6
src/PicView.sln

@@ -19,8 +19,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PicView.Windows", "PicView.
 EndProject
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PicView.MacOS", "PicView.MacOS\PicView.MacOS.csproj", "{FEAC727E-1102-4F11-A747-5A5789FBBF81}"
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PicView.MacOS", "PicView.MacOS\PicView.MacOS.csproj", "{FEAC727E-1102-4F11-A747-5A5789FBBF81}"
 EndProject
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PicView.Avalonia.Theme", "PicView.Avalonia.Theme\PicView.Avalonia.Theme.csproj", "{EE8108EE-F9B9-44C3-AEAB-298BC503DF0D}"
-EndProject
 Global
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Debug|Any CPU = Debug|Any CPU
@@ -59,10 +57,6 @@ Global
 		{FEAC727E-1102-4F11-A747-5A5789FBBF81}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{FEAC727E-1102-4F11-A747-5A5789FBBF81}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{FEAC727E-1102-4F11-A747-5A5789FBBF81}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{FEAC727E-1102-4F11-A747-5A5789FBBF81}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{FEAC727E-1102-4F11-A747-5A5789FBBF81}.Release|Any CPU.Build.0 = Release|Any CPU
 		{FEAC727E-1102-4F11-A747-5A5789FBBF81}.Release|Any CPU.Build.0 = Release|Any CPU
-		{EE8108EE-F9B9-44C3-AEAB-298BC503DF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{EE8108EE-F9B9-44C3-AEAB-298BC503DF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{EE8108EE-F9B9-44C3-AEAB-298BC503DF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{EE8108EE-F9B9-44C3-AEAB-298BC503DF0D}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 		HideSolutionNode = FALSE

Some files were not shown because too many files changed in this diff