添加项目文件。
202
.editorconfig
Normal file
|
@ -0,0 +1,202 @@
|
|||
# Rules in this file were initially inferred by Visual Studio IntelliCode from the Template Studio codebase.
|
||||
# You can modify the rules from these initially generated values to suit your own policies.
|
||||
# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference.
|
||||
|
||||
[*.cs]
|
||||
|
||||
#Core editorconfig formatting - indentation
|
||||
|
||||
#use soft tabs (spaces) for indentation
|
||||
indent_style = space
|
||||
|
||||
#Formatting - new line options
|
||||
|
||||
#place else statements on a new line
|
||||
csharp_new_line_before_else = true
|
||||
#require braces to be on a new line for lambdas, methods, control_blocks, types, properties, and accessors (also known as "Allman" style)
|
||||
csharp_new_line_before_open_brace = all
|
||||
|
||||
#Formatting - organize using options
|
||||
|
||||
#sort System.* using directives alphabetically, and place them before other usings
|
||||
dotnet_sort_system_directives_first = true
|
||||
|
||||
#Formatting - spacing options
|
||||
|
||||
#require NO space between a cast and the value
|
||||
csharp_space_after_cast = false
|
||||
#require a space before the colon for bases or interfaces in a type declaration
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
#require a space after a keyword in a control flow statement such as a for loop
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
#require a space before the colon for bases or interfaces in a type declaration
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
#remove space within empty argument list parentheses
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
#remove space between method call name and opening parenthesis
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
#do not place space characters after the opening parenthesis and before the closing parenthesis of a method call
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
#remove space within empty parameter list parentheses for a method declaration
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
#place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
|
||||
#Formatting - wrapping options
|
||||
|
||||
#leave code block on separate lines
|
||||
csharp_preserve_single_line_blocks = false
|
||||
|
||||
#Style - Code block preferences
|
||||
|
||||
#prefer curly braces even for one line of code
|
||||
csharp_prefer_braces = true:suggestion
|
||||
|
||||
#Style - expression bodied member options
|
||||
|
||||
#prefer expression bodies for accessors
|
||||
csharp_style_expression_bodied_accessors = true:warning
|
||||
#prefer block bodies for constructors
|
||||
csharp_style_expression_bodied_constructors = false:suggestion
|
||||
#prefer expression bodies for methods
|
||||
csharp_style_expression_bodied_methods = when_on_single_line:silent
|
||||
#prefer expression-bodied members for properties
|
||||
csharp_style_expression_bodied_properties = true:warning
|
||||
|
||||
#Style - expression level options
|
||||
|
||||
#prefer out variables to be declared before the method call
|
||||
csharp_style_inlined_variable_declaration = false:suggestion
|
||||
#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
|
||||
#Style - Expression-level preferences
|
||||
|
||||
#prefer default over default(T)
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
#prefer objects to be initialized using object initializers when possible
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
|
||||
#Style - implicit and explicit types
|
||||
|
||||
#prefer var over explicit type in all cases, unless overridden by another code style rule
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
#prefer var is used to declare variables with built-in system types such as int
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
#prefer var when the type is already mentioned on the right-hand side of a declaration expression
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
|
||||
#Style - language keyword and framework type options
|
||||
|
||||
#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||
|
||||
#Style - Language rules
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = true:warning
|
||||
csharp_style_var_for_built_in_types = true:warning
|
||||
|
||||
#Style - modifier options
|
||||
|
||||
#prefer accessibility modifiers to be declared except for public interface members. This will currently not differ from always and will act as future proofing for if C# adds default interface methods.
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
|
||||
|
||||
#Style - Modifier preferences
|
||||
|
||||
#when this rule is set to a list of modifiers, prefer the specified ordering.
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,async,readonly,override,sealed,abstract,virtual:warning
|
||||
dotnet_style_readonly_field = true:warning
|
||||
|
||||
#Style - Pattern matching
|
||||
|
||||
#prefer pattern matching instead of is expression with type casts
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:warning
|
||||
|
||||
#Style - qualification options
|
||||
|
||||
#prefer events not to be prefaced with this. or Me. in Visual Basic
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
#prefer fields not to be prefaced with this. or Me. in Visual Basic
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
#prefer methods not to be prefaced with this. or Me. in Visual Basic
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
#prefer properties not to be prefaced with this. or Me. in Visual Basic
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_using_directive_placement = outside_namespace:silent
|
||||
csharp_prefer_simple_using_statement = true:warning
|
||||
csharp_style_namespace_declarations = file_scoped:warning
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
|
||||
[*.{cs,vb}]
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
tab_width = 4
|
||||
indent_size = 4
|
||||
end_of_line = crlf
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:silent
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
[*.{cs,vb}]
|
||||
|
||||
#Style - Unnecessary code rules
|
||||
csharp_style_unused_value_assignment_preference = discard_variable:warning
|
||||
|
||||
#### Naming styles ####
|
||||
|
||||
# Naming rules
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# Symbol specifications
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_compound_assignment = true:warning
|
||||
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
16
.vsconfig
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"version": "1.0",
|
||||
"components": [
|
||||
"Microsoft.Component.MSBuild",
|
||||
"Microsoft.NetCore.Component.Runtime.7.0",
|
||||
"Microsoft.NetCore.Component.SDK",
|
||||
"Microsoft.VisualStudio.Component.ManagedDesktop.Core",
|
||||
"Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites",
|
||||
"Microsoft.VisualStudio.Component.NuGet",
|
||||
"Microsoft.VisualStudio.Component.Windows10SDK.19041",
|
||||
"Microsoft.VisualStudio.Component.Windows10SDK",
|
||||
"Microsoft.VisualStudio.ComponentGroup.MSIX.Packaging",
|
||||
"Microsoft.VisualStudio.ComponentGroup.WindowsAppSDK.Cs",
|
||||
"Microsoft.VisualStudio.Workload.ManagedDesktop"
|
||||
]
|
||||
}
|
10
RustTools.Core/Contracts/Services/IFileService.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace RustTools.Core.Contracts.Services;
|
||||
|
||||
public interface IFileService
|
||||
{
|
||||
T Read<T>(string folderPath, string fileName);
|
||||
|
||||
void Save<T>(string folderPath, string fileName, T content);
|
||||
|
||||
void Delete(string folderPath, string fileName);
|
||||
}
|
22
RustTools.Core/Helpers/Json.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace RustTools.Core.Helpers;
|
||||
|
||||
public static class Json
|
||||
{
|
||||
public static async Task<T> ToObjectAsync<T>(string value)
|
||||
{
|
||||
return await Task.Run<T>(() =>
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(value);
|
||||
});
|
||||
}
|
||||
|
||||
public static async Task<string> StringifyAsync(object value)
|
||||
{
|
||||
return await Task.Run<string>(() =>
|
||||
{
|
||||
return JsonConvert.SerializeObject(value);
|
||||
});
|
||||
}
|
||||
}
|
5
RustTools.Core/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
*Recommended Markdown Viewer: [Markdown Editor](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.MarkdownEditor2)*
|
||||
|
||||
## Getting Started
|
||||
|
||||
The Core project contains code that can be [reused across multiple application projects](https://docs.microsoft.com/dotnet/standard/net-standard#net-5-and-net-standard).
|
17
RustTools.Core/RustTools.Core.csproj
Normal file
|
@ -0,0 +1,17 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<RootNamespace>RustTools.Core</RootNamespace>
|
||||
<Platforms>AnyCPU;x64;x86</Platforms>
|
||||
<Platforms>x86;x64;arm64;AnyCPU</Platforms>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Models\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
41
RustTools.Core/Services/FileService.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using System.Text;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using RustTools.Core.Contracts.Services;
|
||||
|
||||
namespace RustTools.Core.Services;
|
||||
|
||||
public class FileService : IFileService
|
||||
{
|
||||
public T Read<T>(string folderPath, string fileName)
|
||||
{
|
||||
var path = Path.Combine(folderPath, fileName);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
var json = File.ReadAllText(path);
|
||||
return JsonConvert.DeserializeObject<T>(json);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public void Save<T>(string folderPath, string fileName, T content)
|
||||
{
|
||||
if (!Directory.Exists(folderPath))
|
||||
{
|
||||
Directory.CreateDirectory(folderPath);
|
||||
}
|
||||
|
||||
var fileContent = JsonConvert.SerializeObject(content);
|
||||
File.WriteAllText(Path.Combine(folderPath, fileName), fileContent, Encoding.UTF8);
|
||||
}
|
||||
|
||||
public void Delete(string folderPath, string fileName)
|
||||
{
|
||||
if (fileName != null && File.Exists(Path.Combine(folderPath, fileName)))
|
||||
{
|
||||
File.Delete(Path.Combine(folderPath, fileName));
|
||||
}
|
||||
}
|
||||
}
|
69
RustTools.sln
Normal file
|
@ -0,0 +1,69 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.10.34928.147
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RustTools", "RustTools\RustTools.csproj", "{2B938A8C-2116-4961-A9D7-5A755FFC1943}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RustTools.Core", "RustTools.Core\RustTools.Core.csproj", "{39825A39-612C-4260-8079-FA021D04783F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|arm64 = Debug|arm64
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|arm64 = Release|arm64
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Debug|Any CPU.Deploy.0 = Debug|x64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Debug|arm64.ActiveCfg = Debug|arm64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Debug|arm64.Build.0 = Debug|arm64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Debug|arm64.Deploy.0 = Debug|arm64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Debug|x64.Build.0 = Debug|x64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Debug|x86.Build.0 = Debug|x86
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Release|Any CPU.Build.0 = Release|x64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Release|Any CPU.Deploy.0 = Release|x64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Release|arm64.ActiveCfg = Release|arm64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Release|arm64.Build.0 = Release|arm64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Release|arm64.Deploy.0 = Release|arm64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Release|x64.ActiveCfg = Release|x64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Release|x64.Build.0 = Release|x64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Release|x64.Deploy.0 = Release|x64
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Release|x86.ActiveCfg = Release|x86
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Release|x86.Build.0 = Release|x86
|
||||
{2B938A8C-2116-4961-A9D7-5A755FFC1943}.Release|x86.Deploy.0 = Release|x86
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Debug|arm64.ActiveCfg = Debug|arm64
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Debug|arm64.Build.0 = Debug|arm64
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Debug|x64.Build.0 = Debug|x64
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Debug|x86.Build.0 = Debug|x86
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Release|arm64.ActiveCfg = Release|arm64
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Release|arm64.Build.0 = Release|arm64
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Release|x64.ActiveCfg = Release|x64
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Release|x64.Build.0 = Release|x64
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Release|x86.ActiveCfg = Release|x86
|
||||
{39825A39-612C-4260-8079-FA021D04783F}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {93A2DBB8-6839-4361-890B-429688744B6C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
17
RustTools/Activation/ActivationHandler.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
namespace RustTools.Activation;
|
||||
|
||||
// Extend this class to implement new ActivationHandlers. See DefaultActivationHandler for an example.
|
||||
// https://github.com/microsoft/TemplateStudio/blob/main/docs/WinUI/activation.md
|
||||
public abstract class ActivationHandler<T> : IActivationHandler
|
||||
where T : class
|
||||
{
|
||||
// Override this method to add the logic for whether to handle the activation.
|
||||
protected virtual bool CanHandleInternal(T args) => true;
|
||||
|
||||
// Override this method to add the logic for your activation handler.
|
||||
protected abstract Task HandleInternalAsync(T args);
|
||||
|
||||
public bool CanHandle(object args) => args is T && CanHandleInternal((args as T)!);
|
||||
|
||||
public async Task HandleAsync(object args) => await HandleInternalAsync((args as T)!);
|
||||
}
|
29
RustTools/Activation/DefaultActivationHandler.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using Microsoft.UI.Xaml;
|
||||
|
||||
using RustTools.Contracts.Services;
|
||||
using RustTools.ViewModels;
|
||||
|
||||
namespace RustTools.Activation;
|
||||
|
||||
public class DefaultActivationHandler : ActivationHandler<LaunchActivatedEventArgs>
|
||||
{
|
||||
private readonly INavigationService _navigationService;
|
||||
|
||||
public DefaultActivationHandler(INavigationService navigationService)
|
||||
{
|
||||
_navigationService = navigationService;
|
||||
}
|
||||
|
||||
protected override bool CanHandleInternal(LaunchActivatedEventArgs args)
|
||||
{
|
||||
// None of the ActivationHandlers has handled the activation.
|
||||
return _navigationService.Frame?.Content == null;
|
||||
}
|
||||
|
||||
protected async override Task HandleInternalAsync(LaunchActivatedEventArgs args)
|
||||
{
|
||||
_navigationService.NavigateTo(typeof(MainViewModel).FullName!, args.Arguments);
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
8
RustTools/Activation/IActivationHandler.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace RustTools.Activation;
|
||||
|
||||
public interface IActivationHandler
|
||||
{
|
||||
bool CanHandle(object args);
|
||||
|
||||
Task HandleAsync(object args);
|
||||
}
|
15
RustTools/App.xaml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<Application
|
||||
x:Class="RustTools.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<ResourceDictionary Source="/Styles/FontSizes.xaml" />
|
||||
<ResourceDictionary Source="/Styles/Thickness.xaml" />
|
||||
<ResourceDictionary Source="/Styles/TextBlock.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
103
RustTools/App.xaml.cs
Normal file
|
@ -0,0 +1,103 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
using RustTools.Activation;
|
||||
using RustTools.Contracts.Services;
|
||||
using RustTools.Core.Contracts.Services;
|
||||
using RustTools.Core.Services;
|
||||
using RustTools.Helpers;
|
||||
using RustTools.Models;
|
||||
using RustTools.Services;
|
||||
using RustTools.ViewModels;
|
||||
using RustTools.Views;
|
||||
|
||||
namespace RustTools;
|
||||
|
||||
// To learn more about WinUI 3, see https://docs.microsoft.com/windows/apps/winui/winui3/.
|
||||
public partial class App : Application
|
||||
{
|
||||
// The .NET Generic Host provides dependency injection, configuration, logging, and other services.
|
||||
// https://docs.microsoft.com/dotnet/core/extensions/generic-host
|
||||
// https://docs.microsoft.com/dotnet/core/extensions/dependency-injection
|
||||
// https://docs.microsoft.com/dotnet/core/extensions/configuration
|
||||
// https://docs.microsoft.com/dotnet/core/extensions/logging
|
||||
public IHost Host
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public static T GetService<T>()
|
||||
where T : class
|
||||
{
|
||||
if ((App.Current as App)!.Host.Services.GetService(typeof(T)) is not T service)
|
||||
{
|
||||
throw new ArgumentException($"{typeof(T)} needs to be registered in ConfigureServices within App.xaml.cs.");
|
||||
}
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
public static WindowEx MainWindow { get; } = new MainWindow();
|
||||
|
||||
public static UIElement? AppTitlebar { get; set; }
|
||||
|
||||
public App()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Host = Microsoft.Extensions.Hosting.Host.
|
||||
CreateDefaultBuilder().
|
||||
UseContentRoot(AppContext.BaseDirectory).
|
||||
ConfigureServices((context, services) =>
|
||||
{
|
||||
// Default Activation Handler
|
||||
services.AddTransient<ActivationHandler<LaunchActivatedEventArgs>, DefaultActivationHandler>();
|
||||
|
||||
// Other Activation Handlers
|
||||
|
||||
// Services
|
||||
services.AddSingleton<ILocalSettingsService, LocalSettingsService>();
|
||||
services.AddSingleton<IThemeSelectorService, ThemeSelectorService>();
|
||||
services.AddTransient<INavigationViewService, NavigationViewService>();
|
||||
|
||||
services.AddSingleton<IActivationService, ActivationService>();
|
||||
services.AddSingleton<IPageService, PageService>();
|
||||
services.AddSingleton<INavigationService, NavigationService>();
|
||||
|
||||
// Core Services
|
||||
services.AddSingleton<IFileService, FileService>();
|
||||
|
||||
// Views and ViewModels
|
||||
services.AddTransient<SettingsViewModel>();
|
||||
services.AddTransient<SettingsPage>();
|
||||
services.AddTransient<MainViewModel>();
|
||||
services.AddTransient<MainPage>();
|
||||
|
||||
services.AddTransient<HomePageViewModel>();
|
||||
services.AddTransient<HomePage>();
|
||||
|
||||
services.AddTransient<ShellPage>();
|
||||
services.AddTransient<ShellViewModel>();
|
||||
|
||||
// Configuration
|
||||
services.Configure<LocalSettingsOptions>(context.Configuration.GetSection(nameof(LocalSettingsOptions)));
|
||||
}).
|
||||
Build();
|
||||
|
||||
UnhandledException += App_UnhandledException;
|
||||
}
|
||||
|
||||
private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
|
||||
{
|
||||
// TODO: Log and handle exceptions as appropriate.
|
||||
// https://docs.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.application.unhandledexception.
|
||||
}
|
||||
|
||||
protected async override void OnLaunched(LaunchActivatedEventArgs args)
|
||||
{
|
||||
base.OnLaunched(args);
|
||||
|
||||
await App.GetService<IActivationService>().ActivateAsync(args);
|
||||
}
|
||||
}
|
BIN
RustTools/Assets/LockScreenLogo.scale-200.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
RustTools/Assets/SplashScreen.scale-200.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
RustTools/Assets/Square150x150Logo.scale-200.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
RustTools/Assets/Square44x44Logo.scale-200.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.2 KiB |
BIN
RustTools/Assets/StoreLogo.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
RustTools/Assets/Wide310x150Logo.scale-200.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
RustTools/Assets/WindowIcon.ico
Normal file
After Width: | Height: | Size: 264 KiB |
BIN
RustTools/Assets/res/BadgeLogo.scale-100.png
Normal file
After Width: | Height: | Size: 213 B |
BIN
RustTools/Assets/res/BadgeLogo.scale-125.png
Normal file
After Width: | Height: | Size: 236 B |
BIN
RustTools/Assets/res/BadgeLogo.scale-150.png
Normal file
After Width: | Height: | Size: 295 B |
BIN
RustTools/Assets/res/BadgeLogo.scale-200.png
Normal file
After Width: | Height: | Size: 350 B |
BIN
RustTools/Assets/res/BadgeLogo.scale-400.png
Normal file
After Width: | Height: | Size: 677 B |
BIN
RustTools/Assets/res/LargeTile.scale-100.png
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
RustTools/Assets/res/LargeTile.scale-125.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
RustTools/Assets/res/LargeTile.scale-150.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
RustTools/Assets/res/LargeTile.scale-200.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
RustTools/Assets/res/LargeTile.scale-400.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
RustTools/Assets/res/SmallTile.scale-100.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
RustTools/Assets/res/SmallTile.scale-125.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
RustTools/Assets/res/SmallTile.scale-150.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
RustTools/Assets/res/SmallTile.scale-200.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
RustTools/Assets/res/SmallTile.scale-400.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
RustTools/Assets/res/SplashScreen.scale-100.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
RustTools/Assets/res/SplashScreen.scale-125.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
RustTools/Assets/res/SplashScreen.scale-150.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
RustTools/Assets/res/SplashScreen.scale-200.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
RustTools/Assets/res/SplashScreen.scale-400.png
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
RustTools/Assets/res/Square150x150Logo.scale-100.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
RustTools/Assets/res/Square150x150Logo.scale-125.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
RustTools/Assets/res/Square150x150Logo.scale-150.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
RustTools/Assets/res/Square150x150Logo.scale-200.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
RustTools/Assets/res/Square150x150Logo.scale-400.png
Normal file
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 775 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 775 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.2 KiB |
BIN
RustTools/Assets/res/Square44x44Logo.scale-100.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
RustTools/Assets/res/Square44x44Logo.scale-125.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
RustTools/Assets/res/Square44x44Logo.scale-150.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
RustTools/Assets/res/Square44x44Logo.scale-200.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
RustTools/Assets/res/Square44x44Logo.scale-400.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
RustTools/Assets/res/Square44x44Logo.targetsize-16.png
Normal file
After Width: | Height: | Size: 575 B |
BIN
RustTools/Assets/res/Square44x44Logo.targetsize-24.png
Normal file
After Width: | Height: | Size: 906 B |
BIN
RustTools/Assets/res/Square44x44Logo.targetsize-256.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
RustTools/Assets/res/Square44x44Logo.targetsize-32.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
RustTools/Assets/res/Square44x44Logo.targetsize-48.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
RustTools/Assets/res/StoreLogo.scale-100.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
RustTools/Assets/res/StoreLogo.scale-125.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
RustTools/Assets/res/StoreLogo.scale-150.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
RustTools/Assets/res/StoreLogo.scale-200.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
RustTools/Assets/res/StoreLogo.scale-400.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
RustTools/Assets/res/Wide310x150Logo.scale-100.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
RustTools/Assets/res/Wide310x150Logo.scale-125.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
RustTools/Assets/res/Wide310x150Logo.scale-150.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
RustTools/Assets/res/Wide310x150Logo.scale-200.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
RustTools/Assets/res/Wide310x150Logo.scale-400.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
RustTools/Assets/tool.png
Normal file
After Width: | Height: | Size: 10 KiB |
122
RustTools/Behaviors/NavigationViewHeaderBehavior.cs
Normal file
|
@ -0,0 +1,122 @@
|
|||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Microsoft.Xaml.Interactivity;
|
||||
|
||||
using RustTools.Contracts.Services;
|
||||
|
||||
namespace RustTools.Behaviors;
|
||||
|
||||
public class NavigationViewHeaderBehavior : Behavior<NavigationView>
|
||||
{
|
||||
private static NavigationViewHeaderBehavior? _current;
|
||||
|
||||
private Page? _currentPage;
|
||||
|
||||
public DataTemplate? DefaultHeaderTemplate
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public object DefaultHeader
|
||||
{
|
||||
get => GetValue(DefaultHeaderProperty);
|
||||
set => SetValue(DefaultHeaderProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DefaultHeaderProperty =
|
||||
DependencyProperty.Register("DefaultHeader", typeof(object), typeof(NavigationViewHeaderBehavior), new PropertyMetadata(null, (d, e) => _current!.UpdateHeader()));
|
||||
|
||||
public static NavigationViewHeaderMode GetHeaderMode(Page item) => (NavigationViewHeaderMode)item.GetValue(HeaderModeProperty);
|
||||
|
||||
public static void SetHeaderMode(Page item, NavigationViewHeaderMode value) => item.SetValue(HeaderModeProperty, value);
|
||||
|
||||
public static readonly DependencyProperty HeaderModeProperty =
|
||||
DependencyProperty.RegisterAttached("HeaderMode", typeof(bool), typeof(NavigationViewHeaderBehavior), new PropertyMetadata(NavigationViewHeaderMode.Always, (d, e) => _current!.UpdateHeader()));
|
||||
|
||||
public static object GetHeaderContext(Page item) => item.GetValue(HeaderContextProperty);
|
||||
|
||||
public static void SetHeaderContext(Page item, object value) => item.SetValue(HeaderContextProperty, value);
|
||||
|
||||
public static readonly DependencyProperty HeaderContextProperty =
|
||||
DependencyProperty.RegisterAttached("HeaderContext", typeof(object), typeof(NavigationViewHeaderBehavior), new PropertyMetadata(null, (d, e) => _current!.UpdateHeader()));
|
||||
|
||||
public static DataTemplate GetHeaderTemplate(Page item) => (DataTemplate)item.GetValue(HeaderTemplateProperty);
|
||||
|
||||
public static void SetHeaderTemplate(Page item, DataTemplate value) => item.SetValue(HeaderTemplateProperty, value);
|
||||
|
||||
public static readonly DependencyProperty HeaderTemplateProperty =
|
||||
DependencyProperty.RegisterAttached("HeaderTemplate", typeof(DataTemplate), typeof(NavigationViewHeaderBehavior), new PropertyMetadata(null, (d, e) => _current!.UpdateHeaderTemplate()));
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
var navigationService = App.GetService<INavigationService>();
|
||||
navigationService.Navigated += OnNavigated;
|
||||
|
||||
_current = this;
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
|
||||
var navigationService = App.GetService<INavigationService>();
|
||||
navigationService.Navigated -= OnNavigated;
|
||||
}
|
||||
|
||||
private void OnNavigated(object sender, NavigationEventArgs e)
|
||||
{
|
||||
if (sender is Frame frame && frame.Content is Page page)
|
||||
{
|
||||
_currentPage = page;
|
||||
|
||||
UpdateHeader();
|
||||
UpdateHeaderTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateHeader()
|
||||
{
|
||||
if (_currentPage != null)
|
||||
{
|
||||
var headerMode = GetHeaderMode(_currentPage);
|
||||
if (headerMode == NavigationViewHeaderMode.Never)
|
||||
{
|
||||
AssociatedObject.Header = null;
|
||||
AssociatedObject.AlwaysShowHeader = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var headerFromPage = GetHeaderContext(_currentPage);
|
||||
if (headerFromPage != null)
|
||||
{
|
||||
AssociatedObject.Header = headerFromPage;
|
||||
}
|
||||
else
|
||||
{
|
||||
AssociatedObject.Header = DefaultHeader;
|
||||
}
|
||||
|
||||
if (headerMode == NavigationViewHeaderMode.Always)
|
||||
{
|
||||
AssociatedObject.AlwaysShowHeader = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AssociatedObject.AlwaysShowHeader = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateHeaderTemplate()
|
||||
{
|
||||
if (_currentPage != null)
|
||||
{
|
||||
var headerTemplate = GetHeaderTemplate(_currentPage);
|
||||
AssociatedObject.HeaderTemplate = headerTemplate ?? DefaultHeaderTemplate;
|
||||
}
|
||||
}
|
||||
}
|
8
RustTools/Behaviors/NavigationViewHeaderMode.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace RustTools.Behaviors;
|
||||
|
||||
public enum NavigationViewHeaderMode
|
||||
{
|
||||
Always,
|
||||
Never,
|
||||
Minimal
|
||||
}
|
6
RustTools/Contracts/Services/IActivationService.cs
Normal file
|
@ -0,0 +1,6 @@
|
|||
namespace RustTools.Contracts.Services;
|
||||
|
||||
public interface IActivationService
|
||||
{
|
||||
Task ActivateAsync(object activationArgs);
|
||||
}
|
8
RustTools/Contracts/Services/ILocalSettingsService.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace RustTools.Contracts.Services;
|
||||
|
||||
public interface ILocalSettingsService
|
||||
{
|
||||
Task<T?> ReadSettingAsync<T>(string key);
|
||||
|
||||
Task SaveSettingAsync<T>(string key, T value);
|
||||
}
|
23
RustTools/Contracts/Services/INavigationService.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace RustTools.Contracts.Services;
|
||||
|
||||
public interface INavigationService
|
||||
{
|
||||
event NavigatedEventHandler Navigated;
|
||||
|
||||
bool CanGoBack
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
Frame? Frame
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
bool NavigateTo(string pageKey, object? parameter = null, bool clearNavigation = false);
|
||||
|
||||
bool GoBack();
|
||||
}
|
22
RustTools/Contracts/Services/INavigationViewService.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace RustTools.Contracts.Services;
|
||||
|
||||
public interface INavigationViewService
|
||||
{
|
||||
IList<object>? MenuItems
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
object? SettingsItem
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
void Initialize(NavigationView navigationView);
|
||||
|
||||
void UnregisterEvents();
|
||||
|
||||
NavigationViewItem? GetSelectedItem(Type pageType);
|
||||
}
|
6
RustTools/Contracts/Services/IPageService.cs
Normal file
|
@ -0,0 +1,6 @@
|
|||
namespace RustTools.Contracts.Services;
|
||||
|
||||
public interface IPageService
|
||||
{
|
||||
Type GetPageType(string key);
|
||||
}
|
17
RustTools/Contracts/Services/IThemeSelectorService.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace RustTools.Contracts.Services;
|
||||
|
||||
public interface IThemeSelectorService
|
||||
{
|
||||
ElementTheme Theme
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
Task InitializeAsync();
|
||||
|
||||
Task SetThemeAsync(ElementTheme theme);
|
||||
|
||||
Task SetRequestedThemeAsync();
|
||||
}
|
8
RustTools/Contracts/ViewModels/INavigationAware.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace RustTools.Contracts.ViewModels;
|
||||
|
||||
public interface INavigationAware
|
||||
{
|
||||
void OnNavigatedTo(object parameter);
|
||||
|
||||
void OnNavigatedFrom();
|
||||
}
|
38
RustTools/Helpers/EnumToBooleanConverter.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
|
||||
namespace RustTools.Helpers;
|
||||
|
||||
public class EnumToBooleanConverter : IValueConverter
|
||||
{
|
||||
public EnumToBooleanConverter()
|
||||
{
|
||||
}
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (parameter is string enumString)
|
||||
{
|
||||
if (!Enum.IsDefined(typeof(ElementTheme), value))
|
||||
{
|
||||
throw new ArgumentException("ExceptionEnumToBooleanConverterValueMustBeAnEnum");
|
||||
}
|
||||
|
||||
var enumValue = Enum.Parse(typeof(ElementTheme), enumString);
|
||||
|
||||
return enumValue.Equals(value);
|
||||
}
|
||||
|
||||
throw new ArgumentException("ExceptionEnumToBooleanConverterParameterMustBeAnEnumName");
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (parameter is string enumString)
|
||||
{
|
||||
return Enum.Parse(typeof(ElementTheme), enumString);
|
||||
}
|
||||
|
||||
throw new ArgumentException("ExceptionEnumToBooleanConverterParameterMustBeAnEnumName");
|
||||
}
|
||||
}
|
8
RustTools/Helpers/FrameExtensions.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace RustTools.Helpers;
|
||||
|
||||
public static class FrameExtensions
|
||||
{
|
||||
public static object? GetPageViewModel(this Frame frame) => frame?.Content?.GetType().GetProperty("ViewModel")?.GetValue(frame.Content, null);
|
||||
}
|
21
RustTools/Helpers/NavigationHelper.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace RustTools.Helpers;
|
||||
|
||||
// Helper class to set the navigation target for a NavigationViewItem.
|
||||
//
|
||||
// Usage in XAML:
|
||||
// <NavigationViewItem x:Uid="Shell_Main" Icon="Document" helpers:NavigationHelper.NavigateTo="AppName.ViewModels.MainViewModel" />
|
||||
//
|
||||
// Usage in code:
|
||||
// NavigationHelper.SetNavigateTo(navigationViewItem, typeof(MainViewModel).FullName);
|
||||
public class NavigationHelper
|
||||
{
|
||||
public static string GetNavigateTo(NavigationViewItem item) => (string)item.GetValue(NavigateToProperty);
|
||||
|
||||
public static void SetNavigateTo(NavigationViewItem item, string value) => item.SetValue(NavigateToProperty, value);
|
||||
|
||||
public static readonly DependencyProperty NavigateToProperty =
|
||||
DependencyProperty.RegisterAttached("NavigateTo", typeof(string), typeof(NavigationHelper), new PropertyMetadata(null));
|
||||
}
|
10
RustTools/Helpers/ResourceExtensions.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using Microsoft.Windows.ApplicationModel.Resources;
|
||||
|
||||
namespace RustTools.Helpers;
|
||||
|
||||
public static class ResourceExtensions
|
||||
{
|
||||
private static readonly ResourceLoader _resourceLoader = new();
|
||||
|
||||
public static string GetLocalized(this string resourceKey) => _resourceLoader.GetString(resourceKey);
|
||||
}
|
20
RustTools/Helpers/RuntimeHelper.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace RustTools.Helpers;
|
||||
|
||||
public class RuntimeHelper
|
||||
{
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder? packageFullName);
|
||||
|
||||
public static bool IsMSIX
|
||||
{
|
||||
get
|
||||
{
|
||||
var length = 0;
|
||||
|
||||
return GetCurrentPackageFullName(ref length, null) != 15700L;
|
||||
}
|
||||
}
|
||||
}
|
112
RustTools/Helpers/SettingsStorageExtensions.cs
Normal file
|
@ -0,0 +1,112 @@
|
|||
using RustTools.Core.Helpers;
|
||||
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Streams;
|
||||
|
||||
namespace RustTools.Helpers;
|
||||
|
||||
// Use these extension methods to store and retrieve local and roaming app data
|
||||
// More details regarding storing and retrieving app data at https://docs.microsoft.com/windows/apps/design/app-settings/store-and-retrieve-app-data
|
||||
public static class SettingsStorageExtensions
|
||||
{
|
||||
private const string FileExtension = ".json";
|
||||
|
||||
public static bool IsRoamingStorageAvailable(this ApplicationData appData)
|
||||
{
|
||||
return appData.RoamingStorageQuota == 0;
|
||||
}
|
||||
|
||||
public static async Task SaveAsync<T>(this StorageFolder folder, string name, T content)
|
||||
{
|
||||
var file = await folder.CreateFileAsync(GetFileName(name), CreationCollisionOption.ReplaceExisting);
|
||||
var fileContent = await Json.StringifyAsync(content);
|
||||
|
||||
await FileIO.WriteTextAsync(file, fileContent);
|
||||
}
|
||||
|
||||
public static async Task<T?> ReadAsync<T>(this StorageFolder folder, string name)
|
||||
{
|
||||
if (!File.Exists(Path.Combine(folder.Path, GetFileName(name))))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
var file = await folder.GetFileAsync($"{name}.json");
|
||||
var fileContent = await FileIO.ReadTextAsync(file);
|
||||
|
||||
return await Json.ToObjectAsync<T>(fileContent);
|
||||
}
|
||||
|
||||
public static async Task SaveAsync<T>(this ApplicationDataContainer settings, string key, T value)
|
||||
{
|
||||
settings.SaveString(key, await Json.StringifyAsync(value));
|
||||
}
|
||||
|
||||
public static void SaveString(this ApplicationDataContainer settings, string key, string value)
|
||||
{
|
||||
settings.Values[key] = value;
|
||||
}
|
||||
|
||||
public static async Task<T?> ReadAsync<T>(this ApplicationDataContainer settings, string key)
|
||||
{
|
||||
object? obj;
|
||||
|
||||
if (settings.Values.TryGetValue(key, out obj))
|
||||
{
|
||||
return await Json.ToObjectAsync<T>((string)obj);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public static async Task<StorageFile> SaveFileAsync(this StorageFolder folder, byte[] content, string fileName, CreationCollisionOption options = CreationCollisionOption.ReplaceExisting)
|
||||
{
|
||||
if (content == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(content));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
throw new ArgumentException("File name is null or empty. Specify a valid file name", nameof(fileName));
|
||||
}
|
||||
|
||||
var storageFile = await folder.CreateFileAsync(fileName, options);
|
||||
await FileIO.WriteBytesAsync(storageFile, content);
|
||||
return storageFile;
|
||||
}
|
||||
|
||||
public static async Task<byte[]?> ReadFileAsync(this StorageFolder folder, string fileName)
|
||||
{
|
||||
var item = await folder.TryGetItemAsync(fileName).AsTask().ConfigureAwait(false);
|
||||
|
||||
if ((item != null) && item.IsOfType(StorageItemTypes.File))
|
||||
{
|
||||
var storageFile = await folder.GetFileAsync(fileName);
|
||||
var content = await storageFile.ReadBytesAsync();
|
||||
return content;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<byte[]?> ReadBytesAsync(this StorageFile file)
|
||||
{
|
||||
if (file != null)
|
||||
{
|
||||
using IRandomAccessStream stream = await file.OpenReadAsync();
|
||||
using var reader = new DataReader(stream.GetInputStreamAt(0));
|
||||
await reader.LoadAsync((uint)stream.Size);
|
||||
var bytes = new byte[stream.Size];
|
||||
reader.ReadBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string GetFileName(string name)
|
||||
{
|
||||
return string.Concat(name, FileExtension);
|
||||
}
|
||||
}
|
96
RustTools/Helpers/TitleBarHelper.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
|
||||
using Windows.UI;
|
||||
using Windows.UI.ViewManagement;
|
||||
|
||||
namespace RustTools.Helpers;
|
||||
|
||||
// Helper class to workaround custom title bar bugs.
|
||||
// DISCLAIMER: The resource key names and color values used below are subject to change. Do not depend on them.
|
||||
// https://github.com/microsoft/TemplateStudio/issues/4516
|
||||
internal class TitleBarHelper
|
||||
{
|
||||
private const int WAINACTIVE = 0x00;
|
||||
private const int WAACTIVE = 0x01;
|
||||
private const int WMACTIVATE = 0x0006;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr GetActiveWindow();
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
|
||||
|
||||
public static void UpdateTitleBar(ElementTheme theme)
|
||||
{
|
||||
if (App.MainWindow.ExtendsContentIntoTitleBar)
|
||||
{
|
||||
if (theme == ElementTheme.Default)
|
||||
{
|
||||
var uiSettings = new UISettings();
|
||||
var background = uiSettings.GetColorValue(UIColorType.Background);
|
||||
|
||||
theme = background == Colors.White ? ElementTheme.Light : ElementTheme.Dark;
|
||||
}
|
||||
|
||||
if (theme == ElementTheme.Default)
|
||||
{
|
||||
theme = Application.Current.RequestedTheme == ApplicationTheme.Light ? ElementTheme.Light : ElementTheme.Dark;
|
||||
}
|
||||
|
||||
App.MainWindow.AppWindow.TitleBar.ButtonForegroundColor = theme switch
|
||||
{
|
||||
ElementTheme.Dark => Colors.White,
|
||||
ElementTheme.Light => Colors.Black,
|
||||
_ => Colors.Transparent
|
||||
};
|
||||
|
||||
App.MainWindow.AppWindow.TitleBar.ButtonHoverForegroundColor = theme switch
|
||||
{
|
||||
ElementTheme.Dark => Colors.White,
|
||||
ElementTheme.Light => Colors.Black,
|
||||
_ => Colors.Transparent
|
||||
};
|
||||
|
||||
App.MainWindow.AppWindow.TitleBar.ButtonHoverBackgroundColor = theme switch
|
||||
{
|
||||
ElementTheme.Dark => Color.FromArgb(0x33, 0xFF, 0xFF, 0xFF),
|
||||
ElementTheme.Light => Color.FromArgb(0x33, 0x00, 0x00, 0x00),
|
||||
_ => Colors.Transparent
|
||||
};
|
||||
|
||||
App.MainWindow.AppWindow.TitleBar.ButtonPressedBackgroundColor = theme switch
|
||||
{
|
||||
ElementTheme.Dark => Color.FromArgb(0x66, 0xFF, 0xFF, 0xFF),
|
||||
ElementTheme.Light => Color.FromArgb(0x66, 0x00, 0x00, 0x00),
|
||||
_ => Colors.Transparent
|
||||
};
|
||||
|
||||
App.MainWindow.AppWindow.TitleBar.BackgroundColor = Colors.Transparent;
|
||||
|
||||
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
|
||||
if (hwnd == GetActiveWindow())
|
||||
{
|
||||
SendMessage(hwnd, WMACTIVATE, WAINACTIVE, IntPtr.Zero);
|
||||
SendMessage(hwnd, WMACTIVATE, WAACTIVE, IntPtr.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessage(hwnd, WMACTIVATE, WAACTIVE, IntPtr.Zero);
|
||||
SendMessage(hwnd, WMACTIVATE, WAINACTIVE, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ApplySystemThemeToCaptionButtons()
|
||||
{
|
||||
var frame = App.AppTitlebar as FrameworkElement;
|
||||
if (frame != null)
|
||||
{
|
||||
UpdateTitleBar(frame.ActualTheme);
|
||||
}
|
||||
}
|
||||
}
|
16
RustTools/MainWindow.xaml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<windowex:WindowEx
|
||||
x:Class="RustTools.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:RustTools"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:windowex="using:WinUIEx"
|
||||
MinWidth="500"
|
||||
MinHeight="500"
|
||||
PersistenceId="MainWindow"
|
||||
mc:Ignorable="d">
|
||||
<Window.SystemBackdrop>
|
||||
<MicaBackdrop/>
|
||||
</Window.SystemBackdrop>
|
||||
</windowex:WindowEx>
|
38
RustTools/MainWindow.xaml.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using RustTools.Helpers;
|
||||
|
||||
using Windows.UI.ViewManagement;
|
||||
|
||||
namespace RustTools;
|
||||
|
||||
public sealed partial class MainWindow : WindowEx
|
||||
{
|
||||
private Microsoft.UI.Dispatching.DispatcherQueue dispatcherQueue;
|
||||
|
||||
private UISettings settings;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
//AppWindow.SetIcon("Assets/tool.png");
|
||||
AppWindow.SetIcon(Path.Combine(AppContext.BaseDirectory, "Assets/WindowIcon.ico"));
|
||||
Content = null;
|
||||
Title = "AppDisplayName".GetLocalized();
|
||||
|
||||
// Theme change code picked from https://github.com/microsoft/WinUI-Gallery/pull/1239
|
||||
dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();
|
||||
settings = new UISettings();
|
||||
settings.ColorValuesChanged += Settings_ColorValuesChanged; // cannot use FrameworkElement.ActualThemeChanged event
|
||||
}
|
||||
|
||||
// this handles updating the caption button colors correctly when indows system theme is changed
|
||||
// while the app is open
|
||||
private void Settings_ColorValuesChanged(UISettings sender, object args)
|
||||
{
|
||||
// This calls comes off-thread, hence we will need to dispatch it to current app's thread
|
||||
dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
TitleBarHelper.ApplySystemThemeToCaptionButtons();
|
||||
});
|
||||
}
|
||||
}
|
14
RustTools/Models/LocalSettingsOptions.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
namespace RustTools.Models;
|
||||
|
||||
public class LocalSettingsOptions
|
||||
{
|
||||
public string? ApplicationDataFolder
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string? LocalSettingsFile
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
17
RustTools/Package.appinstaller
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AppInstaller Uri="{AppInstallerUri}"
|
||||
Version="{Version}"
|
||||
xmlns="http://schemas.microsoft.com/appx/appinstaller/2017/2">
|
||||
|
||||
<!-- Read more about updating settings with Package.appinstaller at https://docs.microsoft.com/windows/msix/app-installer/update-settings -->
|
||||
|
||||
<MainBundle Name="{Name}"
|
||||
Version="{Version}"
|
||||
Publisher="{Publisher}"
|
||||
Uri="{MainPackageUri}"/>
|
||||
|
||||
<UpdateSettings>
|
||||
<OnLaunch HoursBetweenUpdateChecks="0" />
|
||||
</UpdateSettings>
|
||||
|
||||
</AppInstaller>
|
77
RustTools/Package.appxmanifest
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
xmlns:genTemplate="http://schemas.microsoft.com/appx/developer/templatestudio"
|
||||
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
IgnorableNamespaces="uap rescap genTemplate">
|
||||
|
||||
<Identity
|
||||
Name="fd2b2e41-3313-4569-9ada-72a0640e6c21"
|
||||
Publisher="CN=19669"
|
||||
Version="1.0.0.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="fd2b2e41-3313-4569-9ada-72a0640e6c21" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>RustTools</DisplayName>
|
||||
<PublisherDisplayName>19669</PublisherDisplayName>
|
||||
<Logo>Assets\res\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="ms-resource:AppDisplayName"
|
||||
Description="ms-resource:AppDescription"
|
||||
BackgroundColor="transparent"
|
||||
Square150x150Logo="Assets\res\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\res\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\res\Wide310x150Logo.png" Square71x71Logo="Assets\res\SmallTile.png" Square310x310Logo="Assets\res\LargeTile.png"/>
|
||||
<uap:SplashScreen Image="Assets\res\SplashScreen.png" />
|
||||
<uap:LockScreen BadgeLogo="Assets\res\BadgeLogo.png" Notification="badgeAndTileText"/>
|
||||
</uap:VisualElements>
|
||||
<Extensions>
|
||||
<desktop:Extension Category="windows.toastNotificationActivation">
|
||||
<desktop:ToastNotificationActivation ToastActivatorCLSID="cbd67608-14d1-4cde-a790-f2aa9775ffa1" />
|
||||
</desktop:Extension>
|
||||
|
||||
<com:Extension Category="windows.comServer">
|
||||
<com:ComServer>
|
||||
<com:ExeServer Executable="RustTools.exe" Arguments="----AppNotificationActivated:" DisplayName="Toast activator">
|
||||
<com:Class Id="cbd67608-14d1-4cde-a790-f2aa9775ffa1" DisplayName="Toast activator"/>
|
||||
</com:ExeServer>
|
||||
</com:ComServer>
|
||||
</com:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
</Capabilities>
|
||||
|
||||
<genTemplate:Metadata>
|
||||
<genTemplate:Item Name="generator" Value="Template Studio"/>
|
||||
<genTemplate:Item Name="wizardVersion" Version="v5.5" />
|
||||
<genTemplate:Item Name="projectType" Value="NavView" />
|
||||
<genTemplate:Item Name="framework" Value="MVVMToolkit" />
|
||||
<genTemplate:Item Name="platform" Value="WinUI" />
|
||||
<genTemplate:Item Name="appmodel" Value="Desktop" />
|
||||
</genTemplate:Metadata>
|
||||
</Package>
|
10
RustTools/Properties/launchsettings.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"profiles": {
|
||||
"RustTools (Package)": {
|
||||
"commandName": "MsixPackage"
|
||||
},
|
||||
"RustTools (Unpackaged)": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
27
RustTools/README.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
*Recommended Markdown Viewer: [Markdown Editor](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.MarkdownEditor2)*
|
||||
|
||||
## Getting Started
|
||||
|
||||
Browse and address `TODO:` comments in `View -> Task List` to learn the codebase and understand next steps for turning the generated code into production code.
|
||||
|
||||
Explore the [WinUI Gallery](https://www.microsoft.com/store/productId/9P3JFPWWDZRC) to learn about available controls and design patterns.
|
||||
|
||||
Relaunch Template Studio to modify the project by right-clicking on the project in `View -> Solution Explorer` then selecting `Add -> New Item (Template Studio)`.
|
||||
|
||||
## Publishing
|
||||
|
||||
For projects with MSIX packaging, right-click on the application project and select `Package and Publish -> Create App Packages...` to create an MSIX package.
|
||||
|
||||
For projects without MSIX packaging, follow the [deployment guide](https://docs.microsoft.com/windows/apps/windows-app-sdk/deploy-unpackaged-apps) or add the `Self-Contained` Feature to enable xcopy deployment.
|
||||
|
||||
## CI Pipelines
|
||||
|
||||
See [README.md](https://github.com/microsoft/TemplateStudio/blob/main/docs/WinUI/pipelines/README.md) for guidance on building and testing projects in CI pipelines.
|
||||
|
||||
## Changelog
|
||||
|
||||
See [releases](https://github.com/microsoft/TemplateStudio/releases) and [milestones](https://github.com/microsoft/TemplateStudio/milestones).
|
||||
|
||||
## Feedback
|
||||
|
||||
Bugs and feature requests should be filed at https://aka.ms/templatestudio.
|