-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
using System; | ||
using System.Collections.Frozen; | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using System.Threading.Tasks; | ||
using DSharpPlus.Commands.Processors.SlashCommands; | ||
using DSharpPlus.Commands.Processors.SlashCommands.ArgumentModifiers; | ||
using DSharpPlus.Entities; | ||
|
||
namespace OoLunar.Tomoe.AutocompleteProviders | ||
{ | ||
public sealed class CultureInfoAutocompleteProvider : IAutoCompleteProvider | ||
Check failure on line 12 in src/AutocompleteProviders/CultureInfoAutocompleteProvider.cs GitHub Actions / Build Commit
Check failure on line 12 in src/AutocompleteProviders/CultureInfoAutocompleteProvider.cs GitHub Actions / Build Commit
Check failure on line 12 in src/AutocompleteProviders/CultureInfoAutocompleteProvider.cs GitHub Actions / Build Commit
Check failure on line 12 in src/AutocompleteProviders/CultureInfoAutocompleteProvider.cs GitHub Actions / Build Commit
|
||
{ | ||
private static readonly CultureInfo[] _cultures; | ||
private static readonly FrozenSet<DiscordAutoCompleteChoice> _defaultCultureList; | ||
private static readonly FrozenDictionary<CultureInfo, string> _cultureInfoDisplayNames; | ||
|
||
static CultureInfoAutocompleteProvider() | ||
{ | ||
_cultures = CultureInfo.GetCultures(CultureTypes.AllCultures); | ||
Array.Sort(_cultures, (x, y) => string.Compare(x.DisplayName, y.DisplayName, StringComparison.Ordinal)); | ||
|
||
List<DiscordAutoCompleteChoice> choices = []; | ||
Dictionary<CultureInfo, string> cultureInfoDisplayNames = []; | ||
for (int i = 0; i < _cultures.Length; i++) | ||
{ | ||
string displayName = $"{_cultures[i].DisplayName} ({_cultures[i].IetfLanguageTag})"; | ||
cultureInfoDisplayNames[_cultures[i]] = displayName; | ||
|
||
// Only add the first 25 cultures to the default list | ||
// which is returned when the user input is empty | ||
if (i < 25) | ||
{ | ||
choices.Add(new DiscordAutoCompleteChoice(displayName, _cultures[i].IetfLanguageTag)); | ||
} | ||
} | ||
|
||
_defaultCultureList = choices.ToFrozenSet(); | ||
_cultureInfoDisplayNames = cultureInfoDisplayNames.ToFrozenDictionary(); | ||
} | ||
|
||
public ValueTask<IEnumerable<DiscordAutoCompleteChoice>> AutoCompleteAsync(AutoCompleteContext context) | ||
{ | ||
if (string.IsNullOrWhiteSpace(context.UserInput)) | ||
{ | ||
return ValueTask.FromResult<IEnumerable<DiscordAutoCompleteChoice>>(_defaultCultureList); | ||
} | ||
|
||
List<DiscordAutoCompleteChoice> choices = []; | ||
foreach (CultureInfo cultureInfo in _cultures) | ||
{ | ||
if (choices.Count >= 25) | ||
{ | ||
break; | ||
} | ||
else if (cultureInfo.DisplayName.Contains(context.UserInput, StringComparison.OrdinalIgnoreCase) | ||
|| cultureInfo.EnglishName.Contains(context.UserInput, StringComparison.OrdinalIgnoreCase) | ||
|| cultureInfo.IetfLanguageTag.Contains(context.UserInput, StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
choices.Add(new DiscordAutoCompleteChoice(_cultureInfoDisplayNames[cultureInfo], cultureInfo.Name)); | ||
} | ||
} | ||
|
||
return ValueTask.FromResult<IEnumerable<DiscordAutoCompleteChoice>>(choices); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
using System; | ||
using System.Collections.Frozen; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using DSharpPlus.Commands.Processors.SlashCommands; | ||
using DSharpPlus.Commands.Processors.SlashCommands.ArgumentModifiers; | ||
using DSharpPlus.Entities; | ||
|
||
namespace OoLunar.Tomoe.AutocompleteProviders | ||
{ | ||
public sealed class TimeZoneInfoAutocompleteProvider : IAutoCompleteProvider | ||
Check failure on line 11 in src/AutocompleteProviders/TimeZoneInfoAutocompleteProvider.cs GitHub Actions / Build Commit
Check failure on line 11 in src/AutocompleteProviders/TimeZoneInfoAutocompleteProvider.cs GitHub Actions / Build Commit
Check failure on line 11 in src/AutocompleteProviders/TimeZoneInfoAutocompleteProvider.cs GitHub Actions / Build Commit
Check failure on line 11 in src/AutocompleteProviders/TimeZoneInfoAutocompleteProvider.cs GitHub Actions / Build Commit
|
||
{ | ||
private static readonly TimeZoneInfo[] _timezones; | ||
private static readonly FrozenSet<DiscordAutoCompleteChoice> _defaultTimezoneList; | ||
private static readonly FrozenDictionary<TimeZoneInfo, string> _timezoneDisplayNames; | ||
|
||
static TimeZoneInfoAutocompleteProvider() | ||
{ | ||
_timezones = [.. TimeZoneInfo.GetSystemTimeZones()]; | ||
Array.Sort(_timezones, (x, y) => string.Compare(x.DisplayName, y.DisplayName, StringComparison.Ordinal)); | ||
|
||
List<DiscordAutoCompleteChoice> choices = []; | ||
Dictionary<TimeZoneInfo, string> timezoneDisplayNames = []; | ||
for (int i = 0; i < _timezones.Length; i++) | ||
{ | ||
string displayName = $"{_timezones[i].DisplayName} ({_timezones[i].Id})"; | ||
timezoneDisplayNames[_timezones[i]] = displayName; | ||
|
||
// Only add the first 25 timezones to the default list | ||
// which is returned when the user input is empty | ||
if (i < 25) | ||
{ | ||
choices.Add(new DiscordAutoCompleteChoice(displayName, _timezones[i].Id)); | ||
} | ||
} | ||
|
||
_defaultTimezoneList = choices.ToFrozenSet(); | ||
_timezoneDisplayNames = timezoneDisplayNames.ToFrozenDictionary(); | ||
} | ||
|
||
public ValueTask<IEnumerable<DiscordAutoCompleteChoice>> AutoCompleteAsync(AutoCompleteContext context) | ||
{ | ||
if (string.IsNullOrWhiteSpace(context.UserInput)) | ||
{ | ||
return ValueTask.FromResult<IEnumerable<DiscordAutoCompleteChoice>>(_defaultTimezoneList); | ||
} | ||
|
||
List<DiscordAutoCompleteChoice> choices = []; | ||
foreach (TimeZoneInfo timezone in _timezones) | ||
{ | ||
if (choices.Count >= 25) | ||
{ | ||
break; | ||
} | ||
else if (timezone.DisplayName.Contains(context.UserInput, StringComparison.OrdinalIgnoreCase) | ||
|| timezone.StandardName.Contains(context.UserInput, StringComparison.OrdinalIgnoreCase) | ||
|| timezone.Id.Contains(context.UserInput, StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
choices.Add(new DiscordAutoCompleteChoice(_timezoneDisplayNames[timezone], timezone.Id)); | ||
} | ||
} | ||
|
||
return ValueTask.FromResult<IEnumerable<DiscordAutoCompleteChoice>>(choices); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
using DSharpPlus.Commands; | ||
|
||
namespace OoLunar.Tomoe.Commands | ||
{ | ||
/// <summary> | ||
/// Manages settings that the bot uses to personalize the experience for the user, server or globally. | ||
/// </summary> | ||
[Command("settings")] | ||
public sealed partial class SettingsCommand; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using System.Globalization; | ||
using System.Threading.Tasks; | ||
using DSharpPlus.Commands; | ||
using DSharpPlus.Commands.Trees.Metadata; | ||
using OoLunar.Tomoe.Database.Models; | ||
|
||
namespace OoLunar.Tomoe.Commands | ||
{ | ||
public sealed partial class SettingsCommand | ||
{ | ||
public static partial class UserSettingsCommand | ||
{ | ||
/// <summary> | ||
/// Sets the culture for the current user, which is responsible for formatting dates and numbers. | ||
/// </summary> | ||
[Command("culture"), DefaultGroupCommand] | ||
public static async ValueTask CultureAsync(CommandContext context, CultureInfo? culture = null) | ||
{ | ||
UserSettingsModel? userSettings = await UserSettingsModel.GetUserSettingsAsync(context.User.Id); | ||
if (userSettings is null) | ||
{ | ||
await context.RespondAsync(SETTINGS_NOT_SETUP); | ||
return; | ||
} | ||
else if (culture is null) | ||
{ | ||
await context.RespondAsync($"Your current culture is set to {userSettings.Culture.NativeName}/{userSettings.Culture.IetfLanguageTag}."); | ||
return; | ||
} | ||
|
||
userSettings = userSettings with { Culture = culture }; | ||
await UserSettingsModel.UpdateUserSettingsAsync(userSettings); | ||
await context.RespondAsync($"Your culture has been updated to {culture.NativeName}/{culture.IetfLanguageTag}."); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
using System.Threading.Tasks; | ||
using DSharpPlus.Commands; | ||
using DSharpPlus.Commands.Trees.Metadata; | ||
using DSharpPlus.Entities; | ||
using OoLunar.Tomoe.Database.Models; | ||
|
||
namespace OoLunar.Tomoe.Commands | ||
{ | ||
public sealed partial class SettingsCommand | ||
{ | ||
public static partial class UserSettingsCommand | ||
{ | ||
private const string SETTINGS_NOT_SETUP = "Your user settings have not been set up yet! Please run `/settings user setup` to set them up."; | ||
|
||
/// <summary> | ||
/// Lists all the settings for the current user. | ||
/// </summary> | ||
[Command("list"), DefaultGroupCommand] | ||
public static async ValueTask ListSettingsAsync(CommandContext context) | ||
{ | ||
UserSettingsModel? userSettings = await UserSettingsModel.GetUserSettingsAsync(context.User.Id); | ||
if (userSettings is null) | ||
{ | ||
await context.RespondAsync(SETTINGS_NOT_SETUP); | ||
return; | ||
} | ||
|
||
DiscordEmbedBuilder embedBuilder = new() | ||
{ | ||
Title = "User Settings", | ||
Color = new DiscordColor("#6b73db") | ||
}; | ||
|
||
embedBuilder.AddField("Culture", $"{userSettings.Culture.NativeName}/{userSettings.Culture.IetfLanguageTag}", true); | ||
embedBuilder.AddField("Timezone", userSettings.Timezone.Id, true); | ||
await context.RespondAsync(embedBuilder); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using System; | ||
using System.Globalization; | ||
using System.Threading.Tasks; | ||
using DSharpPlus.Commands; | ||
using DSharpPlus.Commands.Trees.Metadata; | ||
using OoLunar.Tomoe.Database.Models; | ||
|
||
namespace OoLunar.Tomoe.Commands | ||
{ | ||
public sealed partial class SettingsCommand | ||
{ | ||
public static partial class UserSettingsCommand | ||
{ | ||
/// <summary> | ||
/// Sets the timezone for the current user, which is responsible for time-based commands such as reminders. | ||
/// </summary> | ||
[Command("setup"), DefaultGroupCommand] | ||
public static async ValueTask SetupAsync(CommandContext context, CultureInfo? culture = null, TimeZoneInfo? timezone = null) | ||
{ | ||
UserSettingsModel userSettings = new() | ||
{ | ||
UserId = context.User.Id, | ||
Culture = culture ?? CultureInfo.CurrentCulture, | ||
Timezone = timezone ?? TimeZoneInfo.Local | ||
}; | ||
|
||
await UserSettingsModel.UpdateUserSettingsAsync(userSettings); | ||
await context.RespondAsync($"Your user settings have been set up with the culture {userSettings.Culture.NativeName}/{userSettings.Culture.IetfLanguageTag} and timezone {userSettings.Timezone.DisplayName}/{userSettings.Timezone.Id}."); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using DSharpPlus.Commands; | ||
using DSharpPlus.Commands.Trees.Metadata; | ||
using OoLunar.Tomoe.Database.Models; | ||
|
||
namespace OoLunar.Tomoe.Commands | ||
{ | ||
public sealed partial class SettingsCommand | ||
{ | ||
public static partial class UserSettingsCommand | ||
{ | ||
/// <summary> | ||
/// Sets the timezone for the current user, which is responsible for time-based commands such as reminders. | ||
/// </summary> | ||
[Command("timezone"), DefaultGroupCommand] | ||
public static async ValueTask CultureAsync(CommandContext context, TimeZoneInfo? timezone = null) | ||
{ | ||
UserSettingsModel? userSettings = await UserSettingsModel.GetUserSettingsAsync(context.User.Id); | ||
if (userSettings is null) | ||
{ | ||
await context.RespondAsync(SETTINGS_NOT_SETUP); | ||
return; | ||
} | ||
else if (timezone is null) | ||
{ | ||
await context.RespondAsync($"Your current culture is set to {userSettings.Timezone.DisplayName}/{userSettings.Timezone.Id}."); | ||
return; | ||
} | ||
|
||
userSettings = userSettings with { Timezone = timezone }; | ||
await UserSettingsModel.UpdateUserSettingsAsync(userSettings); | ||
await context.RespondAsync($"Your culture has been updated to {timezone.DisplayName}/{timezone.Id}."); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using DSharpPlus.Commands; | ||
|
||
namespace OoLunar.Tomoe.Commands | ||
{ | ||
public sealed partial class SettingsCommand | ||
{ | ||
/// <summary> | ||
/// Manages settings for the current user, such as their culture and timezone. | ||
/// </summary> | ||
[Command("user")] | ||
public static partial class UserSettingsCommand; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
using System.Globalization; | ||
using System.Threading.Tasks; | ||
using DSharpPlus.Commands.Converters; | ||
using DSharpPlus.Commands.Processors.SlashCommands; | ||
using DSharpPlus.Commands.Processors.TextCommands; | ||
using DSharpPlus.Entities; | ||
|
||
namespace OoLunar.Tomoe.Converters | ||
{ | ||
public sealed class CultureInfoConverter : ISlashArgumentConverter<CultureInfo>, ITextArgumentConverter<CultureInfo> | ||
Check failure on line 10 in src/Converters/CultureInfoConverter.cs GitHub Actions / Build Commit
Check failure on line 10 in src/Converters/CultureInfoConverter.cs GitHub Actions / Build Commit
Check failure on line 10 in src/Converters/CultureInfoConverter.cs GitHub Actions / Build Commit
Check failure on line 10 in src/Converters/CultureInfoConverter.cs GitHub Actions / Build Commit
Check failure on line 10 in src/Converters/CultureInfoConverter.cs GitHub Actions / Build Commit
Check failure on line 10 in src/Converters/CultureInfoConverter.cs GitHub Actions / Build Commit
Check failure on line 10 in src/Converters/CultureInfoConverter.cs GitHub Actions / Build Commit
Check failure on line 10 in src/Converters/CultureInfoConverter.cs GitHub Actions / Build Commit
|
||
{ | ||
public bool RequiresText => true; | ||
public string ReadableName => "Culture Info"; | ||
public DiscordApplicationCommandOptionType ParameterType => DiscordApplicationCommandOptionType.String; | ||
|
||
public Task<Optional<CultureInfo>> ConvertAsync(ConverterContext context) | ||
{ | ||
try | ||
{ | ||
return context.Argument switch | ||
{ | ||
// String will be from text commands | ||
string languageTag => Task.FromResult(Optional.FromValue(CultureInfo.GetCultureInfoByIetfLanguageTag(languageTag))), | ||
|
||
// Int will be from slash commands, either through a choice provider or autocomplete | ||
int cultureId => Task.FromResult(Optional.FromValue(CultureInfo.GetCultureInfo(cultureId))), | ||
|
||
// What the fuck. | ||
_ => Task.FromResult(Optional.FromNoValue<CultureInfo>()) | ||
}; | ||
} | ||
catch | ||
{ | ||
return Task.FromResult(Optional.FromNoValue<CultureInfo>()); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using DSharpPlus.Commands.Converters; | ||
using DSharpPlus.Commands.Processors.SlashCommands; | ||
using DSharpPlus.Commands.Processors.TextCommands; | ||
using DSharpPlus.Entities; | ||
|
||
namespace OoLunar.Tomoe.Converters | ||
{ | ||
public sealed class TimeZoneInfoConverter : ISlashArgumentConverter<TimeZoneInfo>, ITextArgumentConverter<TimeZoneInfo> | ||
Check failure on line 10 in src/Converters/TimeZoneConverter.cs GitHub Actions / Build Commit
Check failure on line 10 in src/Converters/TimeZoneConverter.cs GitHub Actions / Build Commit
Check failure on line 10 in src/Converters/TimeZoneConverter.cs GitHub Actions / Build Commit
Check failure on line 10 in src/Converters/TimeZoneConverter.cs GitHub Actions / Build Commit
|
||
{ | ||
public bool RequiresText => true; | ||
public string ReadableName => "Timezone"; | ||
public DiscordApplicationCommandOptionType ParameterType => DiscordApplicationCommandOptionType.String; | ||
|
||
public Task<Optional<TimeZoneInfo>> ConvertAsync(ConverterContext context) | ||
{ | ||
if (context.Argument is not string argument) | ||
{ | ||
return Task.FromResult(Optional.FromNoValue<TimeZoneInfo>()); | ||
} | ||
else if (TimeZoneInfo.TryFindSystemTimeZoneById(argument, out TimeZoneInfo? timeZoneInfo)) | ||
{ | ||
return Task.FromResult(Optional.FromValue(timeZoneInfo)); | ||
} | ||
|
||
return Task.FromResult(Optional.FromNoValue<TimeZoneInfo>()); | ||
} | ||
} | ||
} |