Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c71b9f7

Browse files
Merge pull request #20 from Kibnet/#14
feat: Add config subsystem based on json-file
2 parents 1b843a2 + 2e28cb6 commit c71b9f7

File tree

8 files changed

+196
-9
lines changed

8 files changed

+196
-9
lines changed

‎SimpleStateMachineNodeEditor/App.xaml.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
using System.Reflection;
2-
using System.Windows;
2+
using Microsoft.Extensions.Configuration;
33
using ReactiveUI;
4+
using SimpleStateMachineNodeEditor.Helpers.Configuration;
45
using Splat;
5-
using SimpleStateMachineNodeEditor.Helpers;
66
using SimpleStateMachineNodeEditor.Helpers.Converters;
7+
using Application = System.Windows.Application;
78

89
namespace SimpleStateMachineNodeEditor
910
{
@@ -16,7 +17,18 @@ public App()
1617
{
1718
Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetCallingAssembly());
1819
Locator.CurrentMutable.RegisterConstant(new ConverterBoolAndVisibility(), typeof(IBindingTypeConverter));
19-
}
2020

21+
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
22+
IConfigurationRoot configuration = configurationBuilder.Add<WritableJsonConfigurationSource>(s =>
23+
{
24+
s.FileProvider = null;
25+
s.Path = "Settings.json";
26+
s.Optional = true;
27+
s.ReloadOnChange = true;
28+
s.ResolveFileProvider();
29+
}).Build();
30+
31+
Locator.CurrentMutable.RegisterConstant(configuration, typeof(IConfiguration));
32+
}
2133
}
2234
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using Newtonsoft.Json;
2+
using Newtonsoft.Json.Converters;
3+
using SimpleStateMachineNodeEditor.Helpers.Enums;
4+
5+
namespace SimpleStateMachineNodeEditor
6+
{
7+
public class AppSettings
8+
{
9+
public class AppearanceSettings
10+
{
11+
[JsonConverter(typeof(StringEnumConverter))]
12+
public Themes Theme { get; set; }
13+
}
14+
15+
public AppearanceSettings Appearance { get; set; }
16+
}
17+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System;
2+
using System.IO;
3+
using Microsoft.Extensions.Configuration.Json;
4+
using Newtonsoft.Json;
5+
using Newtonsoft.Json.Linq;
6+
7+
namespace SimpleStateMachineNodeEditor.Helpers.Configuration
8+
{
9+
public class WritableJsonConfigurationProvider : JsonConfigurationProvider
10+
{
11+
public WritableJsonConfigurationProvider(JsonConfigurationSource source) : base(source)
12+
{
13+
}
14+
15+
private void Save(dynamic jsonObj)
16+
{
17+
var fileFullPath = base.Source.FileProvider.GetFileInfo(base.Source.Path).PhysicalPath;
18+
string output = JsonConvert.SerializeObject(jsonObj, Formatting.Indented);
19+
File.WriteAllText(fileFullPath, output);
20+
}
21+
22+
private void SetValue(string key, string value, dynamic jsonObj)
23+
{
24+
base.Set(key, value);
25+
var split = key.Split(":");
26+
var context = jsonObj;
27+
for (int i = 0; i < split.Length; i++)
28+
{
29+
var currentKey = split[i];
30+
if (i < split.Length - 1)
31+
{
32+
var child = jsonObj[currentKey];
33+
if (child == null)
34+
{
35+
context[currentKey] = new JObject();
36+
}
37+
context = context[currentKey];
38+
}
39+
else
40+
{
41+
context[currentKey] = value;
42+
}
43+
}
44+
}
45+
46+
private dynamic GetJsonObj()
47+
{
48+
var fileFullPath = base.Source.FileProvider.GetFileInfo(base.Source.Path).PhysicalPath;
49+
var json = File.Exists(fileFullPath) ? File.ReadAllText(fileFullPath) : "{}";
50+
return JsonConvert.DeserializeObject(json);
51+
}
52+
53+
public override void Set(string key, string value)
54+
{
55+
var jsonObj = GetJsonObj();
56+
SetValue(key, value, jsonObj);
57+
Save(jsonObj);
58+
}
59+
60+
public void Set(string key, object value)
61+
{
62+
var jsonObj = GetJsonObj();
63+
var serialized = JsonConvert.SerializeObject(value);
64+
var jToken = JsonConvert.DeserializeObject(serialized) as JToken ?? new JValue(value);
65+
WalkAndSet(key, jToken, jsonObj);
66+
Save(jsonObj);
67+
}
68+
69+
private void WalkAndSet(string key, JToken value, dynamic jsonObj)
70+
{
71+
switch (value)
72+
{
73+
case JArray jArray:
74+
{
75+
//TODO Realize arrays
76+
break;
77+
}
78+
case JObject jObject:
79+
{
80+
foreach (var propertyInfo in jObject.Properties())
81+
{
82+
var propName = propertyInfo.Name;
83+
var currentKey = key == null ? propName : $"{key}:{propName}";
84+
var propValue = propertyInfo.Value;
85+
WalkAndSet(currentKey, propValue, jsonObj);
86+
}
87+
break;
88+
}
89+
case JValue jValue:
90+
{
91+
SetValue(key, jValue.ToString(), jsonObj);
92+
break;
93+
}
94+
default:
95+
throw new ArgumentOutOfRangeException(nameof(value));
96+
}
97+
}
98+
}
99+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.Linq;
3+
using System.Reflection;
4+
using Microsoft.Extensions.Configuration;
5+
6+
namespace SimpleStateMachineNodeEditor.Helpers.Configuration
7+
{
8+
public static class WritableJsonConfigurationProviderExtensions
9+
{
10+
public static void Set(this IConfiguration configuration, object value)
11+
{
12+
switch (configuration)
13+
{
14+
case IConfigurationRoot configurationRoot:
15+
{
16+
var provider = configurationRoot.Providers.First(p => p is WritableJsonConfigurationProvider) as WritableJsonConfigurationProvider;
17+
provider.Set(null, value);
18+
break;
19+
}
20+
case ConfigurationSection configurationSection:
21+
{
22+
var rootProp = typeof(ConfigurationSection).GetField("_root", BindingFlags.NonPublic | BindingFlags.Instance); ;
23+
var root = rootProp.GetValue(configurationSection) as IConfigurationRoot;
24+
var provider = root.Providers.First(p => p is WritableJsonConfigurationProvider) as WritableJsonConfigurationProvider;
25+
provider.Set(configurationSection.Path, value);
26+
break;
27+
}
28+
default:
29+
throw new ArgumentOutOfRangeException(nameof(configuration));
30+
}
31+
}
32+
}
33+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Microsoft.Extensions.Configuration;
2+
using Microsoft.Extensions.Configuration.Json;
3+
4+
namespace SimpleStateMachineNodeEditor.Helpers.Configuration
5+
{
6+
public class WritableJsonConfigurationSource : JsonConfigurationSource
7+
{
8+
public override IConfigurationProvider Build(IConfigurationBuilder builder)
9+
{
10+
this.EnsureDefaults(builder);
11+
return (IConfigurationProvider)new WritableJsonConfigurationProvider(this);
12+
}
13+
}
14+
}

‎SimpleStateMachineNodeEditor/SimpleStateMachineNodeEditor.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ ReactiveUI 11.4.17</PackageReleaseNotes>
6262
</ItemGroup>
6363

6464
<ItemGroup>
65+
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.5" />
66+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.5" />
67+
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
6568
<PackageReference Include="ReactiveUI" Version="11.4.17" />
6669
<PackageReference Include="ReactiveUI.Events.WPF" Version="11.4.17" />
6770
<PackageReference Include="ReactiveUI.Fody" Version="11.4.17" />

‎SimpleStateMachineNodeEditor/ViewModel/NodesCanvas/ViewModelNodesCanvas.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using System.Windows.Controls;
1616
using System.Windows.Media;
1717
using DynamicData;
18+
using Microsoft.Extensions.Configuration;
1819

1920
namespace SimpleStateMachineNodeEditor.ViewModel
2021
{
@@ -45,10 +46,10 @@ public partial class ViewModelNodesCanvas : ReactiveObject
4546
/// Flag for close application
4647
/// </summary>
4748
[Reactive] public bool NeedExit { get; set; }
48-
[Reactive] public string ImagePath{ get; set; }
49+
[Reactive] public string ImagePath{ get; set; }
4950
[Reactive] public ImageFormats ImageFormat { get; set; }
5051
[Reactive] public bool WithoutMessages { get; set; }
51-
[Reactive] public Themes Theme { get; set; }=Themes.Dark;
52+
[Reactive] public Themes Theme { get; set; }
5253

5354

5455

@@ -63,10 +64,14 @@ public partial class ViewModelNodesCanvas : ReactiveObject
6364
public double ScaleMax = 5;
6465
public double ScaleMin = 0.1;
6566
public double Scales { get; set; } = 0.05;
66-
67+
6768

6869
public ViewModelNodesCanvas()
6970
{
71+
var configuration = Locator.Current.GetService<IConfiguration>();
72+
Theme = configuration.GetSection("Appearance:Theme").Get<Themes>();
73+
if (Theme == Themes.noCorrect) Theme = Themes.Dark;
74+
SetTheme(Theme);
7075
Cutter = new ViewModelCutter(this);
7176
Nodes.Connect().ObserveOnDispatcher().Bind(NodesForView).Subscribe();
7277
SetupCommands();
@@ -107,7 +112,7 @@ private void SetAsStart(ViewModelNode node)
107112

108113
public void LogDebug(string message, params object[] args)
109114
{
110-
if(!WithoutMessages)
115+
if(!WithoutMessages)
111116
Messages.Add(new ViewModelMessage(TypeMessage.Debug, string.Format(message, args)));
112117
}
113118
public void LogError(string message, params object[] args)
@@ -133,7 +138,7 @@ private void UpdateCount(int oldValue, int newValue)
133138
if (newValue > oldValue)
134139
{
135140
NodesCount++;
136-
}
141+
}
137142
}
138143
private string SchemeName()
139144
{

‎SimpleStateMachineNodeEditor/ViewModel/NodesCanvas/ViewModelNodesCanvasCommands.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
using System.Windows;
1313
using System.Windows.Input;
1414
using System.Xml.Linq;
15+
using Microsoft.Extensions.Configuration;
16+
using SimpleStateMachineNodeEditor.Helpers.Configuration;
17+
using Splat;
1518

1619
namespace SimpleStateMachineNodeEditor.ViewModel
1720
{
@@ -137,7 +140,6 @@ private void SetupCommands()
137140
CommandChangeNodeName = new Command<(ViewModelNode node, string newName), (ViewModelNode node, string oldName)>(ChangeNodeName, UnChangeNodeName);
138141
CommandChangeConnectName = new Command<(ViewModelConnector connector, string newName), (ViewModelConnector connector, string oldName)>(ChangeConnectName, UnChangeConnectName);
139142

140-
141143
NotSavedSubscrube();
142144
}
143145

@@ -189,6 +191,8 @@ private void ChangeTheme()
189191
}
190192
private void SetTheme(Themes theme)
191193
{
194+
var configuration = Locator.Current.GetService<IConfiguration>();
195+
configuration.GetSection("Appearance:Theme").Set(theme);
192196
Application.Current.Resources.Clear();
193197
var uri = new Uri(themesPaths[theme], UriKind.RelativeOrAbsolute);
194198
ResourceDictionary resourceDict = Application.LoadComponent(uri) as ResourceDictionary;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /