Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Themable components #231

Merged
merged 56 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
34c6f3a
Create theme manager
snixtho Nov 15, 2023
364ea6b
dont include default theme
snixtho Nov 15, 2023
d4f8d09
fix err
snixtho Nov 15, 2023
54aef6e
again
snixtho Nov 15, 2023
a4fe60a
add theme builder tests
snixtho Nov 16, 2023
2edec8b
Set effective manialink name based on theme config.
snixtho Nov 16, 2023
192d7d9
Add ability to access theme options, option fallback to config. Confi…
snixtho Nov 20, 2023
27ad8ff
fix invalid theme option access
snixtho Nov 20, 2023
26e3430
Avoid generating the theme config the normal way.
snixtho Nov 21, 2023
c3df126
There can now be multiple themes active at the same time, and themes …
snixtho Nov 23, 2023
74990b7
rename options
snixtho Nov 23, 2023
d787a18
Update ManiaTemplates to fix dynamic global variables.
snixtho Nov 25, 2023
4aafb3c
Add color utilities for modifying lightness of a color.
snixtho Nov 27, 2023
be30b09
begin default Theme
snixtho Nov 27, 2023
e9f31e9
Add luma and grayscale calculation utilities.
snixtho Nov 27, 2023
3e04de2
some comments
snixtho Nov 27, 2023
9289440
set default component theme
snixtho Nov 27, 2023
1be30dd
add icons
snixtho Nov 28, 2023
4879f4b
add kenney icons
snixtho Nov 29, 2023
a25e9f6
Use theme for alert
snixtho Nov 29, 2023
fb31276
Use theme for checkbopx
snixtho Nov 29, 2023
9b41b04
use theme for radio button
snixtho Nov 29, 2023
3fffda9
use theme for switch
snixtho Nov 29, 2023
bbd2fc3
Theme for Asay
snixtho Nov 29, 2023
27c53fd
use theme for current map module
snixtho Nov 29, 2023
dceba2b
fastest cp module theme and refactor
snixtho Nov 29, 2023
abc9e43
some fixes and theme for live ranking module
snixtho Nov 29, 2023
8cface3
match ranking theme
snixtho Nov 29, 2023
527d3f7
Theme for ready widget.
snixtho Nov 29, 2023
13b7908
Fixes to MOTD templates.
snixtho Nov 29, 2023
2a82fdf
Theme for Next Map module.
snixtho Nov 30, 2023
c66ddec
OpenPlanet module theme.
snixtho Nov 30, 2023
883869e
Theme for setname module
snixtho Nov 30, 2023
a3dd87d
scoreboard theme
snixtho Dec 1, 2023
802d6e9
spectator target info theme
snixtho Dec 1, 2023
a09c431
Match colors to widgets for spectator target info
snixtho Dec 1, 2023
d1e23b4
override theme from config
snixtho Dec 1, 2023
b2cb8fb
Use primary text color as default.
snixtho Dec 6, 2023
d080544
Add comments.
snixtho Dec 6, 2023
ea17bc1
fix tests and more comments
snixtho Dec 6, 2023
679e5f5
remove external module
snixtho Dec 6, 2023
f44e7b6
Update src/EvoSC.Common/Util/ColorUtils.cs
snixtho Dec 9, 2023
6f91122
optimize usings
snixtho Dec 11, 2023
f38e4e3
Merge remote-tracking branch 'origin/229-themable-components' into 22…
snixtho Dec 11, 2023
8d5da75
fix potential null exception
snixtho Dec 11, 2023
f993a11
fix sonarcloud issues
snixtho Dec 11, 2023
73b5205
fix tests
snixtho Dec 11, 2023
f604650
fix more sonarcloud
snixtho Dec 11, 2023
a0159c3
add async postfix
snixtho Dec 11, 2023
0477d1c
Merge branch 'master' into 229-themable-components
snixtho Dec 11, 2023
ee5aa1f
Update src/EvoSC.Common/Config/Mapping/Toml/ThemeConfigOptionsMapper.cs
snixtho Dec 11, 2023
c3991c5
move public method up
snixtho Dec 11, 2023
e848f04
Update src/EvoSC.Common/Util/ColorUtils.cs
snixtho Dec 11, 2023
fa681ce
Update src/EvoSC.Common/Util/ColorUtils.cs
snixtho Dec 11, 2023
2576bd3
remove commented code
snixtho Dec 11, 2023
d0c8554
Merge remote-tracking branch 'origin/229-themable-components' into 22…
snixtho Dec 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion EvoSC.sln
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvoSC.Manialinks.Tests", "t
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SetName", "src\Modules\SetName\SetName.csproj", "{568D81FE-858A-4052-B59B-9381E0FE604C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastestCp", "src\Modules\FastestCp\FastestCp.csproj", "{9E1335F9-6C39-4B3F-9CEB-A65EEDDF798D}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastestCpModule", "src\Modules\FastestCpModule\FastestCpModule.csproj", "{9E1335F9-6C39-4B3F-9CEB-A65EEDDF798D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{6D75D6A2-6ECD-4DE4-96C5-CAD7D134407A}"
EndProject
Expand Down Expand Up @@ -104,6 +104,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModuleManagerModule", "src\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatchTrackerModule.Tests", "tests\Modules\MatchTrackerModule.Tests\MatchTrackerModule.Tests.csproj", "{9EF4D340-0C49-4A15-9BCF-6CD9508AA7DE}"
EndProject



Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down
1 change: 0 additions & 1 deletion src/EvoSC.Commands/Parser/ChatCommandParser.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using EvoSC.Commands.Exceptions;
using EvoSC.Commands.Interfaces;
using EvoSC.Common.Interfaces.Parsing;

namespace EvoSC.Commands.Parser;

Expand Down
8 changes: 7 additions & 1 deletion src/EvoSC.Common/Application/AppFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,11 @@ public enum AppFeature
/// Manage, add, remove, display manialinks and respond to actions. The manialink framework.
/// </summary>
[Identifier(NoPrefix = true)]
Manialinks
Manialinks,

/// <summary>
/// Add, remove and manage themes using the theme manager.
/// </summary>
[Identifier(NoPrefix = true)]
Themes
}
5 changes: 3 additions & 2 deletions src/EvoSC.Common/Config/Configuration.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using Config.Net;
using EvoSC.Common.Config.Models;
using EvoSC.Common.Config.Stores;
using EvoSC.Common.Config.Mapping;
using EvoSC.Common.Config.Mapping.Toml;
using EvoSC.Common.Config.Models;
using EvoSC.Common.Config.Stores;

namespace EvoSC.Common.Config;

Expand All @@ -23,6 +23,7 @@ public static IEvoScBaseConfig GetBaseConfig(string configFile, Dictionary<strin
.UseEvoScConfig(MainConfigFile, cliOptions)
.UseTypeParser(new TextColorTypeParser())
.UseTypeParser(new VersionParser())
.UseTypeParser(new ThemeOptionsParser())
.Build();

return baseConfig;
Expand Down
47 changes: 47 additions & 0 deletions src/EvoSC.Common/Config/Mapping/ThemeOptionsParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Diagnostics.CodeAnalysis;
using Config.Net;
using EvoSC.Common.Themes;
using Tomlet;
using Tomlet.Models;

namespace EvoSC.Common.Config.Mapping;

public class ThemeOptionsParser : ITypeParser
{
public bool TryParse(string? value, Type t, [UnscopedRef] out object? result)
{
var parser = new TomlParser();
var doc = parser.Parse(value);
var options = new Dictionary<string, object>();

foreach (var entry in doc.Entries)
{
GetEntriesRecursive(entry.Key, entry.Value, options);
}

result = new DynamicThemeOptions(options);
return true;
}

public string? ToRawString(object? value)
{
return "";
}

public IEnumerable<Type> SupportedTypes => new[] { typeof(DynamicThemeOptions) };

private void GetEntriesRecursive(string name, TomlValue tomlValue, Dictionary<string, object> options)
{
if (tomlValue is TomlTable table)
{
foreach (var entry in table.Entries)
{
GetEntriesRecursive($"{name}.{entry.Key}", entry.Value, options);
}
}
else
{
options[name] = tomlValue.StringValue;
}
}
}
1 change: 1 addition & 0 deletions src/EvoSC.Common/Config/Mapping/Toml/ConfigMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public static void AddMapper<T>(ITomlTypeMapper<T> mapper) =>
public static void SetupDefaultMappers()
{
AddMapper(new TextColorTomlMapper());
AddMapper(new ThemeConfigOptionsMapper());
}
}
82 changes: 82 additions & 0 deletions src/EvoSC.Common/Config/Mapping/Toml/ThemeConfigOptionsMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using EvoSC.Common.Interfaces.Config.Mapping;
using EvoSC.Common.Themes;
using Tomlet;
using Tomlet.Models;

namespace EvoSC.Common.Config.Mapping.Toml;

public class ThemeConfigOptionsMapper : ITomlTypeMapper<DynamicThemeOptions>
{
public TomlValue Serialize(DynamicThemeOptions? typeValue)
{
var doc = TomlDocument.CreateEmpty();

foreach (var option in typeValue)
{
BuildTomlDocument(doc, option.Key.Split('.'), option.Value);
}

return doc;
}

public DynamicThemeOptions Deserialize(TomlValue tomlValue)
{
var doc = tomlValue as TomlDocument;

if (doc == null)
{
throw new InvalidOperationException("Value is not a document");
}

var options = new DynamicThemeOptions();

foreach (var entry in doc.Entries)
{
BuildOptionsObject(options, entry.Key, entry.Value);
}

return options;
}

private void BuildTomlDocument(TomlDocument doc, IEnumerable<string> optionParts, object value)
{
var parts = optionParts as string[] ?? optionParts.ToArray();

if (parts.Length == 1)
{
var tomlValue = TomletMain.ValueFrom(value);
doc.Entries[parts.First()] = tomlValue;
return;
}

foreach (var part in parts)
{
if (doc.ContainsKey(part))
{
BuildTomlDocument((TomlDocument)doc.Entries[part], parts.Skip(1), value);
}
else
{
var newDoc = TomlDocument.CreateEmpty();
doc.Entries[part] = newDoc;
BuildTomlDocument(newDoc, parts.Skip(1), value);
}
}
}

private void BuildOptionsObject(DynamicThemeOptions options, string key, TomlValue tomlValue)
{
var doc = tomlValue as TomlDocument;

if (doc == null)
{
options[key] = tomlValue.StringValue;
return;
}

foreach (var entry in doc.Entries)
{
BuildOptionsObject(options, $"{key}.{entry.Key}", entry.Value);
}
}
}
8 changes: 6 additions & 2 deletions src/EvoSC.Common/Config/Models/IEvoScBaseConfig.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
namespace EvoSC.Common.Config.Models;
using EvoSC.Common.Themes;

namespace EvoSC.Common.Config.Models;

public interface IEvoScBaseConfig
{
public IDatabaseConfig Database { get; set; }
public ILoggingConfig Logging { get; set; }
public IServerConfig Server { get; set; }
public IPathConfig Path { get; set; }
public IThemeConfig Theme { get; set; }

public IModuleConfig Modules { get; set; }
public ILocaleConfig Locale { get; set; }

public DynamicThemeOptions Theme { get; set; }
}
21 changes: 16 additions & 5 deletions src/EvoSC.Common/Config/Stores/TomlConfigStore.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Globalization;
using System.Reflection;
using Config.Net;
using EvoSC.Common.Themes;
using EvoSC.Common.Util;
using EvoSC.Common.Util.TextFormatting;
using Tomlet;
using Tomlet.Exceptions;
using Tomlet.Models;

namespace EvoSC.Common.Config.Stores;
Expand All @@ -20,11 +19,11 @@
{
if (!File.Exists(path))
{
string directory = Path.GetDirectoryName(path);

Check warning on line 22 in src/EvoSC.Common/Config/Stores/TomlConfigStore.cs

View workflow job for this annotation

GitHub Actions / build_and_test

Converting null literal or possible null value to non-nullable type.

if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);

Check warning on line 26 in src/EvoSC.Common/Config/Stores/TomlConfigStore.cs

View workflow job for this annotation

GitHub Actions / build_and_test

Possible null reference argument for parameter 'path' in 'DirectoryInfo Directory.CreateDirectory(string path)'.
}

_document = CreateDefaultConfig();
Expand Down Expand Up @@ -53,6 +52,11 @@
{
foreach (var property in type.GetProperties())
{
if (property.PropertyType == typeof(DynamicThemeOptions))
{
continue;
}

if (property.PropertyType.IsInterface)
{
document = BuildSubDocument(document, property.PropertyType, name == "" ? property.Name : $"{name}.{property.Name}");
Expand All @@ -68,11 +72,13 @@

var tomlValue = optionAttr?.DefaultValue ?? property.PropertyType.GetDefaultTypeValue();
if (property.PropertyType == typeof(TextColor))
{
tomlValue = new TextColor(tomlValue.ToString());

Check warning on line 76 in src/EvoSC.Common/Config/Stores/TomlConfigStore.cs

View workflow job for this annotation

GitHub Actions / build_and_test

Dereference of a possibly null reference.

Check warning on line 76 in src/EvoSC.Common/Config/Stores/TomlConfigStore.cs

View workflow job for this annotation

GitHub Actions / build_and_test

Possible null reference argument for parameter 'hex' in 'TextColor.TextColor(string hex)'.
}

// get property value
var value = TomletMain.ValueFrom(property.PropertyType,
tomlValue);

Check warning on line 81 in src/EvoSC.Common/Config/Stores/TomlConfigStore.cs

View workflow job for this annotation

GitHub Actions / build_and_test

Possible null reference argument for parameter 't' in 'TomlValue? TomletMain.ValueFrom(Type type, object t)'.

// add description/comment if defined
if (descAttr != null)
Expand Down Expand Up @@ -100,13 +106,13 @@
if (lastDotIndex > 0 && key.Length > lastDotIndex + 1 && !char.IsAsciiLetterOrDigit(key[lastDotIndex + 1]))
{
var value = _document.GetValue(key[..lastDotIndex]) as TomlArray;
return value.Count.ToString();
return value.Count.ToString(CultureInfo.InvariantCulture);
}

if (key.EndsWith("]", StringComparison.Ordinal))
{
var indexStart = key.IndexOf("[", StringComparison.Ordinal);
var index = int.Parse(key[(indexStart + 1)..^1]);
var index = int.Parse(key[(indexStart + 1)..^1], CultureInfo.InvariantCulture);
var value = _document.GetValue(key[..indexStart]) as TomlArray;

return value?.Skip(index)?.FirstOrDefault()?.StringValue;
Expand All @@ -118,6 +124,11 @@
{
return string.Join(" ", arrayValue.Select(v => v.StringValue));
}

if (keyValue is TomlTable tableValue)
{
return tableValue.SerializeNonInlineTable("Theme", false);
}

return keyValue.StringValue;
}
Expand Down
1 change: 0 additions & 1 deletion src/EvoSC.Common/Database/Repository/DbRepository.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

using EvoSC.Common.Interfaces.Database;
using LinqToDB;
using LinqToDB.Data;

namespace EvoSC.Common.Database.Repository;

Expand Down
1 change: 1 addition & 0 deletions src/EvoSC.Common/EvoSC.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="ColorMinePortable" Version="2.0.4" />
<PackageReference Include="Config.Net" Version="5.1.4" />
<PackageReference Include="FluentMigrator" Version="3.3.2" />
<PackageReference Include="FluentMigrator.Runner" Version="3.3.2" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using LinqToDB;
using LinqToDB.Data;

namespace EvoSC.Common.Interfaces.Database;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ public interface IServiceContainerManager
/// <param name="moduleId">The ID of the module that requires the dependency.</param>
/// <param name="dependencyId">The ID of the dependency.</param>
public void RegisterDependency(Guid moduleId, Guid dependencyId);

public Container GetContainer(Guid moduleId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using EvoSC.Common.Themes;

namespace EvoSC.Common.Interfaces.Themes.Builders;

public interface IReplaceComponentBuilder<out TTheme>
where TTheme : Theme<TTheme>
{
/// <summary>
/// Replace a component with the provided component.
/// </summary>
/// <param name="newComponent">Name of the new component that will replace the old component.</param>
/// <returns></returns>
public TTheme With(string newComponent);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using EvoSC.Common.Themes;

namespace EvoSC.Common.Interfaces.Themes.Builders;

public interface ISetThemeOptionBuilder<TTheme> where TTheme : Theme<TTheme>
{
/// <summary>
/// Set a theme option value.
/// </summary>
/// <param name="value">Value of the theme option.</param>
/// <returns></returns>
public TTheme To(object value);
}
Loading
Loading