mirror of
https://github.com/GalaxyViewer/GalaxyViewer.git
synced 2026-08-14 09:02:08 +00:00
Merge pull request #7 from GalaxyViewer/dev
✨ Add Localization, Cleanup
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net8.0-android</TargetFramework>
|
||||
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ApplicationId>com.CompanyName.GalaxyViewer</ApplicationId>
|
||||
<ApplicationId>com.GalaxyViewer.GalaxyViewer</ApplicationId>
|
||||
<ApplicationVersion>1</ApplicationVersion>
|
||||
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
|
||||
<AndroidPackageFormat>apk</AndroidPackageFormat>
|
||||
|
||||
+3
-3
@@ -8,11 +8,11 @@ EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GalaxyViewer.Desktop", "GalaxyViewer.Desktop\GalaxyViewer.Desktop.csproj", "{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}"
|
||||
EndProject
|
||||
# Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GalaxyViewer.Browser", "GalaxyViewer.Browser\GalaxyViewer.Browser.csproj", "{1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}"
|
||||
EndProject
|
||||
# EndProject
|
||||
# Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GalaxyViewer.iOS", "GalaxyViewer.iOS\GalaxyViewer.iOS.csproj", "{EBD9022F-BC83-4846-9A11-6F7F3772DC64}"
|
||||
# EndProject
|
||||
# Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GalaxyViewer.Android", "GalaxyViewer.Android\GalaxyViewer.Android.csproj", "{7AD1DAC8-7FBE-49D5-8614-7321233DB82E}"
|
||||
# EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GalaxyViewer.Android", "GalaxyViewer.Android\GalaxyViewer.Android.csproj", "{7AD1DAC8-7FBE-49D5-8614-7321233DB82E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3DA99C4E-89E3-4049-9C22-0A7EC60D83D8}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Directory.Build.props = Directory.Build.props
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=metaverse/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -10,6 +10,8 @@
|
||||
</Application.DataTemplates>
|
||||
|
||||
<Application.Styles>
|
||||
<StyleInclude Source="avares://GalaxyViewer/Styles.axaml"></StyleInclude>
|
||||
<StyleInclude Source="avares://AvaloniaInside.Shell/Default.axaml"></StyleInclude>
|
||||
<FluentTheme />
|
||||
</Application.Styles>
|
||||
</Application>
|
||||
+20
-15
@@ -1,19 +1,21 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Serilog;
|
||||
using GalaxyViewer.ViewModels;
|
||||
using GalaxyViewer.Views;
|
||||
using GalaxyViewer.Services;
|
||||
using Serilog;
|
||||
|
||||
namespace GalaxyViewer;
|
||||
|
||||
public partial class App : Application
|
||||
public class App : Application
|
||||
{
|
||||
private readonly PreferencesManager _preferencesManager = new PreferencesManager();
|
||||
|
||||
public App()
|
||||
{
|
||||
// Initialize Serilog here
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.Debug()
|
||||
.WriteTo.Console()
|
||||
.WriteTo.File("logs/error.log", rollingInterval: RollingInterval.Day)
|
||||
.CreateLogger();
|
||||
@@ -26,19 +28,22 @@ public partial class App : Application
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
_preferencesManager.LoadPreferencesAsync();
|
||||
|
||||
switch (ApplicationLifetime)
|
||||
{
|
||||
desktop.MainWindow = new MainWindow
|
||||
{
|
||||
DataContext = new MainViewModel()
|
||||
};
|
||||
}
|
||||
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
|
||||
{
|
||||
singleViewPlatform.MainView = new MainView
|
||||
{
|
||||
DataContext = new MainViewModel()
|
||||
};
|
||||
case IClassicDesktopStyleApplicationLifetime desktop:
|
||||
desktop.MainWindow = new MainWindow
|
||||
{
|
||||
DataContext = new MainViewModel()
|
||||
};
|
||||
break;
|
||||
case ISingleViewApplicationLifetime singleViewPlatform:
|
||||
singleViewPlatform.MainView = new MainView
|
||||
{
|
||||
DataContext = new MainViewModel()
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
@@ -0,0 +1,31 @@
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Resources;
|
||||
|
||||
namespace GalaxyViewer.Assets.Localization
|
||||
{
|
||||
public class LocalizationManager : INotifyPropertyChanged
|
||||
{
|
||||
private readonly ResourceManager _resourceManager = new(typeof(Strings));
|
||||
private CultureInfo _currentCulture = CultureInfo.CurrentCulture;
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public string GetString(string name)
|
||||
{
|
||||
return _resourceManager.GetString(name, _currentCulture) ?? $"[{name}]";
|
||||
}
|
||||
|
||||
public void SetCulture(string cultureCode)
|
||||
{
|
||||
var newCulture = new CultureInfo(cultureCode);
|
||||
if (_currentCulture.Name != newCulture.Name)
|
||||
{
|
||||
_currentCulture = newCulture;
|
||||
CultureInfo.CurrentCulture = newCulture;
|
||||
CultureInfo.CurrentUICulture = newCulture;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace GalaxyViewer.Assets.Localization {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Strings {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Strings() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GalaxyViewer.Assets.Localization.Strings", typeof(Strings).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace GalaxyViewer.Assets.Localization {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Strings_en_US {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Strings_en_US() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GalaxyViewer.Assets.Localization.Strings.en-US", typeof(Strings_en_US).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Login.
|
||||
/// </summary>
|
||||
internal static string LoginScreenLoginButton {
|
||||
get {
|
||||
return ResourceManager.GetString("LoginScreenLoginButton", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Password.
|
||||
/// </summary>
|
||||
internal static string LoginScreenPassword {
|
||||
get {
|
||||
return ResourceManager.GetString("LoginScreenPassword", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Register.
|
||||
/// </summary>
|
||||
internal static string LoginScreenRegisterButton {
|
||||
get {
|
||||
return ResourceManager.GetString("LoginScreenRegisterButton", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Login.
|
||||
/// </summary>
|
||||
internal static string LoginScreenTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("LoginScreenTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Username.
|
||||
/// </summary>
|
||||
internal static string LoginScreenUsername {
|
||||
get {
|
||||
return ResourceManager.GetString("LoginScreenUsername", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>1.3</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<!-- Add your English strings here -->
|
||||
<!-- General Stuff -->
|
||||
<data name="ViewerName" xml:space="preserve">
|
||||
<value>GalaxyViewer</value>
|
||||
</data>
|
||||
<data name="Version" xml:space="preserve">
|
||||
<value>0.1</value>
|
||||
</data>
|
||||
<data name="WelcomeMessage" xml:space="preserve">
|
||||
<value>Welcome to GalaxyViewer 🌌</value>
|
||||
</data>
|
||||
<data name="Error" xml:space="preserve">
|
||||
<value>Error</value>
|
||||
</data>
|
||||
<data name="Ok" xml:space="preserve">
|
||||
<value>Ok</value>
|
||||
</data>
|
||||
<data name="Cancel" xml:space="preserve">
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<!-- Login Screen -->
|
||||
<data name="LoginScreenTitle" xml:space="preserve">
|
||||
<value>Login</value>
|
||||
</data>
|
||||
<data name="LoginScreenUsername" xml:space="preserve">
|
||||
<value>Username</value>
|
||||
</data>
|
||||
<data name="LoginScreenPassword" xml:space="preserve">
|
||||
<value>Password</value>
|
||||
</data>
|
||||
<data name="LoginLocation" xml:space="preserve">
|
||||
<value>Login Location</value>
|
||||
</data>
|
||||
<data name="LoginScreenGrid" xml:space="preserve">
|
||||
<value>Grid</value>
|
||||
</data>
|
||||
<data name="LoginScreenLoginButton" xml:space="preserve">
|
||||
<value>Login</value>
|
||||
</data>
|
||||
<data name="LoginSuceess" xml:space="preserve">
|
||||
<value>Login successful</value>
|
||||
</data>
|
||||
<data name="LoginScreenWrongCredentials" xml:space="preserve">
|
||||
<value>Wrong username or password</value>
|
||||
</data>
|
||||
<!-- Preferences Screen -->
|
||||
<data name="PreferencesTitle" xml:space="preserve">
|
||||
<value>Preferences</value>
|
||||
</data>
|
||||
<data name="PreferencesLanguage" xml:space="preserve">
|
||||
<value>Language</value>
|
||||
</data>
|
||||
<data name="PreferencesLoginLocation" xml:space="preserve">
|
||||
<value>Login Location</value>
|
||||
</data>
|
||||
<data name="PreferencesTheme" xml:space="preserve">
|
||||
<value>Theme</value>
|
||||
</data>
|
||||
<data name="PreferencesFont" xml:space="preserve">
|
||||
<value>Font</value>
|
||||
</data>
|
||||
<data name="PreferencesSaveButton" xml:space="preserve">
|
||||
<value>Save Preferences</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
This is in English (United States) language, as the default. It is in case there is no other language file available.
|
||||
-->
|
||||
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>1.3</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<!-- General Stuff -->
|
||||
<data name="ViewerName" xml:space="preserve">
|
||||
<value>GalaxyViewer</value>
|
||||
</data>
|
||||
<data name="Version" xml:space="preserve">
|
||||
<value>0.1</value>
|
||||
</data>
|
||||
<data name="WelcomeMessage" xml:space="preserve">
|
||||
<value>Welcome to GalaxyViewer 🌌</value>
|
||||
</data>
|
||||
<data name="Error" xml:space="preserve">
|
||||
<value>Error</value>
|
||||
</data>
|
||||
<data name="Ok" xml:space="preserve">
|
||||
<value>Ok</value>
|
||||
</data>
|
||||
<data name="Cancel" xml:space="preserve">
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<!-- Login Screen -->
|
||||
<data name="LoginScreenTitle" xml:space="preserve">
|
||||
<value>Login</value>
|
||||
</data>
|
||||
<data name="LoginScreenUsername" xml:space="preserve">
|
||||
<value>Username</value>
|
||||
</data>
|
||||
<data name="LoginScreenPassword" xml:space="preserve">
|
||||
<value>Password</value>
|
||||
</data>
|
||||
<data name="LoginLocation" xml:space="preserve">
|
||||
<value>Login Location</value>
|
||||
</data>
|
||||
<data name="LoginScreenGrid" xml:space="preserve">
|
||||
<value>Grid</value>
|
||||
</data>
|
||||
<data name="LoginScreenLoginButton" xml:space="preserve">
|
||||
<value>Login</value>
|
||||
</data>
|
||||
<data name="LoginSuceess" xml:space="preserve">
|
||||
<value>Login successful</value>
|
||||
</data>
|
||||
<data name="LoginScreenWrongCredentials" xml:space="preserve">
|
||||
<value>Wrong username or password</value>
|
||||
</data>
|
||||
<!-- Preferences Screen -->
|
||||
<data name="PreferencesTitle" xml:space="preserve">
|
||||
<value>Preferences</value>
|
||||
</data>
|
||||
<data name="PreferencesLanguage" xml:space="preserve">
|
||||
<value>Language</value>
|
||||
</data>
|
||||
<data name="PreferencesLoginLocation" xml:space="preserve">
|
||||
<value>Login Location</value>
|
||||
</data>
|
||||
<data name="PreferencesTheme" xml:space="preserve">
|
||||
<value>Theme</value>
|
||||
</data>
|
||||
<data name="PreferencesFont" xml:space="preserve">
|
||||
<value>Font</value>
|
||||
</data>
|
||||
<data name="PreferencesSaveButton" xml:space="preserve">
|
||||
<value>Save Preferences</value>
|
||||
</data>
|
||||
</root>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 184 KiB |
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferencesModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Theme>Default</Theme>
|
||||
<LoginLocation>Home</LoginLocation>
|
||||
<Font>Atkinson Hyperlegible</Font>
|
||||
<Language>en-US</Language>
|
||||
<LastSavedEpoch>1721172337</LastSavedEpoch>
|
||||
</PreferencesModel>
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Avalonia.Data.Converters;
|
||||
using GalaxyViewer.Assets.Localization;
|
||||
|
||||
namespace GalaxyViewer.Converters;
|
||||
|
||||
public class LocalizedStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (parameter is string key) return new LocalizationManager().GetString(key);
|
||||
return "Key not found for " + value;
|
||||
}
|
||||
|
||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
// Change to en-US if the language is not found
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -3,29 +3,70 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
<!-- Local NuGet package sources here -->
|
||||
<RestoreSources>$(RestoreSources);./Libs;</RestoreSources>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="Assets\**" />
|
||||
<AvaloniaResource Include="Assets\**"/>
|
||||
<None Update="Assets\galaxy.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Include="Assets\Fonts\*.ttf">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="$(AvaloniaVersion)" />
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="$(AvaloniaVersion)" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="$(AvaloniaVersion)" />
|
||||
<Watch Include="**\*.axaml"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)"/>
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="$(AvaloniaVersion)"/>
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="$(AvaloniaVersion)"/>
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="$(AvaloniaVersion)"/>
|
||||
<!-- Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration. -->
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)"/>
|
||||
<!-- More things will go here -->
|
||||
<PackageReference Include="LibreMetaverse" Version="2.0.10.*" />
|
||||
<PackageReference Include="AvaloniaInside.Shell" Version="1.1.3"/>
|
||||
<PackageReference Include="LibreMetaverse" Version="2.0.11.636"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Logging -->
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="MessageBox.Avalonia" Version="3.1.5.1"/>
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Assets\Localization\Strings.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Assets\Localization\Strings.en-US.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Strings.en.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Assets\Localization\Strings.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Strings.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Assets\Localization\Strings.en-US.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Strings.en-US.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Libs\"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,61 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GalaxyViewer.Models
|
||||
{
|
||||
public enum ThemeOptions
|
||||
{
|
||||
Light,
|
||||
Dark,
|
||||
System
|
||||
}
|
||||
|
||||
public enum LoginLocationOptions
|
||||
{
|
||||
Home,
|
||||
LastLocation
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class PreferencesModel
|
||||
{
|
||||
private string _theme = Enum.TryParse(typeof(ThemeOptions), "System", out _) ? "System" : "Light";
|
||||
private string _loginLocation = Enum.TryParse(typeof(LoginLocationOptions), "LastLocation", out _) ? "LastLocation" : "Home";
|
||||
public long LastSavedEpoch { get; set; } // Hidden from UI, but stored
|
||||
public List<string> ThemeOptions { get; set; } = ["Light", "Dark", "Default"];
|
||||
public List<string> LoginLocationOptions { get; set; } = ["Home", "Last Location"];
|
||||
public List<string> FontOptions { get; set; } =
|
||||
["Inter", "Atkinson Hyperlegible"];
|
||||
public List<string> LanguageOptions { get; set; } = ["en-US"];
|
||||
|
||||
public string Theme
|
||||
{
|
||||
get => _theme;
|
||||
set
|
||||
{
|
||||
if (IsValidTheme(value))
|
||||
{
|
||||
_theme = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid theme value: {value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string LoginLocation
|
||||
{
|
||||
get => _loginLocation;
|
||||
set
|
||||
{
|
||||
if (IsValidLoginLocation(value))
|
||||
{
|
||||
_loginLocation = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid login location value: {value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assuming ThemeOptions and LoginLocationOptions are enums or similar
|
||||
private bool IsValidTheme(string theme) => Enum.TryParse(typeof(ThemeOptions), theme, out _);
|
||||
private bool IsValidLoginLocation(string location) => Enum.TryParse(typeof(LoginLocationOptions), location, out _);
|
||||
// Default values
|
||||
public string Theme { get; set; } = "Default";
|
||||
public string LoginLocation { get; set; } = "Home";
|
||||
public string Font { get; set; } = "Atkinson Hyperlegible";
|
||||
public string Language { get; set; } = "en-US";
|
||||
public long LastSavedEpoch { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -10,30 +10,28 @@ namespace GalaxyViewer.Services
|
||||
{
|
||||
public List<Grid> ParseGridsFromXml()
|
||||
{
|
||||
string xmlFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "grids.xml");
|
||||
var xdoc = XDocument.Load(xmlFilePath);
|
||||
var xmlFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "grids.xml");
|
||||
var xDoc = XDocument.Load(xmlFilePath);
|
||||
var grids = new List<Grid>();
|
||||
|
||||
if (xdoc.Root != null)
|
||||
if (xDoc.Root == null) return grids;
|
||||
foreach (var gridElement in xDoc.Root.Elements("grid"))
|
||||
{
|
||||
foreach (var gridElement in xdoc.Root.Elements("grid"))
|
||||
{
|
||||
var grid = new Grid(
|
||||
gridElement.Element("gridnick")?.Value ?? string.Empty,
|
||||
gridElement.Element("gridname")?.Value ?? string.Empty,
|
||||
gridElement.Element("platform")?.Value ?? string.Empty,
|
||||
gridElement.Element("loginuri")?.Value ?? string.Empty,
|
||||
gridElement.Element("loginpage")?.Value ?? string.Empty,
|
||||
gridElement.Element("helperuri")?.Value ?? string.Empty,
|
||||
gridElement.Element("website")?.Value ?? string.Empty,
|
||||
gridElement.Element("support")?.Value ?? string.Empty,
|
||||
gridElement.Element("register")?.Value ?? string.Empty,
|
||||
gridElement.Element("password")?.Value ?? string.Empty,
|
||||
gridElement.Element("version")?.Value ?? string.Empty
|
||||
);
|
||||
var grid = new Grid(
|
||||
gridElement.Element("gridnick")?.Value ?? string.Empty,
|
||||
gridElement.Element("gridname")?.Value ?? string.Empty,
|
||||
gridElement.Element("platform")?.Value ?? string.Empty,
|
||||
gridElement.Element("loginuri")?.Value ?? string.Empty,
|
||||
gridElement.Element("loginpage")?.Value ?? string.Empty,
|
||||
gridElement.Element("helperuri")?.Value ?? string.Empty,
|
||||
gridElement.Element("website")?.Value ?? string.Empty,
|
||||
gridElement.Element("support")?.Value ?? string.Empty,
|
||||
gridElement.Element("register")?.Value ?? string.Empty,
|
||||
gridElement.Element("password")?.Value ?? string.Empty,
|
||||
gridElement.Element("version")?.Value ?? string.Empty
|
||||
);
|
||||
|
||||
grids.Add(grid);
|
||||
}
|
||||
grids.Add(grid);
|
||||
}
|
||||
|
||||
return grids;
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using GalaxyViewer.Models;
|
||||
using Serilog;
|
||||
|
||||
namespace GalaxyViewer.Services;
|
||||
|
||||
public class PreferencesManager
|
||||
{
|
||||
private readonly string _preferencesFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "GalaxyViewer", "preferences.xml");
|
||||
private bool _preferencesLoaded;
|
||||
|
||||
public PreferencesManager()
|
||||
{
|
||||
EnsurePreferencesDirectory();
|
||||
}
|
||||
|
||||
private void EnsurePreferencesDirectory()
|
||||
{
|
||||
var directoryPath = Path.GetDirectoryName(_preferencesFilePath);
|
||||
if (!string.IsNullOrEmpty(directoryPath))
|
||||
{
|
||||
Directory.CreateDirectory(directoryPath);
|
||||
}
|
||||
}
|
||||
|
||||
public Task<PreferencesModel> LoadPreferencesAsync()
|
||||
{
|
||||
if (_preferencesLoaded)
|
||||
{
|
||||
return Task.FromResult(new PreferencesModel());
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!File.Exists(_preferencesFilePath))
|
||||
{
|
||||
_preferencesLoaded = true;
|
||||
return Task.FromResult(new PreferencesModel());
|
||||
}
|
||||
|
||||
using var stream = new FileStream(_preferencesFilePath, FileMode.Open, FileAccess.Read);
|
||||
var serializer = new XmlSerializer(typeof(PreferencesModel));
|
||||
var preferences = (PreferencesModel)serializer.Deserialize(stream)!;
|
||||
_preferencesLoaded = true;
|
||||
return Task.FromResult(preferences);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed to load preferences");
|
||||
_preferencesLoaded = true;
|
||||
return Task.FromResult(new PreferencesModel());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SavePreferencesAsync(PreferencesModel preferences)
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var stream = new FileStream(_preferencesFilePath, FileMode.Create, FileAccess.Write);
|
||||
var serializer = new XmlSerializer(typeof(PreferencesModel));
|
||||
serializer.Serialize(stream, preferences);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed to save preferences");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Style Selector="TextBlock">
|
||||
<Setter Property="FontFamily" Value="avares://GalaxyViewer/Assets/Fonts/#Noto Emoji, avar://GalaxyViewer/Assets/Fonts/#Atkinson Hyperlegible" />
|
||||
</Style>
|
||||
</Styles>
|
||||
@@ -0,0 +1,67 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.RegularExpressions;
|
||||
using ReactiveUI;
|
||||
using System.ComponentModel;
|
||||
using GalaxyViewer.Assets.Localization;
|
||||
using Serilog;
|
||||
using OpenMetaverse;
|
||||
|
||||
namespace GalaxyViewer.ViewModels;
|
||||
|
||||
public abstract partial class LoginViewModel : ReactiveObject
|
||||
{
|
||||
private string _username;
|
||||
private string _password;
|
||||
private readonly GridClient _client = new GridClient();
|
||||
private readonly LocalizationManager _localizationManager;
|
||||
|
||||
protected LoginViewModel(string username, string password,
|
||||
LocalizationManager localizationManager)
|
||||
{
|
||||
_username = username;
|
||||
_password = password;
|
||||
_localizationManager = localizationManager;
|
||||
ReactiveCommand.Create(TryLoginAsync);
|
||||
}
|
||||
|
||||
public string Username
|
||||
{
|
||||
get => _username;
|
||||
set => this.RaiseAndSetIfChanged(ref _username, value);
|
||||
}
|
||||
|
||||
public string Password
|
||||
{
|
||||
get => _password;
|
||||
set => this.RaiseAndSetIfChanged(ref _password, value);
|
||||
}
|
||||
|
||||
private async void TryLoginAsync()
|
||||
{
|
||||
/*var loginParams = new LoginParams(
|
||||
_client,
|
||||
MyRegex().Split(Username.Trim())[0], // firstName
|
||||
MyRegex().Split(Username.Trim()).Length > 1
|
||||
? MyRegex().Split(Username.Trim())[1]
|
||||
: "Resident", // lastName
|
||||
Password,
|
||||
ViewerName,
|
||||
ViewerVersion,
|
||||
DetermineGridUrl())
|
||||
{
|
||||
LoginLocation = DetermineStartLocation(),
|
||||
AgreeToTos = true // Assuming you have a way to get this value
|
||||
};
|
||||
|
||||
var loginSuccess = await Task.Run(() => _client.Network.Login(loginParams));
|
||||
|
||||
if (loginSuccess)
|
||||
{
|
||||
Log.Information(LoginSuccess);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Logger.Error(LoginFailed);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using GalaxyViewer.Views;
|
||||
using ReactiveUI;
|
||||
using System.Reactive;
|
||||
using System.Threading.Tasks;
|
||||
using OpenMetaverse;
|
||||
using System.IO;
|
||||
using System.Windows.Input;
|
||||
using ReactiveUI;
|
||||
using Serilog;
|
||||
using Avalonia;
|
||||
|
||||
namespace GalaxyViewer.ViewModels
|
||||
{
|
||||
@@ -18,13 +20,39 @@ namespace GalaxyViewer.ViewModels
|
||||
private UserControl? _currentView;
|
||||
private bool _isLoggedIn;
|
||||
|
||||
private GridClient _client = new GridClient();
|
||||
private readonly GridClient _client = new();
|
||||
|
||||
// Define properties for Username, Password, LoginLocation, and Grid.
|
||||
public string? Username { get; set; }
|
||||
public string? Password { get; set; }
|
||||
public string? LoginLocation { get; set; }
|
||||
public string? Grid { get; set; }
|
||||
private string? _username;
|
||||
|
||||
public string? Username
|
||||
{
|
||||
get => _username;
|
||||
set => this.RaiseAndSetIfChanged(ref _username, value);
|
||||
}
|
||||
|
||||
private string? _password;
|
||||
|
||||
public string? Password
|
||||
{
|
||||
get => _password;
|
||||
set => this.RaiseAndSetIfChanged(ref _password, value);
|
||||
}
|
||||
|
||||
private string? _loginLocation;
|
||||
|
||||
public string? LoginLocation
|
||||
{
|
||||
get => _loginLocation;
|
||||
set => this.RaiseAndSetIfChanged(ref _loginLocation, value);
|
||||
}
|
||||
|
||||
private string? _grid;
|
||||
|
||||
public string? Grid
|
||||
{
|
||||
get => _grid;
|
||||
set => this.RaiseAndSetIfChanged(ref _grid, value);
|
||||
}
|
||||
|
||||
public UserControl? CurrentView
|
||||
{
|
||||
@@ -38,13 +66,12 @@ namespace GalaxyViewer.ViewModels
|
||||
set
|
||||
{
|
||||
this.RaiseAndSetIfChanged(ref _isLoggedIn, value);
|
||||
CurrentView = value ? (UserControl)new LoggedInView() : new LoginView();
|
||||
CurrentView = value ? new LoggedInView() : new LoginView();
|
||||
}
|
||||
}
|
||||
|
||||
public ReactiveCommand<Unit, Unit> LogoutCommand { get; }
|
||||
public ReactiveCommand<Unit, Unit> LoginCommand { get; }
|
||||
public ReactiveCommand<Unit, Unit> LoginWithCurrentValues { get; }
|
||||
|
||||
public ICommand ShowPreferencesCommand { get; }
|
||||
|
||||
@@ -57,7 +84,6 @@ namespace GalaxyViewer.ViewModels
|
||||
|
||||
LogoutCommand = ReactiveCommand.Create(Logout);
|
||||
LoginCommand = ReactiveCommand.Create(DisplayLoginView);
|
||||
LoginWithCurrentValues = ReactiveCommand.CreateFromTask(Login);
|
||||
|
||||
ShowPreferencesCommand = ReactiveCommand.Create(ShowPreferences);
|
||||
|
||||
@@ -76,23 +102,24 @@ namespace GalaxyViewer.ViewModels
|
||||
CurrentView = new LoginView();
|
||||
}
|
||||
|
||||
public async Task Login()
|
||||
public async Task Login(string username, string password)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Validate properties before using them
|
||||
if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password))
|
||||
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
|
||||
{
|
||||
// Handle invalid login parameters
|
||||
// For example, you might want to show an error message
|
||||
// or log the invalid login attempt to a file
|
||||
File.AppendAllText("error.log", "Invalid login parameters for user: " + Username);
|
||||
await File.AppendAllTextAsync("error.log",
|
||||
"Invalid login parameters for user: " + username);
|
||||
return;
|
||||
}
|
||||
|
||||
string userAgent = "GalaxyViewer/0.1.0";
|
||||
LoginParams libreMetaverseLoginParams = _client.Network.DefaultLoginParams(Username, Password, userAgent, LoginLocation, Grid);
|
||||
const string userAgent = "GalaxyViewer/0.1.0";
|
||||
var libreMetaverseLoginParams =
|
||||
_client.Network.DefaultLoginParams(username, password, userAgent, LoginLocation,
|
||||
Grid);
|
||||
|
||||
bool loginSuccess = await Task.Run(() => _client.Network.Login(libreMetaverseLoginParams));
|
||||
var loginSuccess =
|
||||
await Task.Run(() => _client.Network.Login(libreMetaverseLoginParams));
|
||||
|
||||
if (loginSuccess)
|
||||
{
|
||||
@@ -100,27 +127,33 @@ namespace GalaxyViewer.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle failed login
|
||||
Log.Error("Failed to login user: {Username}", Username);
|
||||
Log.Error("Failed to login user: {Username}", username);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Handle any exceptions that occur during login
|
||||
Log.Error(ex, "An error occurred while logging in user: {Username}", Username);
|
||||
Log.Error(ex, "An error occurred while logging in user: {Username}", username);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowPreferences()
|
||||
{
|
||||
CurrentView = new PreferencesView
|
||||
#if ANDROID
|
||||
CurrentView = new PreferencesView();
|
||||
#else
|
||||
var preferencesWindow = new PreferencesWindow
|
||||
{
|
||||
DataContext = new PreferencesViewModel()
|
||||
};
|
||||
preferencesWindow.Show();
|
||||
#endif
|
||||
}
|
||||
|
||||
private void ExitApplication()
|
||||
{
|
||||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime)
|
||||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime
|
||||
desktopLifetime)
|
||||
{
|
||||
desktopLifetime.Shutdown();
|
||||
}
|
||||
|
||||
@@ -1,123 +1,224 @@
|
||||
using GalaxyViewer.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reactive;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using GalaxyViewer.Models;
|
||||
using GalaxyViewer.Services;
|
||||
using ReactiveUI;
|
||||
using System.Reactive;
|
||||
using Serilog;
|
||||
|
||||
namespace GalaxyViewer.ViewModels
|
||||
{
|
||||
public class PreferencesViewModel : ReactiveObject
|
||||
public sealed class PreferencesViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public IEnumerable<string> ThemeOptions => Enum.GetNames(typeof(ThemeOptions));
|
||||
private PreferencesModel _preferences = new();
|
||||
private readonly PreferencesManager _preferencesManager = new();
|
||||
|
||||
public IEnumerable<string> LoginLocationOptions => Enum.GetNames(typeof(LoginLocationOptions));
|
||||
private string _selectedLanguage = "en-US";
|
||||
private string _selectedTheme = "Default";
|
||||
private string _selectedFont = "Atkinson Hyperlegible";
|
||||
private string _selectedLoginLocation = "Home";
|
||||
|
||||
public IEnumerable<string> LanguageOptions => _preferences.LanguageOptions;
|
||||
|
||||
public string SelectedLanguage
|
||||
{
|
||||
get => _selectedLanguage;
|
||||
set
|
||||
{
|
||||
if (_selectedLanguage == value) return;
|
||||
_selectedLanguage = value;
|
||||
OnPropertyChanged(nameof(SelectedLanguage));
|
||||
_preferences.Language = value;
|
||||
ChangeCulture(value);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> ThemeOptions => _preferences.ThemeOptions;
|
||||
|
||||
public string SelectedTheme
|
||||
{
|
||||
get => _selectedTheme;
|
||||
set
|
||||
{
|
||||
if (_selectedTheme == value) return;
|
||||
_selectedTheme = value;
|
||||
OnPropertyChanged(nameof(SelectedTheme));
|
||||
_preferences.Theme = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> FontOptions => _preferences.FontOptions;
|
||||
|
||||
public string SelectedFont
|
||||
{
|
||||
get => _selectedFont;
|
||||
set
|
||||
{
|
||||
if (_selectedFont == value) return;
|
||||
_selectedFont = value;
|
||||
OnPropertyChanged(nameof(SelectedFont));
|
||||
_preferences.Font = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> LoginLocationOptions => _preferences.LoginLocationOptions;
|
||||
|
||||
public string SelectedLoginLocation
|
||||
{
|
||||
get => _selectedLoginLocation;
|
||||
set
|
||||
{
|
||||
if (_selectedLoginLocation == value) return;
|
||||
_selectedLoginLocation = value;
|
||||
OnPropertyChanged(nameof(SelectedLoginLocation));
|
||||
_preferences.LoginLocation = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ChangeCulture(string cultureName)
|
||||
{
|
||||
CultureInfo.CurrentCulture = new CultureInfo(cultureName);
|
||||
CultureInfo.CurrentUICulture = new CultureInfo(cultureName);
|
||||
}
|
||||
|
||||
public PreferencesModel Preferences
|
||||
{
|
||||
get => _preferences;
|
||||
set
|
||||
{
|
||||
_preferences = value;
|
||||
OnPropertyChanged(nameof(Preferences));
|
||||
}
|
||||
}
|
||||
|
||||
private Lazy<PreferencesModel> _lazyPreferences;
|
||||
private readonly string _preferencesFilePath;
|
||||
public ReactiveCommand<Unit, Unit> SaveCommand { get; }
|
||||
public ReactiveCommand<Unit, Unit>? SaveCommand { get; private set; }
|
||||
|
||||
public PreferencesViewModel()
|
||||
{
|
||||
_preferencesFilePath = GetPreferencesFilePath();
|
||||
_lazyPreferences = new Lazy<PreferencesModel>(LoadOrCreatePreferences);
|
||||
_preferencesFilePath =
|
||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"GalaxyViewer", "preferences.xml");
|
||||
var directoryPath = Path.GetDirectoryName(_preferencesFilePath);
|
||||
if (directoryPath != null)
|
||||
{
|
||||
_ = Directory.CreateDirectory(directoryPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("Failed to create preferences directory");
|
||||
}
|
||||
|
||||
SaveCommand = ReactiveCommand.CreateFromTask(SavePreferencesAsync);
|
||||
|
||||
Task.Run(InitializeAsync).Wait();
|
||||
}
|
||||
|
||||
public static async Task<PreferencesViewModel> CreateAsync()
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
var viewModel = new PreferencesViewModel();
|
||||
await viewModel.LoadPreferencesAsync();
|
||||
return viewModel;
|
||||
Preferences = await _preferencesManager.LoadPreferencesAsync();
|
||||
|
||||
// Update local fields from loaded preferences
|
||||
_selectedLanguage = Preferences.Language;
|
||||
_selectedTheme = Preferences.Theme;
|
||||
_selectedFont = Preferences.Font;
|
||||
_selectedLoginLocation = Preferences.LoginLocation;
|
||||
|
||||
// Notify the UI to update
|
||||
OnPropertyChanged(nameof(SelectedLanguage));
|
||||
OnPropertyChanged(nameof(SelectedTheme));
|
||||
OnPropertyChanged(nameof(SelectedFont));
|
||||
OnPropertyChanged(nameof(SelectedLoginLocation));
|
||||
|
||||
ChangeCulture(
|
||||
_selectedLanguage);
|
||||
}
|
||||
|
||||
private PreferencesModel Preferences => _lazyPreferences.Value;
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
private static string GetPreferencesFilePath()
|
||||
private void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
var appDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
var applicationFolder = Path.Combine(appDataFolder, "GalaxyViewer");
|
||||
Directory.CreateDirectory(applicationFolder); // CreateDirectory is no-op if exists
|
||||
return Path.Combine(applicationFolder, "preferences.xml");
|
||||
}
|
||||
|
||||
private PreferencesModel LoadOrCreatePreferences()
|
||||
{
|
||||
if (File.Exists(_preferencesFilePath))
|
||||
{
|
||||
using var stream = new FileStream(_preferencesFilePath, FileMode.Open);
|
||||
var serializer = new XmlSerializer(typeof(PreferencesModel));
|
||||
return serializer.Deserialize(stream) as PreferencesModel ?? new PreferencesModel();
|
||||
}
|
||||
return new PreferencesModel
|
||||
{
|
||||
Theme = Enum.TryParse(typeof(ThemeOptions), "System", out object themeResult) ? themeResult.ToString() : Models.ThemeOptions.Light.ToString(),
|
||||
LoginLocation = Enum.TryParse(typeof(LoginLocationOptions), "LastLocation", out object loginLocationResult) ? loginLocationResult.ToString() : Models.LoginLocationOptions.Home.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
private string _theme;
|
||||
public string Theme
|
||||
{
|
||||
get => Preferences.Theme;
|
||||
set
|
||||
{
|
||||
if (Preferences.Theme != value)
|
||||
{
|
||||
Preferences.Theme = value;
|
||||
this.RaisePropertyChanged(nameof(Theme));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _loginLocation;
|
||||
public string LoginLocation
|
||||
{
|
||||
get => Preferences.LoginLocation;
|
||||
set
|
||||
{
|
||||
if (Preferences.LoginLocation != value)
|
||||
{
|
||||
Preferences.LoginLocation = value;
|
||||
this.RaisePropertyChanged(nameof(LoginLocation));
|
||||
}
|
||||
}
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
private string _statusMessage = string.Empty;
|
||||
|
||||
public string StatusMessage
|
||||
{
|
||||
get => _statusMessage;
|
||||
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
|
||||
}
|
||||
|
||||
public async Task LoadPreferencesAsync()
|
||||
{
|
||||
await Task.Run(() =>
|
||||
set
|
||||
{
|
||||
_lazyPreferences = new Lazy<PreferencesModel>(LoadOrCreatePreferences);
|
||||
});
|
||||
_statusMessage = value;
|
||||
OnPropertyChanged(nameof(StatusMessage));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SavePreferencesAsync()
|
||||
public async Task<PreferencesModel> LoadPreferencesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Step 1: Check and copy default preferences if necessary
|
||||
var defaultPreferencesPath = Path.Combine("Assets", "preferences.xml");
|
||||
if (!File.Exists(_preferencesFilePath) && File.Exists(defaultPreferencesPath))
|
||||
{
|
||||
File.Copy(defaultPreferencesPath, _preferencesFilePath);
|
||||
}
|
||||
|
||||
// Step 2: Open the preferences file
|
||||
await using var stream = new FileStream(_preferencesFilePath, FileMode.OpenOrCreate,
|
||||
FileAccess.Read, FileShare.Read);
|
||||
var serializer = new XmlSerializer(typeof(PreferencesModel));
|
||||
|
||||
// Step 3 & 4: Deserialize the XML content
|
||||
var loadedPreferences = await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = serializer.Deserialize(stream);
|
||||
if (result is PreferencesModel preferences)
|
||||
{
|
||||
return preferences;
|
||||
}
|
||||
|
||||
throw new InvalidCastException(
|
||||
"Deserialized object is not of type PreferencesModel.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Step 5: Handle deserialization failure
|
||||
Log.Error(ex, "Failed to deserialize preferences");
|
||||
StatusMessage = "Failed to load preferences. Using default settings.";
|
||||
return new PreferencesModel(); // Return default preferences on error
|
||||
}
|
||||
});
|
||||
return loadedPreferences;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Step 6: Handle any other exceptions
|
||||
Log.Error(ex, "Error loading preferences");
|
||||
StatusMessage = "Error loading preferences. Using default settings.";
|
||||
return new PreferencesModel(); // Return default preferences on error
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SavePreferencesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
Preferences.LastSavedEpoch = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
|
||||
using var stream = new FileStream(_preferencesFilePath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true);
|
||||
var serializer = new XmlSerializer(typeof(PreferencesModel));
|
||||
|
||||
await Task.Run(() => serializer.Serialize(stream, Preferences));
|
||||
|
||||
StatusMessage = "Preferences saved";
|
||||
await _preferencesManager.SavePreferencesAsync(Preferences);
|
||||
StatusMessage = "Preferences saved successfully.";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
StatusMessage = $"Error saving preferences: {ex.Message}";
|
||||
Log.Error(ex, "Error saving preferences");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace GalaxyViewer.Views
|
||||
{
|
||||
public class BaseWindow : Window
|
||||
{
|
||||
protected BaseWindow()
|
||||
{
|
||||
Icon = new WindowIcon("Assets/galaxy.ico");
|
||||
CanResize = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,45 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="GalaxyViewer.Views.LoginView">
|
||||
<StackPanel Margin="20">
|
||||
<TextBox Name="UsernameBox" Watermark="Username" />
|
||||
<TextBox Name="PasswordBox" Watermark="Password" PasswordChar="*" />
|
||||
<Button Content="Login" Margin="0,10,0,0" Click="LoginButton_Click" />
|
||||
</StackPanel>
|
||||
x:Class="GalaxyViewer.Views.LoginView"
|
||||
xmlns:converters="clr-namespace:GalaxyViewer.Converters"
|
||||
xmlns:viewModels="clr-namespace:GalaxyViewer.ViewModels"
|
||||
x:DataType="viewModels:LoginViewModel">
|
||||
<UserControl.Resources>
|
||||
<converters:LocalizedStringConverter x:Key="LocalizedStringConverter" />
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<!-- WebView or Image goes here -->
|
||||
<Image Grid.Row="0" Source="/Assets/Images/banner.jpg" Stretch="Fill" />
|
||||
<!-- Login Options -->
|
||||
<Grid Grid.Row="1" Margin="20">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="240" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="240" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0"
|
||||
Content="{Binding Converter={StaticResource LocalizedStringConverter}, ConverterParameter=LoginScreenUsername}"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Grid.Column="1" Name="UsernameBox"
|
||||
Watermark="{Binding Converter={StaticResource LocalizedStringConverter}, ConverterParameter=LoginScreenUsername}"
|
||||
Margin="5,0" />
|
||||
<Label Grid.Column="2"
|
||||
Content="{Binding Converter={StaticResource LocalizedStringConverter}, ConverterParameter=LoginScreenPassword}"
|
||||
VerticalAlignment="Center" Margin="5,0" />
|
||||
<TextBox Grid.Column="3" Name="PasswordBox"
|
||||
Watermark="{Binding Converter={StaticResource LocalizedStringConverter}, ConverterParameter=LoginScreenPassword}"
|
||||
PasswordChar="*" Margin="5,0" />
|
||||
<Button Grid.Column="4"
|
||||
Content="{Binding Converter={StaticResource LocalizedStringConverter}, ConverterParameter=LoginScreenLoginButton}"
|
||||
Margin="5,0" VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
<!-- TODO: Add in the Grid selector -->
|
||||
<!-- TODO: Add in the Location selector -->
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,6 +1,10 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
using GalaxyViewer.Assets.Localization;
|
||||
using GalaxyViewer.ViewModels;
|
||||
using MsBox.Avalonia;
|
||||
using MsBox.Avalonia.Windows;
|
||||
|
||||
namespace GalaxyViewer.Views
|
||||
{
|
||||
@@ -16,9 +20,35 @@ namespace GalaxyViewer.Views
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void LoginButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||||
private async void LoginButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Your event handling code here, which attempts the Login method
|
||||
// We run TryLoginAsync() and await it to ensure that the login process is completed before proceeding
|
||||
// TODO: Implement TryLoginAsync()
|
||||
|
||||
/*
|
||||
* The following code is a placeholder for the TryLoginAsync() method.
|
||||
* This method should be implemented in the LoginViewModel class.
|
||||
* The method should handle the login process and return a boolean value indicating whether the login was successful.
|
||||
* The method should also handle any errors that may occur during the login process.
|
||||
*/
|
||||
/*
|
||||
if (loginSuccess)
|
||||
{
|
||||
// If login is successful, we navigate to the MainView
|
||||
var mainView = new MainView
|
||||
{
|
||||
DataContext = new MainViewModel()
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// If login is unsuccessful, we show an error message
|
||||
MsBoxWindow.Show(
|
||||
// Localize the error message
|
||||
// TODO: Add error message
|
||||
);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,53 +6,53 @@
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="GalaxyViewer.Views.MainView"
|
||||
x:DataType="vm:MainViewModel">
|
||||
<Design.DataContext>
|
||||
<Design.DataContext>
|
||||
<vm:MainViewModel />
|
||||
</Design.DataContext>
|
||||
</Design.DataContext>
|
||||
|
||||
<DockPanel LastChildFill="True">
|
||||
<DockPanel LastChildFill="True">
|
||||
<Menu DockPanel.Dock="Top">
|
||||
<MenuItem Header="File">
|
||||
<MenuItem Header="New Window"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Upload Blinn-Phong Texture" IsEnabled="{Binding IsLoggedIn}"/>
|
||||
<MenuItem Header="Upload PBR Material" IsEnabled="{Binding IsLoggedIn}"/>
|
||||
<MenuItem Header="Upload Mesh" IsEnabled="{Binding IsLoggedIn}"/>
|
||||
<MenuItem Header="Import Object" IsEnabled="{Binding IsLoggedIn}"/>
|
||||
<MenuItem Header="Script Editor" IsEnabled="{Binding IsLoggedIn}"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Login" Command="{Binding LoginCommand}" IsEnabled="{Binding !IsLoggedIn}"/>
|
||||
<MenuItem Header="Logout" Command="{Binding LogoutCommand}" IsEnabled="{Binding IsLoggedIn}"/>
|
||||
<MenuItem Header="Relog" IsEnabled="{Binding !IsLoggedIn}"/>
|
||||
<MenuItem Header="Preferences" Command="{Binding ShowPreferencesCommand}"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Exit" Command="{Binding ExitCommand}"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="File">
|
||||
<MenuItem Header="New Window" />
|
||||
<Separator />
|
||||
<MenuItem Header="Upload Blinn-Phong Texture" IsEnabled="{Binding IsLoggedIn}" />
|
||||
<MenuItem Header="Upload PBR Material" IsEnabled="{Binding IsLoggedIn}" />
|
||||
<MenuItem Header="Upload Mesh" IsEnabled="{Binding IsLoggedIn}" />
|
||||
<MenuItem Header="Import Object" IsEnabled="{Binding IsLoggedIn}" />
|
||||
<MenuItem Header="Script Editor" IsEnabled="{Binding IsLoggedIn}" />
|
||||
<Separator />
|
||||
<MenuItem Header="Login" Command="{Binding LoginCommand}" IsEnabled="{Binding !IsLoggedIn}" />
|
||||
<MenuItem Header="Logout" Command="{Binding LogoutCommand}" IsEnabled="{Binding IsLoggedIn}" />
|
||||
<MenuItem Header="Relog" IsEnabled="{Binding !IsLoggedIn}" />
|
||||
<MenuItem Header="Preferences" Command="{Binding ShowPreferencesCommand}" />
|
||||
<Separator />
|
||||
<MenuItem Header="Exit" Command="{Binding ExitCommand}" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="World" IsEnabled="{Binding IsLoggedIn}">
|
||||
<MenuItem Header="Create new Landmark Here"/>
|
||||
<MenuItem Header="Landmarks"/>
|
||||
<MenuItem Header="Teleport History"/>
|
||||
<MenuItem Header="Favorites"/>
|
||||
<MenuItem Header="Set Home to Here"/>
|
||||
<MenuItem Header="Teleport Home"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="About Land"/>
|
||||
<MenuItem Header="About Region"/>
|
||||
<MenuItem Header="World Map"/>
|
||||
<MenuItem Header="Mini-Map"/>
|
||||
<MenuItem Header="People Nearby"/>
|
||||
<MenuItem Header="Objects Nearby"/>
|
||||
<MenuItem Header="Create new Landmark Here" />
|
||||
<MenuItem Header="Landmarks" />
|
||||
<MenuItem Header="Teleport History" />
|
||||
<MenuItem Header="Favorites" />
|
||||
<MenuItem Header="Set Home to Here" />
|
||||
<MenuItem Header="Teleport Home" />
|
||||
<Separator />
|
||||
<MenuItem Header="About Land" />
|
||||
<MenuItem Header="About Region" />
|
||||
<MenuItem Header="World Map" />
|
||||
<MenuItem Header="Mini-Map" />
|
||||
<MenuItem Header="People Nearby" />
|
||||
<MenuItem Header="Objects Nearby" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="Community" IsEnabled="{Binding IsLoggedIn}">
|
||||
<MenuItem Header="Friends"/>
|
||||
<MenuItem Header="Groups"/>
|
||||
<MenuItem Header="Events"/>
|
||||
<MenuItem Header="Marketplace"/>
|
||||
<MenuItem Header="Search"/>
|
||||
<MenuItem Header="Friends" />
|
||||
<MenuItem Header="Groups" />
|
||||
<MenuItem Header="Events" />
|
||||
<MenuItem Header="Marketplace" />
|
||||
<MenuItem Header="Search" />
|
||||
</MenuItem>
|
||||
<!-- Add more menu items as needed -->
|
||||
</Menu>
|
||||
|
||||
<ContentControl Content="{Binding CurrentView}"/>
|
||||
</DockPanel>
|
||||
</UserControl>
|
||||
<ContentControl Content="{Binding CurrentView}" />
|
||||
</DockPanel>
|
||||
</UserControl>
|
||||
@@ -1,4 +1,5 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace GalaxyViewer.Views;
|
||||
|
||||
@@ -8,4 +9,9 @@ public partial class MainView : UserControl
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="using:GalaxyViewer.ViewModels"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:views="clr-namespace:GalaxyViewer.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="GalaxyViewer.Views.MainWindow"
|
||||
Icon="/Assets/avalonia-logo.ico"
|
||||
Title="GalaxyViewer">
|
||||
<views:MainView />
|
||||
</Window>
|
||||
<views:BaseWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:views="clr-namespace:GalaxyViewer.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="GalaxyViewer.Views.MainWindow"
|
||||
Title="GalaxyViewer">
|
||||
<views:MainView />
|
||||
</views:BaseWindow>
|
||||
@@ -1,11 +1,25 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace GalaxyViewer.Views;
|
||||
|
||||
public partial class MainWindow : Window
|
||||
public partial class MainWindow : BaseWindow
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
AttachDevToolsConditional();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void AttachDevToolsConditional()
|
||||
{
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,31 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:converters="clr-namespace:GalaxyViewer.Converters"
|
||||
xmlns:vm="clr-namespace:GalaxyViewer.ViewModels"
|
||||
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"
|
||||
x:Class="GalaxyViewer.Views.PreferencesView"
|
||||
x:DataType="vm:PreferencesViewModel">
|
||||
<UserControl.Resources>
|
||||
<converters:LocalizedStringConverter x:Key="LocalizedStringConverter" />
|
||||
</UserControl.Resources>
|
||||
<StackPanel Margin="20">
|
||||
<TextBlock Text="Preferences" />
|
||||
<ComboBox ItemsSource="{Binding ThemeOptions}" SelectedItem="{Binding Theme}" />
|
||||
<ComboBox ItemsSource="{Binding LoginLocationOptions}" SelectedItem="{Binding LoginLocation}" />
|
||||
<!-- Add more UI elements as needed -->
|
||||
<Button Content="Save Preferences" Command="{Binding SaveCommand}" HorizontalAlignment="Left" />
|
||||
<Label Content="{Binding Converter={StaticResource LocalizedStringConverter}, ConverterParameter=PreferencesTitle}"
|
||||
VerticalAlignment="Center" />
|
||||
<Label Content="{Binding Converter={StaticResource LocalizedStringConverter}, ConverterParameter=PreferencesTheme}"
|
||||
VerticalAlignment="Center" />
|
||||
<ComboBox ItemsSource="{Binding ThemeOptions}" SelectedItem="{Binding SelectedTheme}" />
|
||||
<Label Content="{Binding Converter={StaticResource LocalizedStringConverter}, ConverterParameter=PreferencesLoginLocation}"
|
||||
VerticalAlignment="Center" />
|
||||
<ComboBox ItemsSource="{Binding LoginLocationOptions}" SelectedItem="{Binding SelectedLoginLocation}" />
|
||||
<Label Content="{Binding Converter={StaticResource LocalizedStringConverter}, ConverterParameter=PreferencesLanguage}"
|
||||
VerticalAlignment="Center" />
|
||||
<ComboBox ItemsSource="{Binding LanguageOptions}" SelectedItem="{Binding SelectedLanguage}" />
|
||||
<Label Content="{Binding Converter={StaticResource LocalizedStringConverter}, ConverterParameter=PreferencesFont}"
|
||||
VerticalAlignment="Center" />
|
||||
<ComboBox ItemsSource="{Binding FontOptions}" SelectedItem="{Binding SelectedFont}" />
|
||||
<Button Content="{Binding Converter={StaticResource LocalizedStringConverter}, ConverterParameter=PreferencesSaveButton}"
|
||||
Command="{Binding SaveCommand}" HorizontalAlignment="Left" />
|
||||
<TextBlock Text="{Binding StatusMessage}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -1,4 +1,4 @@
|
||||
using Avalonia;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using GalaxyViewer.ViewModels;
|
||||
@@ -10,12 +10,22 @@ namespace GalaxyViewer.Views
|
||||
public PreferencesView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.DataContext = new PreferencesViewModel();
|
||||
LoadViewModelAsync();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
private async void LoadViewModelAsync()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
var viewModel = new PreferencesViewModel();
|
||||
await viewModel.InitializeAsync();
|
||||
DataContext = viewModel;
|
||||
}
|
||||
|
||||
private static async Task<PreferencesViewModel> CreateAsync()
|
||||
{
|
||||
var viewModel = new PreferencesViewModel();
|
||||
await viewModel
|
||||
.LoadPreferencesAsync();
|
||||
return viewModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<views:BaseWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:views="clr-namespace:GalaxyViewer.Views"
|
||||
x:Class="GalaxyViewer.Views.PreferencesWindow"
|
||||
Title="Preferences"
|
||||
Width="450" Height="350">
|
||||
<views:PreferencesView/>
|
||||
</views:BaseWindow>
|
||||
@@ -0,0 +1,20 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using GalaxyViewer.ViewModels;
|
||||
|
||||
namespace GalaxyViewer.Views
|
||||
{
|
||||
public partial class PreferencesWindow : Window
|
||||
{
|
||||
public PreferencesWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = new PreferencesViewModel();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user