diff --git a/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableChannel.cs b/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableChannel.cs
index a5159fdb9..d79596b46 100644
--- a/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableChannel.cs
+++ b/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableChannel.cs
@@ -7,6 +7,7 @@
using Quarrel.Client.Models.Users;
using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
+using Quarrel.Services.Localization;
using System;
namespace Quarrel.Bindables.Channels.Abstract
@@ -84,19 +85,20 @@ private void AckUpdateRoot(object sender, EventArgs e)
///
/// Creates a new instance of a based on the type.
///
- /// The discord service to pass to the .
- /// The dispatcher service to pass to the .
+ /// The to pass to the .
+ /// The to pass to the .
+ /// The to pass to the .
/// The channel to wrap.
/// The current user's guild member for the channel's guild. Null if not a guild channel.
/// The parent category of the channel.
- public static BindableChannel? Create(IDiscordService discordService, IDispatcherService dispatcherService, IChannel channel, GuildMember? member = null, BindableCategoryChannel? parent = null)
+ public static BindableChannel? Create(IDiscordService discordService, ILocalizationService localizationService, IDispatcherService dispatcherService, IChannel channel, GuildMember? member = null, BindableCategoryChannel? parent = null)
{
if (member is null)
{
return channel switch
{
DirectChannel c => new BindableDirectChannel(discordService, dispatcherService, c),
- GroupChannel c => new BindableGroupChannel(discordService, dispatcherService, c),
+ GroupChannel c => new BindableGroupChannel(discordService, localizationService, dispatcherService, c),
_ => null
};
}
diff --git a/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableGuildChannel.cs b/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableGuildChannel.cs
index 9d9d518a5..e9eb56cd3 100644
--- a/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableGuildChannel.cs
+++ b/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableGuildChannel.cs
@@ -8,6 +8,7 @@
using Quarrel.Client.Models.Users;
using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
+using Quarrel.Services.Localization;
namespace Quarrel.Bindables.Channels.Abstract
{
@@ -57,14 +58,15 @@ internal BindableGuildChannel(IDiscordService discordService, IDispatcherService
///
/// Creates a new based on the type.
///
- /// The discord service to pass to the .
- /// The dispatcher service to pass to the .
+ /// The to pass to the .
+ /// The to pass to the .
+ /// The to pass to the .
/// The channel to wrap.
/// The current user's guild member for the channel's guild.
/// The channel's parent category.
- public static BindableGuildChannel? Create(IDiscordService discordService, IDispatcherService dispatcherService, IGuildChannel channel, GuildMember member, BindableCategoryChannel? parent = null)
+ public static BindableGuildChannel? Create(IDiscordService discordService, ILocalizationService localizationService, IDispatcherService dispatcherService, IGuildChannel channel, GuildMember member, BindableCategoryChannel? parent = null)
{
- return BindableChannel.Create(discordService, dispatcherService, channel, member, parent) as BindableGuildChannel;
+ return BindableChannel.Create(discordService, localizationService, dispatcherService, channel, member, parent) as BindableGuildChannel;
}
///
diff --git a/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindablePrivateChannel.cs b/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindablePrivateChannel.cs
index 08ab0add9..6d90b2077 100644
--- a/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindablePrivateChannel.cs
+++ b/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindablePrivateChannel.cs
@@ -5,6 +5,7 @@
using Quarrel.Client.Models.Channels.Interfaces;
using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
+using Quarrel.Services.Localization;
namespace Quarrel.Bindables.Channels.Abstract
{
@@ -27,9 +28,9 @@ internal BindablePrivateChannel(IDiscordService discordService, IDispatcherServi
///
public IMessageChannel MessageChannel => (IMessageChannel)Channel;
- public static BindablePrivateChannel? Create(IDiscordService discordService, IDispatcherService dispatcherService, IPrivateChannel channel)
+ public static BindablePrivateChannel? Create(IDiscordService discordService, ILocalizationService localizationService, IDispatcherService dispatcherService, IPrivateChannel channel)
{
- return BindableChannel.Create(discordService, dispatcherService, channel) as BindablePrivateChannel;
+ return BindableChannel.Create(discordService, localizationService, dispatcherService, channel) as BindablePrivateChannel;
}
}
}
diff --git a/src/Quarrel.ViewModels/Bindables/Channels/BindableGroupChannel.cs b/src/Quarrel.ViewModels/Bindables/Channels/BindableGroupChannel.cs
index 306b9f47d..2fe2394fe 100644
--- a/src/Quarrel.ViewModels/Bindables/Channels/BindableGroupChannel.cs
+++ b/src/Quarrel.ViewModels/Bindables/Channels/BindableGroupChannel.cs
@@ -8,6 +8,8 @@
using Quarrel.Client.Models.Channels.Interfaces;
using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
+using Quarrel.Services.Localization;
+using System.Linq;
namespace Quarrel.Bindables.Channels
{
@@ -16,9 +18,13 @@ namespace Quarrel.Bindables.Channels
///
public class BindableGroupChannel : BindablePrivateChannel, IBindableMessageChannel
{
- internal BindableGroupChannel(IDiscordService discordService, IDispatcherService dispatcherService, GroupChannel groupChannel) :
+ private ILocalizationService _localizationService;
+
+ internal BindableGroupChannel(IDiscordService discordService, ILocalizationService localizationService, IDispatcherService dispatcherService, GroupChannel groupChannel) :
base(discordService, dispatcherService, groupChannel)
{
+ _localizationService = localizationService;
+
Guard.IsNotNull(groupChannel.Recipients);
Recipients = new BindableUser[groupChannel.Recipients.Length];
int i = 0;
@@ -32,17 +38,24 @@ internal BindableGroupChannel(IDiscordService discordService, IDispatcherService
}
///
- public IGroupChannel DirectChannel => (IGroupChannel)Channel;
+ public IGroupChannel GroupChannel => (IGroupChannel)Channel;
- // TODO: Formatted names
///
- public override string? Name => Channel.Name;
+ public override string? Name => Channel.Name ?? _localizationService.CommaList(Recipients.Select(x => x.User.Username).ToArray());
- public string IconUrl => $"https://cdn.discordapp.com/channel-icons/{Channel.Id}/{DirectChannel.Icon}.png";
+ ///
+ /// Gets the icon url of the group channel.
+ ///
+ public string? IconUrl => GroupChannel.Icon is null ? null : $"https://cdn.discordapp.com/channel-icons/{Channel.Id}/{GroupChannel.Icon}.png";
///
/// Gets the recipients of the group channel as a array.
///
public BindableUser[] Recipients { get; }
+
+ ///
+ /// Gets the number of members in the group channel.
+ ///
+ public int MemberCount => Recipients.Length + 1;
}
}
diff --git a/src/Quarrel.ViewModels/Services/Discord/DiscordService.Methods.cs b/src/Quarrel.ViewModels/Services/Discord/DiscordService.Methods.cs
index 221be01a0..fcbc24b97 100644
--- a/src/Quarrel.ViewModels/Services/Discord/DiscordService.Methods.cs
+++ b/src/Quarrel.ViewModels/Services/Discord/DiscordService.Methods.cs
@@ -134,7 +134,7 @@ public async Task GetChannelMessagesAsync(IBindableMessageCha
category = categories[nestedChannel.CategoryId.Value];
}
- channel = BindableGuildChannel.Create(this, _dispatcherService, nestedChannel, member, category);
+ channel = BindableGuildChannel.Create(this, _localizationService, _dispatcherService, nestedChannel, member, category);
if (channel is not null && (channel.Channel.Id == guild.SelectedChannelId || (selectedChannel is null && channel.IsAccessible)) &&
channel is IBindableSelectableChannel messageChannel)
@@ -156,7 +156,7 @@ public async Task GetChannelMessagesAsync(IBindableMessageCha
int i = 0;
foreach (var channel in rawChannels)
{
- channels[i] = BindablePrivateChannel.Create(this, _dispatcherService, channel);
+ channels[i] = BindablePrivateChannel.Create(this, _localizationService, _dispatcherService, channel);
if (channels[i] is IBindableSelectableChannel selectableChannel &&
selectableChannel.Id == home.SelectedChannelId)
diff --git a/src/Quarrel.ViewModels/Services/Discord/DiscordService.cs b/src/Quarrel.ViewModels/Services/Discord/DiscordService.cs
index 42dc49e52..5a94b547a 100644
--- a/src/Quarrel.ViewModels/Services/Discord/DiscordService.cs
+++ b/src/Quarrel.ViewModels/Services/Discord/DiscordService.cs
@@ -11,6 +11,7 @@
using Quarrel.Services.Analytics.Enums;
using Quarrel.Services.Analytics.Models;
using Quarrel.Services.Dispatcher;
+using Quarrel.Services.Localization;
using Quarrel.Services.Storage.Accounts.Models;
using System;
using System.Threading.Tasks;
@@ -24,15 +25,17 @@ public partial class DiscordService : IDiscordService
{
private readonly QuarrelClient _quarrelClient;
private readonly IAnalyticsService _analyticsService;
+ private readonly ILocalizationService _localizationService;
private readonly IDispatcherService _dispatcherService;
private readonly IMessenger _messenger;
///
/// Initializes a new instance of the class.
///
- public DiscordService(IAnalyticsService analyticsService, IDispatcherService dispatcherService, IMessenger messenger)
+ public DiscordService(IAnalyticsService analyticsService, ILocalizationService localizationService, IDispatcherService dispatcherService, IMessenger messenger)
{
_analyticsService = analyticsService;
+ _localizationService = localizationService;
_dispatcherService = dispatcherService;
_messenger = messenger;
_quarrelClient = new QuarrelClient();
diff --git a/src/Quarrel.ViewModels/Services/Localization/ILocalizationService.cs b/src/Quarrel.ViewModels/Services/Localization/ILocalizationService.cs
index cd303efbf..306c7bf79 100644
--- a/src/Quarrel.ViewModels/Services/Localization/ILocalizationService.cs
+++ b/src/Quarrel.ViewModels/Services/Localization/ILocalizationService.cs
@@ -22,6 +22,11 @@ public interface ILocalizationService
/// Localized if valid, otherwise returns an empty .
string this[string key, params object[] args] { get; }
+ ///
+ /// Gets a list of items as as a string with and.
+ ///
+ string CommaList(params string[] args);
+
///
/// Gets a value indicating whether or not the current language is written right to left.
///
diff --git a/src/Quarrel.ViewModels/ViewModels/CurrentUserViewModel.cs b/src/Quarrel.ViewModels/ViewModels/CurrentUserViewModel.cs
index 4518f5dd1..fafb55235 100644
--- a/src/Quarrel.ViewModels/ViewModels/CurrentUserViewModel.cs
+++ b/src/Quarrel.ViewModels/ViewModels/CurrentUserViewModel.cs
@@ -5,8 +5,10 @@
using Microsoft.Toolkit.Mvvm.Messaging;
using Quarrel.Bindables.Users;
using Quarrel.Messages;
+using Quarrel.Messages.Navigation.SubPages;
using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
+using Quarrel.ViewModels.SubPages.Settings;
namespace Quarrel.ViewModels
{
@@ -46,6 +48,7 @@ public CurrentUserViewModel(IMessenger messenger, IDiscordService discordService
[ICommand]
public void NavigateToSettings()
{
+ _messenger.Send(new NavigateToSubPageMessage(typeof(UserSettingsPageViewModel)));
}
}
}
diff --git a/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/Abstract/UserSettingsSubPageViewModel.cs b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/Abstract/UserSettingsSubPageViewModel.cs
new file mode 100644
index 000000000..dfefb04e8
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/Abstract/UserSettingsSubPageViewModel.cs
@@ -0,0 +1,21 @@
+// Quarrel © 2022
+
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+using Quarrel.Services.Localization;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract
+{
+ public abstract class UserSettingsSubPageViewModel : ObservableObject
+ {
+ protected readonly ILocalizationService _localizationService;
+
+ public UserSettingsSubPageViewModel(ILocalizationService localizationService)
+ {
+ _localizationService = localizationService;
+ }
+
+ public abstract string Glyph { get; }
+
+ public abstract string Title { get; }
+ }
+}
diff --git a/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/BehaviorPageViewModel.cs b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/BehaviorPageViewModel.cs
new file mode 100644
index 000000000..b5c62f296
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/BehaviorPageViewModel.cs
@@ -0,0 +1,23 @@
+// Quarrel © 2022
+
+using Quarrel.Services.Localization;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class BehaviorPageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string BehaviorResource = "UserSettings/Behavior";
+
+ public BehaviorPageViewModel(ILocalizationService localizationService) :
+ base(localizationService)
+ {
+ }
+
+ ///
+ public override string Glyph => "";
+
+ ///
+ public override string Title => _localizationService[BehaviorResource];
+ }
+}
diff --git a/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/ConnectionsPageViewModel.cs b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/ConnectionsPageViewModel.cs
new file mode 100644
index 000000000..5f75c5f61
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/ConnectionsPageViewModel.cs
@@ -0,0 +1,23 @@
+// Quarrel © 2022
+
+using Quarrel.Services.Localization;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class ConnectionsPageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string ConnectionsResource = "UserSettings/Connections";
+
+ public ConnectionsPageViewModel(ILocalizationService localizationService) :
+ base(localizationService)
+ {
+ }
+
+ ///
+ public override string Glyph => "";
+
+ ///
+ public override string Title => _localizationService[ConnectionsResource];
+ }
+}
diff --git a/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/DisplayPageViewModel.cs b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/DisplayPageViewModel.cs
new file mode 100644
index 000000000..b0c3f30c5
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/DisplayPageViewModel.cs
@@ -0,0 +1,23 @@
+// Quarrel © 2022
+
+using Quarrel.Services.Localization;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class DisplayPageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string ConnectionsResource = "UserSettings/Display";
+
+ public DisplayPageViewModel(ILocalizationService localizationService) :
+ base(localizationService)
+ {
+ }
+
+ ///
+ public override string Glyph => "";
+
+ ///
+ public override string Title => _localizationService[ConnectionsResource];
+ }
+}
diff --git a/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/MyAccountPageViewModel.cs b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/MyAccountPageViewModel.cs
new file mode 100644
index 000000000..cb1cf31f9
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/MyAccountPageViewModel.cs
@@ -0,0 +1,23 @@
+// Quarrel © 2022
+
+using Quarrel.Services.Localization;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class MyAccountPageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string MyAccountResource = "UserSettings/MyAccount";
+
+ public MyAccountPageViewModel(ILocalizationService localizationService) :
+ base(localizationService)
+ {
+ }
+
+ ///
+ public override string Glyph => "";
+
+ ///
+ public override string Title => _localizationService[MyAccountResource];
+ }
+}
diff --git a/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/NotificationsPageViewModel.cs b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/NotificationsPageViewModel.cs
new file mode 100644
index 000000000..064ef3271
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/NotificationsPageViewModel.cs
@@ -0,0 +1,23 @@
+// Quarrel © 2022
+
+using Quarrel.Services.Localization;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class NotificationsPageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string NotificationsResource = "UserSettings/Notifications";
+
+ public NotificationsPageViewModel(ILocalizationService localizationService) :
+ base(localizationService)
+ {
+ }
+
+ ///
+ public override string Glyph => "";
+
+ ///
+ public override string Title => _localizationService[NotificationsResource];
+ }
+}
diff --git a/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/PrivacyPageViewModel.cs b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/PrivacyPageViewModel.cs
new file mode 100644
index 000000000..e656338eb
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/PrivacyPageViewModel.cs
@@ -0,0 +1,21 @@
+// Quarrel © 2022
+
+using Quarrel.Services.Localization;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class PrivacyPageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string PrivacyResource = "UserSettings/Privacy";
+
+ public PrivacyPageViewModel(ILocalizationService localizationService) :
+ base(localizationService)
+ {
+ }
+
+ public override string Glyph => "";
+
+ public override string Title => _localizationService[PrivacyResource];
+ }
+}
diff --git a/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/VoicePageViewModel.cs b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/VoicePageViewModel.cs
new file mode 100644
index 000000000..2097b0d4c
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/VoicePageViewModel.cs
@@ -0,0 +1,23 @@
+// Quarrel © 2022
+
+using Quarrel.Services.Localization;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class VoicePageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string VoiceResource = "UserSettings/Voice";
+
+ public VoicePageViewModel(ILocalizationService localizationService) :
+ base(localizationService)
+ {
+ }
+
+ ///
+ public override string Glyph => "";
+
+ ///
+ public override string Title => _localizationService[VoiceResource];
+ }
+}
diff --git a/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/UserSettingsPageViewModel.cs b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/UserSettingsPageViewModel.cs
new file mode 100644
index 000000000..857d171ad
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/UserSettingsPageViewModel.cs
@@ -0,0 +1,39 @@
+// Quarrel © 2022
+
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+using Quarrel.Services.Localization;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+using System.Collections.ObjectModel;
+
+namespace Quarrel.ViewModels.SubPages.Settings
+{
+ public class UserSettingsPageViewModel : ObservableObject
+ {
+ private readonly ILocalizationService _localizationService;
+
+ private UserSettingsSubPageViewModel _selectedSubPage;
+
+ public UserSettingsPageViewModel(ILocalizationService localizationService)
+ {
+ _localizationService = localizationService;
+
+ Pages = new ObservableCollection();
+ Pages.Add(new MyAccountPageViewModel(_localizationService));
+ Pages.Add(new PrivacyPageViewModel(_localizationService));
+ Pages.Add(new ConnectionsPageViewModel(_localizationService));
+ Pages.Add(new DisplayPageViewModel(_localizationService));
+ Pages.Add(new BehaviorPageViewModel(_localizationService));
+ Pages.Add(new NotificationsPageViewModel(_localizationService));
+ Pages.Add(new VoicePageViewModel(_localizationService));
+ }
+
+ public UserSettingsSubPageViewModel SelectedSubPage
+ {
+ get => _selectedSubPage;
+ set => SetProperty(ref _selectedSubPage, value);
+ }
+
+ public ObservableCollection Pages { get; }
+ }
+}
diff --git a/src/Quarrel/App.Services.cs b/src/Quarrel/App.Services.cs
index 3250ed46c..24fb2bf30 100644
--- a/src/Quarrel/App.Services.cs
+++ b/src/Quarrel/App.Services.cs
@@ -19,6 +19,7 @@
using Quarrel.ViewModels.SubPages.DiscordStatus;
using Quarrel.ViewModels.SubPages.Host;
using Quarrel.ViewModels.SubPages.Meta;
+using Quarrel.ViewModels.SubPages.Settings;
using System;
using Windows.Storage;
@@ -63,6 +64,7 @@ private IServiceProvider ConfigureServices()
services.AddTransient();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
#if DEV
ApplyDitryOverrides(services);
diff --git a/src/Quarrel/Controls/Shell/Panels/Channels/CurrentUserButton.xaml b/src/Quarrel/Controls/Shell/Panels/Channels/CurrentUserButton.xaml
index 5784ffb77..fa23b57c6 100644
--- a/src/Quarrel/Controls/Shell/Panels/Channels/CurrentUserButton.xaml
+++ b/src/Quarrel/Controls/Shell/Panels/Channels/CurrentUserButton.xaml
@@ -85,10 +85,10 @@