diff --git a/src/API/Discord.API.Status/Models/AffectedComponent.cs b/src/API/Discord.API.Status/Models/AffectedComponent.cs
index db3e3ee3e..21fcc2cd8 100644
--- a/src/API/Discord.API.Status/Models/AffectedComponent.cs
+++ b/src/API/Discord.API.Status/Models/AffectedComponent.cs
@@ -7,17 +7,32 @@
namespace Discord.API.Status.Models
{
+ ///
+ /// A component that is affected by an issue.
+ ///
public class AffectedComponent
{
+ ///
+ /// Gets the code of the issue that altered the component status.
+ ///
[JsonPropertyName("code")]
public string Code { get; set; }
+ ///
+ /// Gets the name of the comonent.
+ ///
[JsonPropertyName("name")]
public string Name { get; set; }
+ ///
+ /// Gets the status of the component before the issue.
+ ///
[JsonPropertyName("old_status")]
public string OldStatus { get; set; }
+ ///
+ /// Gets the status of the component with the issue.
+ ///
[JsonPropertyName("new_status")]
public string NewStatus { get; set; }
}
diff --git a/src/API/Discord.API.Status/Models/AllMetrics.cs b/src/API/Discord.API.Status/Models/AllMetrics.cs
index 0e6824d39..e87474a58 100644
--- a/src/API/Discord.API.Status/Models/AllMetrics.cs
+++ b/src/API/Discord.API.Status/Models/AllMetrics.cs
@@ -7,14 +7,26 @@
namespace Discord.API.Status.Models
{
+ ///
+ /// The set of all response time metrics over a period.
+ ///
public class AllMetrics
{
+ ///
+ /// Gets the peroid of time the metrics cover.
+ ///
[JsonPropertyName("period")]
public Period Period { get; set; }
+ ///
+ /// Gets the set of individual response time elements.
+ ///
[JsonPropertyName("metrics")]
public MetricElement[] Metrics { get; set; }
+ ///
+ /// Gets the summary of the response time.
+ ///
[JsonPropertyName("summary")]
public Summary Summary { get; set; }
}
diff --git a/src/API/Discord.API.Status/Models/Component.cs b/src/API/Discord.API.Status/Models/Component.cs
index c468c4c7b..75b730c2b 100644
--- a/src/API/Discord.API.Status/Models/Component.cs
+++ b/src/API/Discord.API.Status/Models/Component.cs
@@ -8,38 +8,74 @@
namespace Discord.API.Status.Models
{
+ ///
+ /// A component status of the Discord API.
+ ///
public partial class Component
{
+ ///
+ /// Gets the status of the component.
+ ///
[JsonPropertyName("status")]
public string Status { get; set; }
+ ///
+ /// Gets the name of the component.
+ ///
[JsonPropertyName("name")]
public string Name { get; set; }
+ ///
+ /// Gets the time the component was created.
+ ///
[JsonPropertyName("created_at")]
public DateTimeOffset CreatedAt { get; set; }
+ ///
+ /// Gets the time the component status was last updated.
+ ///
[JsonPropertyName("updated_at")]
public DateTimeOffset UpdatedAt { get; set; }
+ ///
+ /// Gets the ordering position of the component.
+ ///
[JsonPropertyName("position")]
public long Position { get; set; }
+ ///
+ /// Gets the description of the component.
+ ///
[JsonPropertyName("description")]
public string? Description { get; set; }
+ ///
+ /// Gets a value indicating whether or not the component is a showcase.
+ ///
[JsonPropertyName("showcase")]
public bool Showcase { get; set; }
+ ///
+ /// Gets the id of the component.
+ ///
[JsonPropertyName("id")]
public string Id { get; set; }
+ ///
+ /// Gets the page id of the component.
+ ///
[JsonPropertyName("page_id")]
public string PageId { get; set; }
+ ///
+ /// Gets the group id of the component.
+ ///
[JsonPropertyName("group_id")]
public object GroupId { get; set; }
+ ///
+ /// Gets a list of child components.
+ ///
[JsonPropertyName("components")]
public string[]? Components { get; set; }
}
diff --git a/src/API/Discord.API.Status/Models/Datum.cs b/src/API/Discord.API.Status/Models/Datum.cs
index f63271af8..2ff08f822 100644
--- a/src/API/Discord.API.Status/Models/Datum.cs
+++ b/src/API/Discord.API.Status/Models/Datum.cs
@@ -4,11 +4,20 @@
namespace Discord.API.Status.Models
{
+ ///
+ /// A response time datum.
+ ///
public partial class Datum
{
+ ///
+ /// Gets the timestamp represented.
+ ///
[JsonPropertyName("timestamp")]
public long Timestamp { get; set; }
+ ///
+ /// Gets the average response time during this time.
+ ///
[JsonPropertyName("value")]
public ushort Value { get; set; }
}
diff --git a/src/API/Discord.API.Status/Models/Incident.cs b/src/API/Discord.API.Status/Models/Incident.cs
index 44f4d1017..e9b7f57e0 100644
--- a/src/API/Discord.API.Status/Models/Incident.cs
+++ b/src/API/Discord.API.Status/Models/Incident.cs
@@ -8,77 +8,152 @@
namespace Discord.API.Status.Models
{
+ ///
+ /// An incident in the Discord API.
+ ///
public partial class Incident
{
+ ///
+ /// Gets the name of the incident.
+ ///
[JsonPropertyName("name")]
public string Name { get; set; }
+ ///
+ /// Gets the status of the api.
+ ///
[JsonPropertyName("status")]
public string Status { get; set; }
+ ///
+ /// Gets the time the incident began.
+ ///
[JsonPropertyName("created_at")]
public DateTimeOffset? CreatedAt { get; set; }
+ ///
+ /// Gets the time of the last incident update.
+ ///
[JsonPropertyName("updated_at")]
public DateTimeOffset? UpdatedAt { get; set; }
+ ///
+ /// Gets the time monitoring began.
+ ///
[JsonPropertyName("monitoring_at")]
public DateTimeOffset? MonitoringAt { get; set; }
+ ///
+ /// Gets the time the incident was resolved at.
+ ///
[JsonPropertyName("resolved_at")]
public DateTimeOffset? ResolvedAt { get; set; }
+ ///
+ /// Gets the impact of the incident.
+ ///
[JsonPropertyName("impact")]
public string Impact { get; set; }
+ ///
+ /// Gets the short link url to the incident.
+ ///
[JsonPropertyName("shortlink")]
public string Shortlink { get; set; }
+ ///
+ /// Gets a value indicating whether or not the post mortem of the incident is ignored.
+ ///
[JsonPropertyName("postmortem_ignored")]
public bool PostmortemIgnored { get; set; }
+ ///
+ /// Gets the post mortem of the incident.
+ ///
[JsonPropertyName("postmortem_body")]
public object PostmortemBody { get; set; }
+ ///
+ /// Gets the time the post mortem body was last updated.
+ ///
[JsonPropertyName("postmortem_body_last_updated_at")]
public object PostmortemBodyLastUpdatedAt { get; set; }
+ ///
+ /// Gets the time when the post mortem was published.
+ ///
[JsonPropertyName("postmortem_published_at")]
public object PostmortemPublishedAt { get; set; }
+ ///
+ /// Gets a value indicating whether or not post mortem subscribers are notified.
+ ///
[JsonPropertyName("postmortem_notified_subscribers")]
public bool PostmortemNotifiedSubscribers { get; set; }
+ ///
+ /// Gets a value indicating whether or not the post mortem was posted on Twitter.
+ ///
[JsonPropertyName("postmortem_notified_twitter")]
public bool PostmortemNotifiedTwitter { get; set; }
+ ///
+ /// TODO: Investigate.
+ ///
[JsonPropertyName("scheduled_for")]
public object ScheduledFor { get; set; }
+ ///
+ /// TODO: Investigate.
+ ///
[JsonPropertyName("scheduled_until")]
public object ScheduledUntil { get; set; }
+ ///
+ /// TODO: Investigate.
+ ///
[JsonPropertyName("scheduled_remind_prior")]
public bool ScheduledRemindPrior { get; set; }
+ ///
+ /// TODO: Investigate.
+ ///
[JsonPropertyName("scheduled_reminded_at")]
public object ScheduledRemindedAt { get; set; }
+ ///
+ /// TODO: Investigate.
+ ///
[JsonPropertyName("impact_override")]
public string ImpactOverride { get; set; }
+ ///
+ /// TODO: Investigate.
+ ///
[JsonPropertyName("scheduled_auto_in_progress")]
public bool ScheduledAutoInProgress { get; set; }
+ ///
+ /// Gets a value indicating whether or not the incident is scheduled for auto complete.
+ ///
[JsonPropertyName("scheduled_auto_completed")]
public bool ScheduledAutoCompleted { get; set; }
+ ///
+ /// Gets the incident id.
+ ///
[JsonPropertyName("id")]
public string Id { get; set; }
+ ///
+ /// Gets the page id for the incident.
+ ///
[JsonPropertyName("page_id")]
public string PageId { get; set; }
+ ///
+ /// Gets a list of updates to the incident.
+ ///
[JsonPropertyName("incident_updates")]
public IncidentUpdate[] IncidentUpdates { get; set; }
}
diff --git a/src/API/Discord.API.Status/Models/Index.cs b/src/API/Discord.API.Status/Models/Index.cs
index 61c732e69..7d0274a8f 100644
--- a/src/API/Discord.API.Status/Models/Index.cs
+++ b/src/API/Discord.API.Status/Models/Index.cs
@@ -7,17 +7,32 @@
namespace Discord.API.Status.Models
{
+ ///
+ /// An index of the discord api status.
+ ///
public class Index
{
+ ///
+ /// Gets the index page.
+ ///
[JsonPropertyName("page")]
public Page Page { get; set; }
+ ///
+ /// Gets the status for the index.
+ ///
[JsonPropertyName("status")]
public StatusClass Status { get; set; }
+ ///
+ /// Gets the component statuses for the index.
+ ///
[JsonPropertyName("components")]
public Component[] Components { get; set; }
+ ///
+ /// Gets the index incidents.
+ ///
[JsonPropertyName("incidents")]
public Incident[] Incidents { get; set; }
}
diff --git a/src/API/Discord.API.Status/Models/Period.cs b/src/API/Discord.API.Status/Models/Period.cs
index 4a4dcbee2..45c5a2985 100644
--- a/src/API/Discord.API.Status/Models/Period.cs
+++ b/src/API/Discord.API.Status/Models/Period.cs
@@ -7,14 +7,26 @@
namespace Discord.API.Status.Models
{
+ ///
+ /// The period of time a metrics set covers.
+ ///
public partial class Period
{
+ ///
+ /// Gets the number of metrics in the peroid.
+ ///
[JsonPropertyName("count")]
public long Count { get; set; }
+ ///
+ /// Gets the interval of time between metric.
+ ///
[JsonPropertyName("interval")]
public long Interval { get; set; }
+ ///
+ /// Gets the interval identifier.
+ ///
[JsonPropertyName("identifier")]
public string Identifier { get; set; }
}
diff --git a/src/API/Discord.API/Gateways/Models/Handshake/Ready.cs b/src/API/Discord.API/Gateways/Models/Handshake/Ready.cs
index ffc0da312..4e2a38847 100644
--- a/src/API/Discord.API/Gateways/Models/Handshake/Ready.cs
+++ b/src/API/Discord.API/Gateways/Models/Handshake/Ready.cs
@@ -28,6 +28,9 @@ internal class Ready
[JsonPropertyName("guilds")]
public JsonGuild[] Guilds { get; set; }
+ [JsonPropertyName("private_channels")]
+ public JsonChannel[] PrivateChannels { get; set; }
+
[JsonPropertyName("session_id")]
public string SessionId { get; set; }
diff --git a/src/API/Discord.API/Models/Enums/Guilds/ExplicitContentFilterLevel.cs b/src/API/Discord.API/Models/Enums/Guilds/ExplicitContentFilterLevel.cs
deleted file mode 100644
index 22a4f3cc2..000000000
--- a/src/API/Discord.API/Models/Enums/Guilds/ExplicitContentFilterLevel.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Quarrel © 2022
-
-namespace Discord.API.Models.Enums.Guilds
-{
- ///
- /// An enum representing the content filter level for a guild.
- ///
- public enum ExplicitContentFilterLevel
- {
- ///
- /// No explicit content filtering.
- ///
- Disabled = 0,
-
- ///
- /// Filter content members without roles.
- ///
- MembersWithoutRoles = 1,
-
- ///
- /// Filters content for all members.
- ///
- AllMembers = 2
- }
-}
diff --git a/src/API/Discord.API/Models/Enums/Settings/ExplicitContentFilterLevel.cs b/src/API/Discord.API/Models/Enums/Settings/ExplicitContentFilterLevel.cs
new file mode 100644
index 000000000..e5c6f5ef5
--- /dev/null
+++ b/src/API/Discord.API/Models/Enums/Settings/ExplicitContentFilterLevel.cs
@@ -0,0 +1,25 @@
+// Quarrel © 2022
+
+namespace Discord.API.Models.Enums.Settings
+{
+ ///
+ /// The content filter level.
+ ///
+ public enum ExplicitContentFilterLevel : int
+ {
+ ///
+ /// Filter content from nobody.
+ ///
+ None,
+
+ ///
+ /// Filter content not from my friends
+ ///
+ Public,
+
+ ///
+ /// Filter content from everyone.
+ ///
+ All,
+ }
+}
diff --git a/src/API/Discord.API/Models/Json/Channels/JsonChannel.cs b/src/API/Discord.API/Models/Json/Channels/JsonChannel.cs
index f5cee2a30..3da146f54 100644
--- a/src/API/Discord.API/Models/Json/Channels/JsonChannel.cs
+++ b/src/API/Discord.API/Models/Json/Channels/JsonChannel.cs
@@ -68,10 +68,6 @@ internal class JsonChannel
[JsonPropertyName("rtc_region")]
public string? RTCRegion { get; set; }
- // Direct
- [JsonPropertyName("recipient")]
- public JsonUser? Recipient { get; set; }
-
// Group
[JsonPropertyName("icon")]
public string? Icon { get; set; }
diff --git a/src/API/Discord.API/Models/Json/Guilds/JsonGuild.cs b/src/API/Discord.API/Models/Json/Guilds/JsonGuild.cs
index 18c07ba6b..de091b7f7 100644
--- a/src/API/Discord.API/Models/Json/Guilds/JsonGuild.cs
+++ b/src/API/Discord.API/Models/Json/Guilds/JsonGuild.cs
@@ -1,6 +1,7 @@
// Quarrel © 2022
using Discord.API.Models.Enums.Guilds;
+using Discord.API.Models.Enums.Settings;
using Discord.API.Models.Json.Channels;
using Discord.API.Models.Json.Emojis;
using Discord.API.Models.Json.Roles;
diff --git a/src/API/Discord.API/Models/Json/Messages/JsonCall.cs b/src/API/Discord.API/Models/Json/Messages/JsonCall.cs
new file mode 100644
index 000000000..ee98278ea
--- /dev/null
+++ b/src/API/Discord.API/Models/Json/Messages/JsonCall.cs
@@ -0,0 +1,19 @@
+// Quarrel © 2022
+
+using System;
+using System.Text.Json.Serialization;
+
+// JSON models don't need to respect standard nullable rules.
+#pragma warning disable CS8618
+
+namespace Discord.API.Models.Json.Messages
+{
+ internal class JsonCall
+ {
+ [JsonPropertyName("ended_timestamp")]
+ public DateTimeOffset EndedTimestamp { get; set; }
+
+ [JsonPropertyName("participants"), JsonNumberHandling(Constants.ReadWriteAsString)]
+ public ulong[] Participants { get; set; }
+ }
+}
diff --git a/src/API/Discord.API/Models/Json/Messages/JsonChannelMention.cs b/src/API/Discord.API/Models/Json/Messages/JsonChannelMention.cs
new file mode 100644
index 000000000..55af9da3b
--- /dev/null
+++ b/src/API/Discord.API/Models/Json/Messages/JsonChannelMention.cs
@@ -0,0 +1,25 @@
+// Quarrel © 2022
+
+using Discord.API.Models.Enums.Channels;
+using System.Text.Json.Serialization;
+
+// JSON models don't need to respect standard nullable rules.
+#pragma warning disable CS8618
+
+namespace Discord.API.Models.Json.Messages
+{
+ internal class JsonChannelMention
+ {
+ [JsonPropertyName("id")]
+ public ulong Id { get; set; }
+
+ [JsonPropertyName("guild_id")]
+ public ulong GuildId { get; set; }
+
+ [JsonPropertyName("type")]
+ public ChannelType ChannelType { get; set; }
+
+ [JsonPropertyName("name")]
+ public string Name { get; set; }
+ }
+}
diff --git a/src/API/Discord.API/Models/Json/Messages/JsonMessage.cs b/src/API/Discord.API/Models/Json/Messages/JsonMessage.cs
index b5c99be07..820a9892e 100644
--- a/src/API/Discord.API/Models/Json/Messages/JsonMessage.cs
+++ b/src/API/Discord.API/Models/Json/Messages/JsonMessage.cs
@@ -1,9 +1,9 @@
// Quarrel © 2022
+using Discord.API.Models.Enums.Messages;
using Discord.API.Models.Json.Messages.Embeds;
using Discord.API.Models.Json.Reactions;
using Discord.API.Models.Json.Users;
-using Discord.API.Models.Enums.Messages;
using System;
using System.Text.Json.Serialization;
@@ -32,6 +32,9 @@ internal class JsonMessage
[JsonPropertyName("author")]
public JsonUser? Author { get; set; }
+ [JsonPropertyName("call")]
+ public JsonCall? Call { get; set; }
+
[JsonPropertyName("member")]
public JsonGuildMember? Member { get; set; }
@@ -56,6 +59,9 @@ internal class JsonMessage
[JsonPropertyName("mention_roles"), JsonNumberHandling(Constants.ReadWriteAsString)]
public ulong[]? RoleMentions { get; set; }
+ [JsonPropertyName("mention_channels")]
+ public JsonChannelMention[]? ChannelMentions { get; set; }
+
[JsonPropertyName("attachments")]
public JsonAttachment[]? Attachments { get; set; }
diff --git a/src/API/Discord.API/Models/Json/Settings/JsonUserSettings.cs b/src/API/Discord.API/Models/Json/Settings/JsonUserSettings.cs
index 41a1301ac..2d1107e5b 100644
--- a/src/API/Discord.API/Models/Json/Settings/JsonUserSettings.cs
+++ b/src/API/Discord.API/Models/Json/Settings/JsonUserSettings.cs
@@ -1,5 +1,6 @@
// Quarrel © 2022
+using Discord.API.Models.Enums.Settings;
using System.Text.Json.Serialization;
// JSON models don't need to respect standard nullable rules.
@@ -48,5 +49,7 @@ internal class JsonUserSettings
[JsonPropertyName("guild_folders")]
public JsonGuildFolder[] GuildFolders { get; set; }
+ [JsonPropertyName("explicit_content_filter")]
+ public ExplicitContentFilterLevel ExplicitContentFilter { get; set; }
}
}
diff --git a/src/API/Patreon.API/Rest/PatreonRestFactory.cs b/src/API/Patreon.API/Rest/PatreonRestFactory.cs
index 50248f671..700d41ca4 100644
--- a/src/API/Patreon.API/Rest/PatreonRestFactory.cs
+++ b/src/API/Patreon.API/Rest/PatreonRestFactory.cs
@@ -17,7 +17,5 @@ public PatreonRestFactory(string token)
{
_token = token;
}
-
-
}
}
diff --git a/src/Quarrel.Client/Events/QuarrelClient.Events.Ready.cs b/src/Quarrel.Client/Events/QuarrelClient.Events.Ready.cs
index d7a285a63..2a1337c80 100644
--- a/src/Quarrel.Client/Events/QuarrelClient.Events.Ready.cs
+++ b/src/Quarrel.Client/Events/QuarrelClient.Events.Ready.cs
@@ -1,9 +1,7 @@
// Quarrel © 2022
using CommunityToolkit.Diagnostics;
-using Discord.API.Gateways;
using Discord.API.Gateways.Models.Handshake;
-using Quarrel.Client.Models.Users;
namespace Quarrel.Client
{
@@ -22,6 +20,11 @@ private void OnReady(Ready ready)
AddGuild(guild);
}
+ foreach (var channel in ready.PrivateChannels)
+ {
+ AddChannel(channel);
+ }
+
foreach (var readState in ready.ReadStates)
{
AddReadState(readState);
@@ -39,7 +42,7 @@ private void OnReady(Ready ready)
UpdateSettings(ready.Settings);
- Guard.IsNotNull(_selfUser, nameof(Client.QuarrelClient._selfUser));
+ Guard.IsNotNull(_selfUser, nameof(_selfUser));
LoggedIn?.Invoke(this, _selfUser);
}
diff --git a/src/Quarrel.Client/Models/Channels/Abstract/PrivateChannel.cs b/src/Quarrel.Client/Models/Channels/Abstract/PrivateChannel.cs
new file mode 100644
index 000000000..f28557d5b
--- /dev/null
+++ b/src/Quarrel.Client/Models/Channels/Abstract/PrivateChannel.cs
@@ -0,0 +1,53 @@
+// Quarrel © 2022
+
+using Discord.API.Models.Json.Channels;
+using Quarrel.Client.Models.Channels.Interfaces;
+
+namespace Quarrel.Client.Models.Channels.Abstract
+{
+ ///
+ /// The base class for private channels.
+ ///
+ public abstract class PrivateChannel : Channel, IPrivateChannel
+ {
+ internal PrivateChannel(JsonChannel restChannel, QuarrelClient context) :
+ base(restChannel, context)
+ {
+ LastMessageId = restChannel.LastMessageId;
+ RTCRegion = restChannel.RTCRegion;
+ }
+
+ ///
+ public int? MentionCount { get; private set; }
+
+ ///
+ public ulong? LastMessageId { get; private set; }
+
+ ///
+ public ulong? LastReadMessageId { get; private set; }
+
+ ///
+ public string? RTCRegion { get; private set; }
+
+ ///
+ public bool IsUnread => LastMessageId > LastReadMessageId;
+
+ int? IMessageChannel.MentionCount
+ {
+ get => MentionCount;
+ set => MentionCount = value;
+ }
+
+ ulong? IMessageChannel.LastMessageId
+ {
+ get => LastMessageId;
+ set => LastMessageId = value;
+ }
+
+ ulong? IMessageChannel.LastReadMessageId
+ {
+ get => LastReadMessageId;
+ set => LastReadMessageId = value;
+ }
+ }
+}
diff --git a/src/Quarrel.Client/Models/Channels/DirectChannel.cs b/src/Quarrel.Client/Models/Channels/DirectChannel.cs
index ce14ba276..fbf140e12 100644
--- a/src/Quarrel.Client/Models/Channels/DirectChannel.cs
+++ b/src/Quarrel.Client/Models/Channels/DirectChannel.cs
@@ -2,6 +2,7 @@
using CommunityToolkit.Diagnostics;
using Discord.API.Models.Json.Channels;
+using Discord.API.Models.Json.Users;
using Quarrel.Client.Models.Channels.Abstract;
using Quarrel.Client.Models.Channels.Interfaces;
using Quarrel.Client.Models.Users;
@@ -11,52 +12,18 @@ namespace Quarrel.Client.Models.Channels
///
/// A direct message channel managed by a .
///
- public class DirectChannel : Channel, IDirectChannel
+ public class DirectChannel : PrivateChannel, IDirectChannel
{
- internal DirectChannel(JsonChannel restChannel, QuarrelClient context) : base(restChannel, context)
- {
- Guard.IsNotNull(restChannel.Recipient, nameof(restChannel.Recipient));
-
- RecipientId = restChannel.Recipient.Id;
- LastMessageId = restChannel.LastMessageId;
- RTCRegion = restChannel.RTCRegion;
- }
-
- ///
- public ulong RecipientId { get; private set; }
-
- ///
- public int? MentionCount { get; private set; }
-
- ///
- public ulong? LastMessageId { get; private set; }
-
- ///
- public ulong? LastReadMessageId { get; private set; }
-
- ///
- public bool IsUnread => LastMessageId > LastReadMessageId;
-
- int? IMessageChannel.MentionCount
+ internal DirectChannel(JsonChannel restChannel, QuarrelClient context) :
+ base(restChannel, context)
{
- get => MentionCount;
- set => MentionCount = value;
- }
+ Guard.IsNotNull(restChannel.Recipients, nameof(restChannel.Recipients));
- ulong? IMessageChannel.LastMessageId
- {
- get => LastMessageId;
- set => LastMessageId = value;
- }
-
- ulong? IMessageChannel.LastReadMessageId
- {
- get => LastReadMessageId;
- set => LastReadMessageId = value;
+ RecipientId = restChannel.Recipients[0].Id;
}
///
- public string? RTCRegion { get; private set; }
+ public ulong RecipientId { get; private set; }
///
/// Gets the recipient of the direct message channel.
@@ -73,16 +40,21 @@ internal override void PrivateUpdateFromJsonChannel(JsonChannel jsonChannel)
{
base.PrivateUpdateFromJsonChannel(jsonChannel);
- if (jsonChannel.Recipient is not null)
+ if (jsonChannel.Recipients is not null)
{
- Context.AddUser(jsonChannel.Recipient);
+ Context.AddUser(jsonChannel.Recipients[0]);
}
}
internal override JsonChannel ToJsonChannel()
{
JsonChannel restChannel = base.ToJsonChannel();
- restChannel.Recipient = Context.GetUserInternal(RecipientId)?.ToRestUser();
+ var recipient = Context.GetUserInternal(RecipientId)?.ToRestUser();
+ if (recipient is not null)
+ {
+ restChannel.Recipients = new JsonUser[] { recipient };
+ }
+
return restChannel;
}
}
diff --git a/src/Quarrel.Client/Models/Channels/GroupChannel.cs b/src/Quarrel.Client/Models/Channels/GroupChannel.cs
index 10eff8381..222293e42 100644
--- a/src/Quarrel.Client/Models/Channels/GroupChannel.cs
+++ b/src/Quarrel.Client/Models/Channels/GroupChannel.cs
@@ -13,7 +13,7 @@ namespace Quarrel.Client.Models.Channels
///
/// A group dm channel managed by a .
///
- public class GroupChannel : Channel, IGroupChannel
+ public class GroupChannel : PrivateChannel, IGroupChannel
{
internal GroupChannel(JsonChannel restChannel, QuarrelClient context) :
base(restChannel, context)
@@ -23,51 +23,20 @@ internal GroupChannel(JsonChannel restChannel, QuarrelClient context) :
OwnerId = restChannel.OwnerId.Value;
- RTCRegion = restChannel.RTCRegion;
Recipients = restChannel.Recipients.Select(x => new User(x, context)).ToArray();
- LastMessageId = restChannel.LastMessageId;
+ Icon = restChannel.Icon;
}
///
public ulong OwnerId { get; private set; }
- ///
- public string? RTCRegion { get; private set; }
-
///
public User[] Recipients { get; private set; }
- IUser[] IGroupChannel.Recipients => Recipients;
-
- ///
- public int? MentionCount { get; internal set; }
-
- ///
- public ulong? LastMessageId { get; internal set; }
-
- ///
- public ulong? LastReadMessageId { get; internal set; }
-
///
- public bool IsUnread => LastMessageId > LastReadMessageId;
+ public string? Icon { get; private set; }
- int? IMessageChannel.MentionCount
- {
- get => MentionCount;
- set => MentionCount = value;
- }
-
- ulong? IMessageChannel.LastMessageId
- {
- get => LastMessageId;
- set => LastMessageId = value;
- }
-
- ulong? IMessageChannel.LastReadMessageId
- {
- get => LastReadMessageId;
- set => LastReadMessageId = value;
- }
+ IUser[] IGroupChannel.Recipients => Recipients;
internal override JsonChannel ToJsonChannel()
{
diff --git a/src/Quarrel.Client/Models/Channels/Interfaces/IAudioChannel.cs b/src/Quarrel.Client/Models/Channels/Interfaces/IAudioChannel.cs
index ae0640e4b..aa73b7fed 100644
--- a/src/Quarrel.Client/Models/Channels/Interfaces/IAudioChannel.cs
+++ b/src/Quarrel.Client/Models/Channels/Interfaces/IAudioChannel.cs
@@ -5,7 +5,7 @@ namespace Quarrel.Client.Models.Channels.Interfaces
///
/// An interface for channels voice channels or channels with calling.
///
- internal interface IAudioChannel : IChannel
+ public interface IAudioChannel : IChannel
{
///
/// The region of the voice server.
diff --git a/src/Quarrel.Client/Models/Channels/Interfaces/IDirectChannel.cs b/src/Quarrel.Client/Models/Channels/Interfaces/IDirectChannel.cs
index 86f777b5e..8c6b641fa 100644
--- a/src/Quarrel.Client/Models/Channels/Interfaces/IDirectChannel.cs
+++ b/src/Quarrel.Client/Models/Channels/Interfaces/IDirectChannel.cs
@@ -5,7 +5,7 @@ namespace Quarrel.Client.Models.Channels.Interfaces
///
/// An interface for direct message channels.
///
- internal interface IDirectChannel : IPrivateChannel, IMessageChannel, IAudioChannel
+ public interface IDirectChannel : IPrivateChannel
{
ulong RecipientId { get; }
}
diff --git a/src/Quarrel.Client/Models/Channels/Interfaces/IGroupChannel.cs b/src/Quarrel.Client/Models/Channels/Interfaces/IGroupChannel.cs
index b90eabcfa..44dd10f80 100644
--- a/src/Quarrel.Client/Models/Channels/Interfaces/IGroupChannel.cs
+++ b/src/Quarrel.Client/Models/Channels/Interfaces/IGroupChannel.cs
@@ -7,13 +7,18 @@ namespace Quarrel.Client.Models.Channels.Interfaces
///
/// An interface for group channels.
///
- internal interface IGroupChannel : IPrivateChannel, IMessageChannel, IAudioChannel
+ public interface IGroupChannel : IPrivateChannel
{
///
/// The id of the user that owns the channel.
///
ulong OwnerId { get; }
+ ///
+ /// Gets the icon id.
+ ///
+ string? Icon { get; }
+
///
/// The list of users in the channel.
///
diff --git a/src/Quarrel.Client/Models/Channels/Interfaces/IPrivateChannel.cs b/src/Quarrel.Client/Models/Channels/Interfaces/IPrivateChannel.cs
index 6dadedf55..be00ccbf5 100644
--- a/src/Quarrel.Client/Models/Channels/Interfaces/IPrivateChannel.cs
+++ b/src/Quarrel.Client/Models/Channels/Interfaces/IPrivateChannel.cs
@@ -5,7 +5,7 @@ namespace Quarrel.Client.Models.Channels.Interfaces
///
/// An interface for channels in DMs.
///
- internal interface IPrivateChannel : IChannel
+ public interface IPrivateChannel : IChannel, IMessageChannel, IAudioChannel
{
}
}
diff --git a/src/Quarrel.Client/Models/Guilds/Guild.cs b/src/Quarrel.Client/Models/Guilds/Guild.cs
index 54c4aa87a..14b30340a 100644
--- a/src/Quarrel.Client/Models/Guilds/Guild.cs
+++ b/src/Quarrel.Client/Models/Guilds/Guild.cs
@@ -2,6 +2,7 @@
using CommunityToolkit.Diagnostics;
using Discord.API.Models.Enums.Guilds;
+using Discord.API.Models.Enums.Settings;
using Discord.API.Models.Json.Guilds;
using Quarrel.Client.Models.Base;
using Quarrel.Client.Models.Channels.Abstract;
diff --git a/src/Quarrel.Client/Models/Guilds/Interfaces/IGuild.cs b/src/Quarrel.Client/Models/Guilds/Interfaces/IGuild.cs
index 6b5aa6f57..ed5ebee9f 100644
--- a/src/Quarrel.Client/Models/Guilds/Interfaces/IGuild.cs
+++ b/src/Quarrel.Client/Models/Guilds/Interfaces/IGuild.cs
@@ -1,6 +1,7 @@
// Quarrel © 2022
using Discord.API.Models.Enums.Guilds;
+using Discord.API.Models.Enums.Settings;
using Quarrel.Client.Models.Base.Interfaces;
namespace Quarrel.Client.Models.Guilds.Interfaces
diff --git a/src/Quarrel.Client/Models/Settings/Settings.cs b/src/Quarrel.Client/Models/Settings/Settings.cs
index da4e19550..f3cb10a0a 100644
--- a/src/Quarrel.Client/Models/Settings/Settings.cs
+++ b/src/Quarrel.Client/Models/Settings/Settings.cs
@@ -22,6 +22,7 @@ internal Settings(JsonUserSettings jsonUserSettings, QuarrelClient context) :
InlineAttachementMedia = jsonUserSettings.InlineAttachementMedia;
Locale = jsonUserSettings.Locale;
ShowCurrentGame = jsonUserSettings.ShowCurrentGame;
+ ContentFilterLevel = jsonUserSettings.ExplicitContentFilter;
switch (jsonUserSettings.Theme)
{
@@ -85,6 +86,11 @@ internal Settings(JsonUserSettings jsonUserSettings, QuarrelClient context) :
///
public bool ShowCurrentGame { get; private set; }
+ ///
+ /// Gets if the user's presence includes the current game.
+ ///
+ public ExplicitContentFilterLevel ContentFilterLevel { get; private set; }
+
///
/// Gets the Discord theme for the user.
///
diff --git a/src/Quarrel.Client/Models/Users/Interfaces/IUser.cs b/src/Quarrel.Client/Models/Users/Interfaces/IUser.cs
index 7e8438e3f..74b1e7783 100644
--- a/src/Quarrel.Client/Models/Users/Interfaces/IUser.cs
+++ b/src/Quarrel.Client/Models/Users/Interfaces/IUser.cs
@@ -5,7 +5,7 @@
namespace Quarrel.Client.Models.Users.Interfaces
{
- internal interface IUser : ISnowflakeItem
+ public interface IUser : ISnowflakeItem
{
///
/// Gets the user's username.
diff --git a/src/Quarrel.Client/QuarrelClient.Methods.cs b/src/Quarrel.Client/QuarrelClient.Methods.cs
index 9062faf8f..5e6b4c3db 100644
--- a/src/Quarrel.Client/QuarrelClient.Methods.cs
+++ b/src/Quarrel.Client/QuarrelClient.Methods.cs
@@ -2,12 +2,16 @@
using CommunityToolkit.Diagnostics;
using Discord.API.Models.Json.Messages;
+using Quarrel.Client.Models.Channels;
+using Quarrel.Client.Models.Channels.Interfaces;
using Quarrel.Client.Models.Guilds;
using Quarrel.Client.Models.Messages;
using Quarrel.Client.Models.Settings;
using Quarrel.Client.Models.Users;
using Refit;
using System;
+using System.Collections;
+using System.Collections.Generic;
using System.Threading.Tasks;
namespace Quarrel.Client
@@ -22,6 +26,17 @@ public partial class QuarrelClient
return CurrentUser;
}
+ public User? GetUser(ulong id)
+ {
+ _userMap.TryGetValue(id, out var user);
+ return user;
+ }
+
+ public Settings? GetSettings()
+ {
+ return _settings;
+ }
+
///
/// Gets messages in a channel.
///
@@ -106,6 +121,35 @@ public GuildFolder[] GetMyGuildFolders()
return _settings.Folders;
}
+ public IPrivateChannel[] GetPrivateChannels()
+ {
+ IPrivateChannel[] privateChannels = new IPrivateChannel[_privateChannels.Count];
+ int i = 0;
+ foreach (var channelId in _privateChannels)
+ {
+ var channel = GetChannelInternal(channelId);
+ if (channel is IPrivateChannel directChannel)
+ {
+ privateChannels[i] = directChannel;
+ i++;
+ }
+ }
+
+ Array.Resize(ref privateChannels, i);
+ Array.Sort(privateChannels, Comparer.Create((item1, item2) =>
+ {
+ if (!item2.LastMessageId.HasValue) return -1;
+ if (!item1.LastMessageId.HasValue) return 1;
+
+ long compare = (long)item2.LastMessageId.Value - (long)item1.LastMessageId.Value;
+ if (compare < 0) return -1;
+ if (compare > 0) return 1;
+ return 0;
+ }));
+
+ return privateChannels;
+ }
+
private async Task MakeRefitRequest(Func> request)
{
try
diff --git a/src/Quarrel.Client/QuarrelClient.State.cs b/src/Quarrel.Client/QuarrelClient.State.cs
index 3c6367f2c..d5fb2e71d 100644
--- a/src/Quarrel.Client/QuarrelClient.State.cs
+++ b/src/Quarrel.Client/QuarrelClient.State.cs
@@ -11,6 +11,7 @@
using Quarrel.Client.Models.Settings;
using Quarrel.Client.Models.Users;
using System.Collections.Concurrent;
+using System.Collections.Generic;
namespace Quarrel.Client
{
@@ -24,6 +25,7 @@ public partial class QuarrelClient
private readonly ConcurrentDictionary _channelMap;
private readonly ConcurrentDictionary _userMap;
private readonly ConcurrentDictionary<(ulong GuildId, ulong UserId), GuildMember> _guildsMemberMap;
+ private readonly HashSet _privateChannels;
internal SelfUser? CurrentUser => _selfUser;
@@ -109,6 +111,15 @@ internal bool AddChannel(JsonChannel jsonChannel, ulong? guildId = null)
{
guild.AddChannel(channel.Id);
}
+ else if (jsonChannel.Recipients is not null)
+ {
+ foreach (var recipient in jsonChannel.Recipients)
+ {
+ AddUser(recipient);
+ }
+
+ _privateChannels.Add(channel.Id);
+ }
return true;
}
diff --git a/src/Quarrel.Client/QuarrelClient.cs b/src/Quarrel.Client/QuarrelClient.cs
index d5a6df682..1bf434aeb 100644
--- a/src/Quarrel.Client/QuarrelClient.cs
+++ b/src/Quarrel.Client/QuarrelClient.cs
@@ -10,6 +10,7 @@
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
+using System.Collections.Generic;
namespace Quarrel.Client
{
@@ -32,6 +33,7 @@ public QuarrelClient()
_channelMap = new ConcurrentDictionary();
_userMap = new ConcurrentDictionary();
_guildsMemberMap = new ConcurrentDictionary<(ulong GuildId, ulong UserId), GuildMember>();
+ _privateChannels = new HashSet();
}
///
diff --git a/src/Quarrel.ViewModels/Bindables/Abstract/BindableItem.cs b/src/Quarrel.ViewModels/Bindables/Abstract/BindableItem.cs
index b580c4534..ea4e0ea24 100644
--- a/src/Quarrel.ViewModels/Bindables/Abstract/BindableItem.cs
+++ b/src/Quarrel.ViewModels/Bindables/Abstract/BindableItem.cs
@@ -1,6 +1,7 @@
// Quarrel © 2022
using Microsoft.Toolkit.Mvvm.ComponentModel;
+using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
namespace Quarrel.Bindables.Abstract
@@ -10,6 +11,11 @@ namespace Quarrel.Bindables.Abstract
///
public abstract class BindableItem : ObservableObject
{
+ ///
+ /// Gets the for the .
+ ///
+ protected readonly IDiscordService _discordService;
+
///
/// Gets an that can run code on the UI Thread.
///
@@ -18,8 +24,9 @@ public abstract class BindableItem : ObservableObject
///
/// Initializes a new instance of the class.
///
- public BindableItem(IDispatcherService dispatcherService)
+ public BindableItem(IDiscordService discordService, IDispatcherService dispatcherService)
{
+ _discordService = discordService;
_dispatcherService = dispatcherService;
}
}
diff --git a/src/Quarrel.ViewModels/Bindables/Abstract/SelectableItem.cs b/src/Quarrel.ViewModels/Bindables/Abstract/SelectableItem.cs
index 5f2ff193f..3a4a74ff2 100644
--- a/src/Quarrel.ViewModels/Bindables/Abstract/SelectableItem.cs
+++ b/src/Quarrel.ViewModels/Bindables/Abstract/SelectableItem.cs
@@ -1,6 +1,7 @@
// Quarrel © 2022
using Quarrel.Bindables.Interfaces;
+using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
namespace Quarrel.Bindables.Abstract
@@ -15,8 +16,8 @@ public abstract class SelectableItem : BindableItem, ISelectableItem
///
/// Initializes a new instance of the class.
///
- public SelectableItem(IDispatcherService dispatcherService) :
- base(dispatcherService)
+ public SelectableItem(IDiscordService discordService, IDispatcherService dispatcherService) :
+ base(discordService, dispatcherService)
{
}
diff --git a/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableChannel.cs b/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableChannel.cs
index 70b754012..d79596b46 100644
--- a/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableChannel.cs
+++ b/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableChannel.cs
@@ -5,7 +5,9 @@
using Quarrel.Client.Models.Channels.Abstract;
using Quarrel.Client.Models.Channels.Interfaces;
using Quarrel.Client.Models.Users;
+using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
+using Quarrel.Services.Localization;
using System;
namespace Quarrel.Bindables.Channels.Abstract
@@ -20,13 +22,18 @@ public abstract partial class BindableChannel : SelectableItem
///
/// Initializes a new instance of the class.
///
- internal BindableChannel(IDispatcherService dispatcherService, Channel channel) :
- base(dispatcherService)
+ internal BindableChannel(IDiscordService discordService, IDispatcherService dispatcherService, Channel channel) :
+ base(discordService, dispatcherService)
{
_channel = channel;
_channel.ItemUpdated += AckUpdateRoot;
}
+ ///
+ /// Gets the id of the channel.
+ ///
+ public ulong Id => Channel.Id;
+
///
/// Gets the name of the channel as displayed.
///
@@ -35,7 +42,7 @@ internal BindableChannel(IDispatcherService dispatcherService, Channel channel)
///
/// Gets a bool representing whether or not the channel is a text channel.
///
- public abstract bool IsTextChannel { get; }
+ public virtual bool IsTextChannel => true;
///
/// Gets the wrapped .
@@ -78,17 +85,29 @@ private void AckUpdateRoot(object sender, EventArgs e)
///
/// Creates a new instance of a based on the type.
///
- /// 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(IDispatcherService dispatcherService, IChannel channel, GuildMember member, 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, localizationService, dispatcherService, c),
+ _ => null
+ };
+ }
+
return channel switch
{
- GuildTextChannel c => new BindableTextChannel(dispatcherService, c, member, parent),
- VoiceChannel c => new BindableVoiceChannel(dispatcherService, c, member, parent),
- CategoryChannel c => new BindableCategoryChannel(dispatcherService, c, member),
+ GuildTextChannel c => new BindableTextChannel(discordService, dispatcherService, c, member, parent),
+ VoiceChannel c => new BindableVoiceChannel(discordService, dispatcherService, c, member, parent),
+ CategoryChannel c => new BindableCategoryChannel(discordService, dispatcherService, c, member),
_ => null
};
}
diff --git a/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableGuildChannel.cs b/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableGuildChannel.cs
index 0cead33a2..e9eb56cd3 100644
--- a/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableGuildChannel.cs
+++ b/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindableGuildChannel.cs
@@ -6,17 +6,19 @@
using Quarrel.Client.Models.Channels.Interfaces;
using Quarrel.Client.Models.Permissions;
using Quarrel.Client.Models.Users;
+using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
+using Quarrel.Services.Localization;
namespace Quarrel.Bindables.Channels.Abstract
{
///
- /// A wrapper of an that can be bound to the UI.
+ /// A wrapper of a that can be bound to the UI.
///
public abstract class BindableGuildChannel : BindableChannel
{
- internal BindableGuildChannel(IDispatcherService dispatcherService, GuildChannel channel, GuildMember selfMember, BindableCategoryChannel? parent = null) :
- base(dispatcherService, channel)
+ internal BindableGuildChannel(IDiscordService discordService, IDispatcherService dispatcherService, GuildChannel channel, GuildMember selfMember, BindableCategoryChannel? parent = null) :
+ base(discordService, dispatcherService, channel)
{
CategoryChannel = parent;
@@ -56,13 +58,15 @@ internal BindableGuildChannel(IDispatcherService dispatcherService, GuildChannel
///
/// Creates a new based on the type.
///
- /// 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(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(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
new file mode 100644
index 000000000..6d90b2077
--- /dev/null
+++ b/src/Quarrel.ViewModels/Bindables/Channels/Abstract/BindablePrivateChannel.cs
@@ -0,0 +1,36 @@
+// Quarrel © 2022
+
+using Quarrel.Bindables.Channels.Interfaces;
+using Quarrel.Client.Models.Channels.Abstract;
+using Quarrel.Client.Models.Channels.Interfaces;
+using Quarrel.Services.Discord;
+using Quarrel.Services.Dispatcher;
+using Quarrel.Services.Localization;
+
+namespace Quarrel.Bindables.Channels.Abstract
+{
+ ///
+ /// A wrapper of an that can be bound to the UI.
+ ///
+ public abstract class BindablePrivateChannel : BindableChannel, IBindableMessageChannel
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ internal BindablePrivateChannel(IDiscordService discordService, IDispatcherService dispatcherService, PrivateChannel privateChannel) :
+ base(discordService, dispatcherService, privateChannel)
+ {
+ }
+
+ ///
+ public bool IsAccessible => true;
+
+ ///
+ public IMessageChannel MessageChannel => (IMessageChannel)Channel;
+
+ public static BindablePrivateChannel? Create(IDiscordService discordService, ILocalizationService localizationService, IDispatcherService dispatcherService, IPrivateChannel channel)
+ {
+ return BindableChannel.Create(discordService, localizationService, dispatcherService, channel) as BindablePrivateChannel;
+ }
+ }
+}
diff --git a/src/Quarrel.ViewModels/Bindables/Channels/BindableCategoryChannel.cs b/src/Quarrel.ViewModels/Bindables/Channels/BindableCategoryChannel.cs
index 178dfc531..32a13f9c7 100644
--- a/src/Quarrel.ViewModels/Bindables/Channels/BindableCategoryChannel.cs
+++ b/src/Quarrel.ViewModels/Bindables/Channels/BindableCategoryChannel.cs
@@ -3,6 +3,7 @@
using Quarrel.Bindables.Channels.Abstract;
using Quarrel.Client.Models.Channels;
using Quarrel.Client.Models.Users;
+using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
namespace Quarrel.Bindables.Channels
@@ -12,8 +13,8 @@ namespace Quarrel.Bindables.Channels
///
public class BindableCategoryChannel : BindableGuildChannel
{
- internal BindableCategoryChannel(IDispatcherService dispatcherService, CategoryChannel channel, GuildMember selfMember) :
- base(dispatcherService, channel, selfMember)
+ internal BindableCategoryChannel(IDiscordService discordService, IDispatcherService dispatcherService, CategoryChannel channel, GuildMember selfMember) :
+ base(discordService, dispatcherService, channel, selfMember)
{
}
diff --git a/src/Quarrel.ViewModels/Bindables/Channels/BindableChannelGroup.cs b/src/Quarrel.ViewModels/Bindables/Channels/BindableChannelGroup.cs
index 2b33ea1aa..4552cbb2e 100644
--- a/src/Quarrel.ViewModels/Bindables/Channels/BindableChannelGroup.cs
+++ b/src/Quarrel.ViewModels/Bindables/Channels/BindableChannelGroup.cs
@@ -2,6 +2,7 @@
using Quarrel.Bindables.Abstract;
using Quarrel.Bindables.Channels.Abstract;
+using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
using System.Collections;
using System.Collections.Generic;
@@ -15,8 +16,8 @@ namespace Quarrel.Bindables.Channels
///
public class BindableChannelGroup : BindableItem, IGrouping
{
- internal BindableChannelGroup(IDispatcherService dispatcherService, BindableCategoryChannel? key) :
- base(dispatcherService)
+ internal BindableChannelGroup(IDiscordService discordService, IDispatcherService dispatcherService, BindableCategoryChannel? key) :
+ base(discordService, dispatcherService)
{
Key = key;
Children = new ObservableCollection();
diff --git a/src/Quarrel.ViewModels/Bindables/Channels/BindableDirectChannel.cs b/src/Quarrel.ViewModels/Bindables/Channels/BindableDirectChannel.cs
new file mode 100644
index 000000000..bb94019d4
--- /dev/null
+++ b/src/Quarrel.ViewModels/Bindables/Channels/BindableDirectChannel.cs
@@ -0,0 +1,38 @@
+// Quarrel © 2022
+
+using CommunityToolkit.Diagnostics;
+using Quarrel.Bindables.Channels.Abstract;
+using Quarrel.Bindables.Channels.Interfaces;
+using Quarrel.Bindables.Users;
+using Quarrel.Client.Models.Channels;
+using Quarrel.Client.Models.Channels.Interfaces;
+using Quarrel.Services.Discord;
+using Quarrel.Services.Dispatcher;
+
+namespace Quarrel.Bindables.Channels
+{
+ ///
+ /// A wrapper of an that can be bound to the UI.
+ ///
+ public class BindableDirectChannel : BindablePrivateChannel, IBindableMessageChannel
+ {
+ internal BindableDirectChannel(IDiscordService discordService, IDispatcherService dispatcherService, DirectChannel directChannel) :
+ base(discordService, dispatcherService, directChannel)
+ {
+ BindableUser? user = _discordService.GetUser(DirectChannel.RecipientId);
+ Guard.IsNotNull(user);
+ Recipient = user;
+ }
+
+ ///
+ public IDirectChannel DirectChannel => (IDirectChannel)Channel;
+
+ ///
+ public override string? Name => Recipient.User.Username;
+
+ ///
+ /// Gets the recipient of the direct messages as a .
+ ///
+ public BindableUser Recipient { get; }
+ }
+}
diff --git a/src/Quarrel.ViewModels/Bindables/Channels/BindableGroupChannel.cs b/src/Quarrel.ViewModels/Bindables/Channels/BindableGroupChannel.cs
new file mode 100644
index 000000000..2fe2394fe
--- /dev/null
+++ b/src/Quarrel.ViewModels/Bindables/Channels/BindableGroupChannel.cs
@@ -0,0 +1,61 @@
+// Quarrel © 2022
+
+using CommunityToolkit.Diagnostics;
+using Quarrel.Bindables.Channels.Abstract;
+using Quarrel.Bindables.Channels.Interfaces;
+using Quarrel.Bindables.Users;
+using Quarrel.Client.Models.Channels;
+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
+{
+ ///
+ /// A wrapper of an that can be bound to the UI.
+ ///
+ public class BindableGroupChannel : BindablePrivateChannel, IBindableMessageChannel
+ {
+ 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;
+ foreach (var recipient in groupChannel.Recipients)
+ {
+ BindableUser? user = _discordService.GetUser(recipient.Id);
+ Guard.IsNotNull(user);
+ Recipients[i] = user;
+ i++;
+ }
+ }
+
+ ///
+ public IGroupChannel GroupChannel => (IGroupChannel)Channel;
+
+ ///
+ public override string? Name => Channel.Name ?? _localizationService.CommaList(Recipients.Select(x => x.User.Username).ToArray());
+
+ ///
+ /// 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/Bindables/Channels/BindableTextChannel.cs b/src/Quarrel.ViewModels/Bindables/Channels/BindableTextChannel.cs
index c51c7e376..70b60cec7 100644
--- a/src/Quarrel.ViewModels/Bindables/Channels/BindableTextChannel.cs
+++ b/src/Quarrel.ViewModels/Bindables/Channels/BindableTextChannel.cs
@@ -5,6 +5,7 @@
using Quarrel.Client.Models.Channels;
using Quarrel.Client.Models.Channels.Interfaces;
using Quarrel.Client.Models.Users;
+using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
namespace Quarrel.Bindables.Channels
@@ -14,13 +15,10 @@ namespace Quarrel.Bindables.Channels
///
public class BindableTextChannel : BindableGuildChannel, IBindableMessageChannel
{
- internal BindableTextChannel(IDispatcherService dispatcherService, GuildTextChannel channel, GuildMember selfMember, BindableCategoryChannel? parent = null) :
- base(dispatcherService, channel, selfMember, parent)
+ internal BindableTextChannel(IDiscordService discordService, IDispatcherService dispatcherService, GuildTextChannel channel, GuildMember selfMember, BindableCategoryChannel? parent = null) :
+ base(discordService, dispatcherService, channel, selfMember, parent)
{
}
-
- ///
- public ulong Id => Channel.Id;
///
public override bool IsTextChannel => true;
diff --git a/src/Quarrel.ViewModels/Bindables/Channels/BindableVoiceChannel.cs b/src/Quarrel.ViewModels/Bindables/Channels/BindableVoiceChannel.cs
index 02ba5ce51..675240fab 100644
--- a/src/Quarrel.ViewModels/Bindables/Channels/BindableVoiceChannel.cs
+++ b/src/Quarrel.ViewModels/Bindables/Channels/BindableVoiceChannel.cs
@@ -3,6 +3,7 @@
using Quarrel.Bindables.Channels.Abstract;
using Quarrel.Client.Models.Channels;
using Quarrel.Client.Models.Users;
+using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
namespace Quarrel.Bindables.Channels
@@ -12,8 +13,8 @@ namespace Quarrel.Bindables.Channels
///
public class BindableVoiceChannel : BindableGuildChannel
{
- internal BindableVoiceChannel(IDispatcherService dispatcherService, VoiceChannel channel, GuildMember selfMember, BindableCategoryChannel? parent = null) :
- base(dispatcherService, channel, selfMember, parent)
+ internal BindableVoiceChannel(IDiscordService discordService, IDispatcherService dispatcherService, VoiceChannel channel, GuildMember selfMember, BindableCategoryChannel? parent = null) :
+ base(discordService, dispatcherService, channel, selfMember, parent)
{
}
diff --git a/src/Quarrel.ViewModels/Bindables/Guilds/BindableGuild.cs b/src/Quarrel.ViewModels/Bindables/Guilds/BindableGuild.cs
index 56534930f..823cd2933 100644
--- a/src/Quarrel.ViewModels/Bindables/Guilds/BindableGuild.cs
+++ b/src/Quarrel.ViewModels/Bindables/Guilds/BindableGuild.cs
@@ -2,35 +2,35 @@
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Quarrel.Bindables.Abstract;
+using Quarrel.Bindables.Channels;
+using Quarrel.Bindables.Channels.Interfaces;
using Quarrel.Bindables.Guilds.Interfaces;
+using Quarrel.Client.Models.Channels.Interfaces;
using Quarrel.Client.Models.Guilds;
+using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
using System;
+using System.Collections.Generic;
namespace Quarrel.Bindables.Guilds
{
///
/// A wrapper of a that can be bound to the UI.
///
- public partial class BindableGuild : SelectableItem, IBindableGuildListItem
+ public partial class BindableGuild : SelectableItem, IBindableSelectableGuildItem, IBindableGuildListItem
{
[AlsoNotifyChangeFor(nameof(IconUrl))]
[AlsoNotifyChangeFor(nameof(IconUri))]
[ObservableProperty]
private Guild _guild;
- internal BindableGuild(IDispatcherService dispatcherService, Guild guild) :
- base(dispatcherService)
+ internal BindableGuild(IDiscordService discordService, IDispatcherService dispatcherService, Guild guild) :
+ base(discordService, dispatcherService)
{
_guild = guild;
}
- ///
- /// The id of the selected channel in the guild.
- ///
- ///
- /// This is used to reopen a channel when navigating to a guild.
- ///
+ ///
public ulong? SelectedChannelId { get; set; }
///
@@ -45,5 +45,48 @@ internal BindableGuild(IDispatcherService dispatcherService, Guild guild) :
///
public string? Name => Guild.Name;
+
+ ///
+ public IEnumerable? GetGroupedChannels(out IBindableSelectableChannel? selectedChannel)
+ {
+ var channels = _discordService.GetGuildChannels(this, out selectedChannel);
+
+ var groups = new Dictionary
+ {
+ { 0, new BindableChannelGroup(_discordService, _dispatcherService, null) }
+ };
+
+ foreach (var channel in channels)
+ {
+ if (channel is BindableCategoryChannel bindableCategory)
+ {
+ groups.Add(channel.Channel.Id, new BindableChannelGroup(_discordService, _dispatcherService, bindableCategory));
+ }
+ }
+
+ foreach (var channel in channels)
+ {
+ if (channel is not null && channel is not BindableCategoryChannel)
+ {
+ ulong parentId = 0;
+ if (channel.Channel is INestedChannel nestedChannel)
+ {
+ parentId = nestedChannel.CategoryId ?? 0;
+ }
+
+ if (groups.TryGetValue(parentId, out var group))
+ {
+ group.AddChild(channel);
+ }
+ }
+ }
+
+ if (groups[0].Children.Count == 0)
+ {
+ groups.Remove(0);
+ }
+
+ return groups.Values;
+ }
}
}
diff --git a/src/Quarrel.ViewModels/Bindables/Guilds/BindableGuildFolder.cs b/src/Quarrel.ViewModels/Bindables/Guilds/BindableGuildFolder.cs
index a75fe2cc1..eb3dec06f 100644
--- a/src/Quarrel.ViewModels/Bindables/Guilds/BindableGuildFolder.cs
+++ b/src/Quarrel.ViewModels/Bindables/Guilds/BindableGuildFolder.cs
@@ -4,6 +4,7 @@
using Quarrel.Bindables.Abstract;
using Quarrel.Bindables.Guilds.Interfaces;
using Quarrel.Client.Models.Settings;
+using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
using System.Collections.ObjectModel;
@@ -17,8 +18,8 @@ public partial class BindableGuildFolder : BindableItem, IBindableGuildListItem
[ObservableProperty]
private GuildFolder _folder;
- internal BindableGuildFolder(IDispatcherService dispatcherService, GuildFolder folder) :
- base(dispatcherService)
+ internal BindableGuildFolder(IDiscordService discordService, IDispatcherService dispatcherService, GuildFolder folder) :
+ base(discordService, dispatcherService)
{
_folder = folder;
@@ -26,7 +27,7 @@ internal BindableGuildFolder(IDispatcherService dispatcherService, GuildFolder f
Children = new ObservableCollection();
foreach (var guild in guilds)
{
- Children.Add(new BindableGuild(dispatcherService, guild));
+ Children.Add(new BindableGuild(discordService, dispatcherService, guild));
}
}
diff --git a/src/Quarrel.ViewModels/Bindables/Guilds/BindableHomeItem.cs b/src/Quarrel.ViewModels/Bindables/Guilds/BindableHomeItem.cs
new file mode 100644
index 000000000..26fa074d6
--- /dev/null
+++ b/src/Quarrel.ViewModels/Bindables/Guilds/BindableHomeItem.cs
@@ -0,0 +1,53 @@
+// Quarrel © 2022
+
+using Quarrel.Bindables.Abstract;
+using Quarrel.Bindables.Channels;
+using Quarrel.Bindables.Channels.Interfaces;
+using Quarrel.Bindables.Guilds.Interfaces;
+using Quarrel.Services.Discord;
+using Quarrel.Services.Dispatcher;
+using Quarrel.Services.Localization;
+using System.Collections.Generic;
+
+namespace Quarrel.Bindables.Guilds
+{
+ ///
+ /// An artifical guild item for selecting DMs.
+ ///
+ public class BindableHomeItem : SelectableItem, IBindableSelectableGuildItem, IBindableGuildListItem
+ {
+ private const string HomeResouece = "Guilds/Home";
+ private readonly ILocalizationService _localizationService;
+
+ ///
+ /// Initializes a new isntance of the class.
+ ///
+ public BindableHomeItem(IDiscordService discordService, IDispatcherService dispatcherService, ILocalizationService localizationService) :
+ base(discordService, dispatcherService)
+ {
+ _localizationService = localizationService;
+ }
+
+ ///
+ public string? Name => _localizationService[HomeResouece];
+
+ ///
+ public ulong? SelectedChannelId { get; set; }
+
+ ///
+ public IEnumerable? GetGroupedChannels(out IBindableSelectableChannel? selected)
+ {
+ var channels = _discordService.GetPrivateChannels(this, out selected);
+ var group = new BindableChannelGroup(_discordService, _dispatcherService, null);
+ foreach (var channel in channels)
+ {
+ if (channel is not null)
+ {
+ group.AddChild(channel);
+ }
+ }
+
+ return new BindableChannelGroup[] { group };
+ }
+ }
+}
diff --git a/src/Quarrel.ViewModels/Bindables/Guilds/Interfaces/IBindableSelectableGuildItem.cs b/src/Quarrel.ViewModels/Bindables/Guilds/Interfaces/IBindableSelectableGuildItem.cs
new file mode 100644
index 000000000..fec19838d
--- /dev/null
+++ b/src/Quarrel.ViewModels/Bindables/Guilds/Interfaces/IBindableSelectableGuildItem.cs
@@ -0,0 +1,25 @@
+// Quarrel © 2022
+
+using Quarrel.Bindables.Channels;
+using Quarrel.Bindables.Channels.Interfaces;
+using Quarrel.Bindables.Interfaces;
+using System.Collections.Generic;
+
+namespace Quarrel.Bindables.Guilds.Interfaces
+{
+ ///
+ /// An interface for items that can be treated as a selected guild.
+ ///
+ public interface IBindableSelectableGuildItem : IBindableGuildListItem, ISelectableItem
+ {
+ ///
+ /// The id of the selected channel in the guild.
+ ///
+ ///
+ /// This is used to reopen a channel when navigating to a guild.
+ ///
+ ulong? SelectedChannelId { get; set; }
+
+ IEnumerable? GetGroupedChannels(out IBindableSelectableChannel? selected);
+ }
+}
diff --git a/src/Quarrel.ViewModels/Bindables/Messages/BindableMessage.cs b/src/Quarrel.ViewModels/Bindables/Messages/BindableMessage.cs
index 874bf6525..c1f81d895 100644
--- a/src/Quarrel.ViewModels/Bindables/Messages/BindableMessage.cs
+++ b/src/Quarrel.ViewModels/Bindables/Messages/BindableMessage.cs
@@ -3,6 +3,7 @@
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Quarrel.Bindables.Abstract;
using Quarrel.Client.Models.Messages;
+using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
namespace Quarrel.Bindables.Messages
@@ -18,8 +19,8 @@ public partial class BindableMessage : SelectableItem
///
/// Initializes a new instance of the class.
///
- internal BindableMessage(IDispatcherService dispatcherService, Message message) :
- base(dispatcherService)
+ internal BindableMessage(IDiscordService discordService, IDispatcherService dispatcherService, Message message) :
+ base(discordService, dispatcherService)
{
_message = message;
}
diff --git a/src/Quarrel.ViewModels/Bindables/Users/BindableSelfUser.cs b/src/Quarrel.ViewModels/Bindables/Users/BindableSelfUser.cs
index 99a385307..7edaf01ce 100644
--- a/src/Quarrel.ViewModels/Bindables/Users/BindableSelfUser.cs
+++ b/src/Quarrel.ViewModels/Bindables/Users/BindableSelfUser.cs
@@ -4,6 +4,7 @@
using Quarrel.Bindables.Abstract;
using Quarrel.Bindables.Users.Interfaces;
using Quarrel.Client.Models.Users;
+using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
using System;
@@ -23,8 +24,8 @@ public partial class BindableSelfUser : BindableItem, IBindableUser
///
/// Initializes a new instance of the class.
///
- internal BindableSelfUser(IDispatcherService dispatcherService, SelfUser selfUser) :
- base(dispatcherService)
+ internal BindableSelfUser(IDiscordService discordService, IDispatcherService dispatcherService, SelfUser selfUser) :
+ base(discordService, dispatcherService)
{
_selfUser = selfUser;
}
diff --git a/src/Quarrel.ViewModels/Bindables/Users/BindableUser.cs b/src/Quarrel.ViewModels/Bindables/Users/BindableUser.cs
index c3a8c60c9..bddcf1f2e 100644
--- a/src/Quarrel.ViewModels/Bindables/Users/BindableUser.cs
+++ b/src/Quarrel.ViewModels/Bindables/Users/BindableUser.cs
@@ -3,6 +3,7 @@
using Quarrel.Bindables.Abstract;
using Quarrel.Bindables.Users.Interfaces;
using Quarrel.Client.Models.Users;
+using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
using System;
@@ -18,8 +19,8 @@ public partial class BindableUser : BindableItem, IBindableUser
///
/// Initializes a new instance of the class.
///
- internal BindableUser(IDispatcherService dispatcherService, User user) :
- base(dispatcherService)
+ internal BindableUser(IDiscordService discordService, IDispatcherService dispatcherService, User user) :
+ base(discordService, dispatcherService)
{
_user = user;
}
diff --git a/src/Quarrel.ViewModels/Extensions/System/EnumExtensions.cs b/src/Quarrel.ViewModels/Extensions/System/EnumExtensions.cs
index af9ed6105..0cc0169a6 100644
--- a/src/Quarrel.ViewModels/Extensions/System/EnumExtensions.cs
+++ b/src/Quarrel.ViewModels/Extensions/System/EnumExtensions.cs
@@ -5,8 +5,14 @@
namespace System
{
+ ///
+ /// A static class containing extensions on enums.
+ ///
public static class EnumExtensions
{
+ ///
+ /// Gets the string value of an that has a .
+ ///
public static string GetStringValue(this Enum value)
{
Type type = value.GetType();
diff --git a/src/Quarrel.ViewModels/Services/Discord/DiscordService.Methods.cs b/src/Quarrel.ViewModels/Services/Discord/DiscordService.Methods.cs
index 144756bc7..fcbc24b97 100644
--- a/src/Quarrel.ViewModels/Services/Discord/DiscordService.Methods.cs
+++ b/src/Quarrel.ViewModels/Services/Discord/DiscordService.Methods.cs
@@ -30,9 +30,21 @@ public partial class DiscordService
return null;
}
- return new BindableSelfUser(_dispatcherService, user);
+ return new BindableSelfUser(this, _dispatcherService, user);
}
-
+
+ ///
+ public BindableUser? GetUser(ulong id)
+ {
+ var user = _quarrelClient.GetUser(id);
+ if (user is not null)
+ {
+ return new BindableUser(this, _dispatcherService, user);
+ }
+
+ return null;
+ }
+
///
public BindableGuild[] GetMyGuilds()
{
@@ -40,7 +52,7 @@ public BindableGuild[] GetMyGuilds()
BindableGuild[] guilds = new BindableGuild[rawGuilds.Length];
for (int i = 0; i < rawGuilds.Length; i++)
{
- guilds[i] = new BindableGuild(_dispatcherService, rawGuilds[i]);
+ guilds[i] = new BindableGuild(this, _dispatcherService, rawGuilds[i]);
}
return guilds;
@@ -53,7 +65,7 @@ public BindableGuildFolder[] GetMyGuildFolders()
BindableGuildFolder[] folders = new BindableGuildFolder[rawFolders.Length];
for (int i = 0; i < rawFolders.Length; i++)
{
- folders[i] = new BindableGuildFolder(_dispatcherService, rawFolders[i]);
+ folders[i] = new BindableGuildFolder(this, _dispatcherService, rawFolders[i]);
}
return folders;
@@ -67,7 +79,7 @@ public async Task GetChannelMessagesAsync(IBindableMessageCha
BindableMessage[] messages = new BindableMessage[rawMessages.Length];
for (int i = 0; i < messages.Length; i++)
{
- messages[i] = new BindableMessage(_dispatcherService, rawMessages[i]);
+ messages[i] = new BindableMessage(this, _dispatcherService, rawMessages[i]);
}
return messages;
@@ -105,7 +117,7 @@ public async Task GetChannelMessagesAsync(IBindableMessageCha
var channel = rawChannels[i];
if (channel is CategoryChannel categoryChannel)
{
- var bindableCategoryChannel = new BindableCategoryChannel(_dispatcherService, categoryChannel, member);
+ var bindableCategoryChannel = new BindableCategoryChannel(this, _dispatcherService, categoryChannel, member);
categories.Add(channel.Id, bindableCategoryChannel);
channels[i] = bindableCategoryChannel;
}
@@ -122,7 +134,7 @@ public async Task GetChannelMessagesAsync(IBindableMessageCha
category = categories[nestedChannel.CategoryId.Value];
}
- channel = BindableGuildChannel.Create(_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)
@@ -134,48 +146,28 @@ public async Task GetChannelMessagesAsync(IBindableMessageCha
return channels;
}
-
+
///
- public IEnumerable? GetGuildChannelsGrouped(BindableGuild guild, out IBindableSelectableChannel? selectedChannel)
+ public BindablePrivateChannel?[] GetPrivateChannels(BindableHomeItem home, out IBindableSelectableChannel? selectedChannel)
{
- var channels = GetGuildChannels(guild, out selectedChannel);
-
- var groups = new Dictionary
- {
- { 0, new BindableChannelGroup(_dispatcherService, null) }
- };
-
- foreach (var channel in channels)
+ selectedChannel = null;
+ IPrivateChannel[] rawChannels = _quarrelClient.GetPrivateChannels();
+ BindablePrivateChannel?[] channels = new BindablePrivateChannel[rawChannels.Length];
+ int i = 0;
+ foreach (var channel in rawChannels)
{
- if (channel is BindableCategoryChannel bindableCategory)
- {
- groups.Add(channel.Channel.Id, new BindableChannelGroup(_dispatcherService, bindableCategory));
- }
- }
+ channels[i] = BindablePrivateChannel.Create(this, _localizationService, _dispatcherService, channel);
- foreach (var channel in channels)
- {
- if (channel is not null && channel is not BindableCategoryChannel)
+ if (channels[i] is IBindableSelectableChannel selectableChannel &&
+ selectableChannel.Id == home.SelectedChannelId)
{
- ulong parentId = 0;
- if (channel.Channel is INestedChannel nestedChannel)
- {
- parentId = nestedChannel.CategoryId ?? 0;
- }
-
- if (groups.TryGetValue(parentId, out var group))
- {
- group.AddChild(channel);
- }
+ selectedChannel = selectableChannel;
}
- }
- if (groups[0].Children.Count == 0)
- {
- groups.Remove(0);
+ i++;
}
- return groups.Values;
+ return channels;
}
}
}
diff --git a/src/Quarrel.ViewModels/Services/Discord/DiscordService.cs b/src/Quarrel.ViewModels/Services/Discord/DiscordService.cs
index 57ca6d04d..5a94b547a 100644
--- a/src/Quarrel.ViewModels/Services/Discord/DiscordService.cs
+++ b/src/Quarrel.ViewModels/Services/Discord/DiscordService.cs
@@ -2,6 +2,8 @@
using CommunityToolkit.Diagnostics;
using Microsoft.Toolkit.Mvvm.Messaging;
+using Quarrel.Bindables.Channels.Abstract;
+using Quarrel.Bindables.Channels.Interfaces;
using Quarrel.Client;
using Quarrel.Client.Models.Users;
using Quarrel.Messages;
@@ -9,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;
@@ -22,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/Discord/IDiscordService.cs b/src/Quarrel.ViewModels/Services/Discord/IDiscordService.cs
index b1844a6a9..0eedddeb1 100644
--- a/src/Quarrel.ViewModels/Services/Discord/IDiscordService.cs
+++ b/src/Quarrel.ViewModels/Services/Discord/IDiscordService.cs
@@ -1,15 +1,11 @@
// Quarrel © 2022
-using Quarrel.Bindables.Channels;
using Quarrel.Bindables.Channels.Abstract;
using Quarrel.Bindables.Channels.Interfaces;
using Quarrel.Bindables.Guilds;
using Quarrel.Bindables.Messages;
using Quarrel.Bindables.Users;
-using Quarrel.Client.Models.Channels.Interfaces;
-using Quarrel.Client.Models.Guilds;
using Quarrel.Services.Analytics.Enums;
-using System.Collections.Generic;
using System.Threading.Tasks;
namespace Quarrel.Services.Discord
@@ -25,6 +21,13 @@ public interface IDiscordService
/// The current user as a .
BindableSelfUser? GetMe();
+ ///
+ /// Gets a user by id.
+ ///
+ /// The id of the user to get.
+ /// The user of an id.
+ BindableUser? GetUser(ulong userId);
+
///
/// Logs into the discord service by token.
///
@@ -58,16 +61,16 @@ public interface IDiscordService
/// Gets the channels in a guild.
///
/// The guild to get the channels for.
- /// An array of s from the guild.
/// The selected channel as an .
+ /// An array of s from the guild.
BindableGuildChannel?[] GetGuildChannels(BindableGuild guild, out IBindableSelectableChannel? selectedChannel);
///
- /// Gets the channels in a guild as channel groups by category.
+ /// Gets the user's direct message channels.
///
- /// The to get the channels from.
+ /// The .
/// The selected channel as an .
- /// The s for the guild in category groups.
- IEnumerable? GetGuildChannelsGrouped(BindableGuild guild, out IBindableSelectableChannel? selectedChannel);
+ /// An array of s.
+ BindablePrivateChannel?[] GetPrivateChannels(BindableHomeItem home, out IBindableSelectableChannel? selectedChannel);
}
}
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/Services/Windows/IWindowService.cs b/src/Quarrel.ViewModels/Services/Windows/IWindowService.cs
index 6ba74c60a..634fcc94c 100644
--- a/src/Quarrel.ViewModels/Services/Windows/IWindowService.cs
+++ b/src/Quarrel.ViewModels/Services/Windows/IWindowService.cs
@@ -4,8 +4,14 @@
namespace Quarrel.Services.Windows
{
+ ///
+ /// An interface for a service that handles multi-window operations.
+ ///
public interface IWindowService
{
+ ///
+ /// A method that opens a secondary window.
+ ///
void OpenSecondaryWindow();
}
}
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/Panels/ChannelsViewModel.cs b/src/Quarrel.ViewModels/ViewModels/Panels/ChannelsViewModel.cs
index 1d0b4e06e..dae0865a8 100644
--- a/src/Quarrel.ViewModels/ViewModels/Panels/ChannelsViewModel.cs
+++ b/src/Quarrel.ViewModels/ViewModels/Panels/ChannelsViewModel.cs
@@ -5,6 +5,7 @@
using Quarrel.Bindables.Channels;
using Quarrel.Bindables.Channels.Interfaces;
using Quarrel.Bindables.Guilds;
+using Quarrel.Bindables.Guilds.Interfaces;
using Quarrel.Messages.Navigation;
using Quarrel.Services.Discord;
using System.Collections.Generic;
@@ -19,7 +20,7 @@ public partial class ChannelsViewModel : ObservableRecipient
private readonly IMessenger _messenger;
private readonly IDiscordService _discordService;
- private BindableGuild? _currentGuild;
+ private IBindableSelectableGuildItem? _currentGuild;
private IBindableSelectableChannel? _selectedChannel;
private IEnumerable? _groupedSource;
@@ -32,7 +33,7 @@ public ChannelsViewModel(IMessenger messenger, IDiscordService discordService)
_messenger = messenger;
_discordService = discordService;
- _messenger.Register>(this, (_, m) => LoadChannels(m.Guild));
+ _messenger.Register>(this, (_, m) => LoadChannels(m.Guild));
}
///
@@ -73,7 +74,7 @@ public IEnumerable? GroupedSource
/// Loads the channels for a guild.
///
/// The guild to load.
- public void LoadChannels(BindableGuild guild)
+ public void LoadChannels(IBindableSelectableGuildItem guild)
{
if (guild == _currentGuild)
{
@@ -81,7 +82,7 @@ public void LoadChannels(BindableGuild guild)
}
_currentGuild = guild;
- var channels = _discordService.GetGuildChannelsGrouped(guild, out IBindableSelectableChannel? selected);
+ var channels = guild.GetGroupedChannels(out IBindableSelectableChannel? selected);
GroupedSource = channels;
SelectedChannel = selected;
}
diff --git a/src/Quarrel.ViewModels/ViewModels/Panels/GuildsViewModel.cs b/src/Quarrel.ViewModels/ViewModels/Panels/GuildsViewModel.cs
index ac3d080c3..5b08a664c 100644
--- a/src/Quarrel.ViewModels/ViewModels/Panels/GuildsViewModel.cs
+++ b/src/Quarrel.ViewModels/ViewModels/Panels/GuildsViewModel.cs
@@ -8,6 +8,7 @@
using Quarrel.Messages.Navigation;
using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
+using Quarrel.Services.Localization;
using System.Collections.Concurrent;
using System.Collections.ObjectModel;
@@ -19,18 +20,20 @@ namespace Quarrel.ViewModels
public partial class GuildsViewModel : ObservableRecipient
{
private readonly IMessenger _messenger;
+ private readonly ILocalizationService _localizationService;
private readonly IDiscordService _discordService;
private readonly IDispatcherService _dispatcherService;
private readonly ConcurrentDictionary _guilds;
- private BindableGuild? _selectedGuild;
+ private IBindableSelectableGuildItem? _selectedGuild;
///
/// Initializes a new instance of the class.
///
- public GuildsViewModel(IMessenger messenger, IDiscordService discordService, IDispatcherService dispatcherService)
+ public GuildsViewModel(IMessenger messenger, ILocalizationService localizationService, IDiscordService discordService, IDispatcherService dispatcherService)
{
_messenger = messenger;
+ _localizationService = localizationService;
_discordService = discordService;
_dispatcherService = dispatcherService;
@@ -44,7 +47,7 @@ public GuildsViewModel(IMessenger messenger, IDiscordService discordService, IDi
///
/// Gets or sets the selected guild.
///
- public BindableGuild? SelectedGuild
+ public IBindableSelectableGuildItem? SelectedGuild
{
get => _selectedGuild;
set
@@ -55,7 +58,7 @@ public BindableGuild? SelectedGuild
if (SetProperty(ref _selectedGuild, value) && value is not null)
{
value.IsSelected = true;
- _messenger.Send(new NavigateToGuildMessage(value));
+ _messenger.Send(new NavigateToGuildMessage(value));
}
}
}
@@ -73,6 +76,8 @@ public void LoadGuilds()
var folders = _discordService.GetMyGuildFolders();
_dispatcherService.RunOnUIThread(() =>
{
+ Source.Clear();
+ Source.Add(new BindableHomeItem(_discordService, _dispatcherService, _localizationService));
foreach (var folder in folders)
{
if (folder.Folder.Id is null)
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..b7f364810
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/Abstract/UserSettingsSubPageViewModel.cs
@@ -0,0 +1,26 @@
+// Quarrel © 2022
+
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+using Quarrel.Services.Localization;
+using Quarrel.Services.Storage;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract
+{
+ public abstract class UserSettingsSubPageViewModel : ObservableObject
+ {
+ protected readonly ILocalizationService _localizationService;
+ protected readonly IStorageService _storageService;
+
+ public UserSettingsSubPageViewModel(ILocalizationService localizationService, IStorageService storageService)
+ {
+ _localizationService = localizationService;
+ _storageService = storageService;
+ }
+
+ public abstract string Glyph { get; }
+
+ public abstract string Title { get; }
+
+ public virtual bool IsActive => false;
+ }
+}
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..d19c1a274
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/BehaviorPageViewModel.cs
@@ -0,0 +1,24 @@
+// Quarrel © 2022
+
+using Quarrel.Services.Localization;
+using Quarrel.Services.Storage;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class BehaviorPageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string BehaviorResource = "UserSettings/Behavior";
+
+ internal BehaviorPageViewModel(ILocalizationService localizationService, IStorageService storageService) :
+ base(localizationService, storageService)
+ {
+ }
+
+ ///
+ 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..17578450e
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/ConnectionsPageViewModel.cs
@@ -0,0 +1,24 @@
+// Quarrel © 2022
+
+using Quarrel.Services.Localization;
+using Quarrel.Services.Storage;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class ConnectionsPageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string ConnectionsResource = "UserSettings/Connections";
+
+ internal ConnectionsPageViewModel(ILocalizationService localizationService, IStorageService storageService) :
+ base(localizationService, storageService)
+ {
+ }
+
+ ///
+ 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..10151ff90
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/DisplayPageViewModel.cs
@@ -0,0 +1,24 @@
+// Quarrel © 2022
+
+using Quarrel.Services.Localization;
+using Quarrel.Services.Storage;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class DisplayPageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string ConnectionsResource = "UserSettings/Display";
+
+ internal DisplayPageViewModel(ILocalizationService localizationService, IStorageService storageService) :
+ base(localizationService, storageService)
+ {
+ }
+
+ ///
+ 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..71b7c8c1c
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/MyAccountPageViewModel.cs
@@ -0,0 +1,73 @@
+// Quarrel © 2022
+
+using Quarrel.Bindables.Users;
+using Quarrel.Services.Discord;
+using Quarrel.Services.Localization;
+using Quarrel.Services.Storage;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class MyAccountPageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string MyAccountResource = "UserSettings/MyAccount";
+ private readonly IDiscordService _discordService;
+
+ private string? _email;
+ private string _username;
+ private int _discriminator;
+ private string? _aboutMe;
+
+ internal MyAccountPageViewModel(ILocalizationService localizationService, IStorageService storageService, IDiscordService discordService) :
+ base(localizationService, storageService)
+ {
+ _discordService = discordService;
+
+ var user = _discordService.GetMe();
+ if (user is not null)
+ {
+ SetBaseValues(user);
+ }
+ }
+
+ ///
+ public override string Glyph => "";
+
+ ///
+ public override string Title => _localizationService[MyAccountResource];
+
+ public override bool IsActive => true;
+
+ public string? Email
+ {
+ get => _email;
+ set => SetProperty(ref _email, value);
+ }
+
+ public string Username
+ {
+ get => _username;
+ set => SetProperty(ref _username, value);
+ }
+
+ public int Discriminator
+ {
+ get => _discriminator;
+ set => SetProperty(ref _discriminator, value);
+ }
+
+ public string? AboutMe
+ {
+ get => _aboutMe;
+ set => SetProperty(ref _aboutMe, value);
+ }
+
+ private void SetBaseValues(BindableSelfUser user)
+ {
+ Email = user.SelfUser.Email;
+ Username = user.SelfUser.Username;
+ Discriminator = user.SelfUser.Discriminator;
+ AboutMe = user.SelfUser.Bio;
+ }
+ }
+}
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..4cb13c4e0
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/NotificationsPageViewModel.cs
@@ -0,0 +1,24 @@
+// Quarrel © 2022
+
+using Quarrel.Services.Localization;
+using Quarrel.Services.Storage;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class NotificationsPageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string NotificationsResource = "UserSettings/Notifications";
+
+ internal NotificationsPageViewModel(ILocalizationService localizationService, IStorageService storageService) :
+ base(localizationService, storageService)
+ {
+ }
+
+ ///
+ 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..bc592a857
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/PrivacyPageViewModel.cs
@@ -0,0 +1,73 @@
+// Quarrel © 2022
+
+using Discord.API.Models.Enums.Settings;
+using Quarrel.Services.Discord;
+using Quarrel.Services.Localization;
+using Quarrel.Services.Storage;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class PrivacyPageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string PrivacyResource = "UserSettings/Privacy";
+ private readonly IDiscordService _discordService;
+ private ExplicitContentFilterLevel _contentFilterLevel;
+
+ internal PrivacyPageViewModel(ILocalizationService localizationService, IStorageService storageService, IDiscordService discordService) :
+ base(localizationService, storageService)
+ {
+ _discordService = discordService;
+ }
+
+ public override string Glyph => "";
+
+ public override string Title => _localizationService[PrivacyResource];
+
+ public override bool IsActive => true;
+
+ private ExplicitContentFilterLevel ContentFilterLevel
+ {
+ get => _contentFilterLevel;
+ set
+ {
+ if (SetProperty(ref _contentFilterLevel, value))
+ {
+ OnPropertyChanged(nameof(FilterNone));
+ OnPropertyChanged(nameof(FilterPublic));
+ OnPropertyChanged(nameof(FilterAll));
+ }
+ }
+ }
+
+ public bool FilterAll
+ {
+ get => _contentFilterLevel == ExplicitContentFilterLevel.All;
+ set
+ {
+ if (!value) return;
+ ContentFilterLevel = ExplicitContentFilterLevel.All;
+ }
+ }
+
+ public bool FilterPublic
+ {
+ get => _contentFilterLevel == ExplicitContentFilterLevel.Public;
+ set
+ {
+ if (!value) return;
+ ContentFilterLevel = ExplicitContentFilterLevel.Public;
+ }
+ }
+
+ public bool FilterNone
+ {
+ get => _contentFilterLevel == ExplicitContentFilterLevel.None;
+ set
+ {
+ if (!value) return;
+ ContentFilterLevel = ExplicitContentFilterLevel.None;
+ }
+ }
+ }
+}
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..cc742acd7
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/Pages/VoicePageViewModel.cs
@@ -0,0 +1,24 @@
+// Quarrel © 2022
+
+using Quarrel.Services.Localization;
+using Quarrel.Services.Storage;
+using Quarrel.ViewModels.SubPages.UserSettings.Pages.Abstract;
+
+namespace Quarrel.ViewModels.SubPages.UserSettings.Pages
+{
+ public class VoicePageViewModel : UserSettingsSubPageViewModel
+ {
+ private const string VoiceResource = "UserSettings/Voice";
+
+ internal VoicePageViewModel(ILocalizationService localizationService, IStorageService storageService) :
+ base(localizationService, storageService)
+ {
+ }
+
+ ///
+ 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..9ad3b4dd2
--- /dev/null
+++ b/src/Quarrel.ViewModels/ViewModels/SubPages/UserSettings/UserSettingsPageViewModel.cs
@@ -0,0 +1,43 @@
+// Quarrel © 2022
+
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+using Quarrel.Services.Discord;
+using Quarrel.Services.Localization;
+using Quarrel.Services.Storage;
+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, IStorageService storageService, IDiscordService discordService)
+ {
+ _localizationService = localizationService;
+
+ Pages = new ObservableCollection();
+
+ Pages.Add(new MyAccountPageViewModel(localizationService, storageService, discordService));
+ Pages.Add(new PrivacyPageViewModel(_localizationService, storageService, discordService));
+ Pages.Add(new ConnectionsPageViewModel(_localizationService, storageService));
+
+ Pages.Add(new DisplayPageViewModel(_localizationService, storageService));
+ Pages.Add(new BehaviorPageViewModel(_localizationService, storageService));
+ Pages.Add(new NotificationsPageViewModel(_localizationService, storageService));
+ Pages.Add(new VoicePageViewModel(_localizationService, storageService));
+ }
+
+ 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/App.xaml b/src/Quarrel/App.xaml
index 4ab0dd8dd..1f7879319 100644
--- a/src/Quarrel/App.xaml
+++ b/src/Quarrel/App.xaml
@@ -20,6 +20,7 @@
+
diff --git a/src/Quarrel/Controls/Shell/ExtendedSplashScreen.xaml b/src/Quarrel/Controls/Host/ExtendedSplashScreen.xaml
similarity index 95%
rename from src/Quarrel/Controls/Shell/ExtendedSplashScreen.xaml
rename to src/Quarrel/Controls/Host/ExtendedSplashScreen.xaml
index c09901395..858ac41a4 100644
--- a/src/Quarrel/Controls/Shell/ExtendedSplashScreen.xaml
+++ b/src/Quarrel/Controls/Host/ExtendedSplashScreen.xaml
@@ -1,8 +1,8 @@
-
+
diff --git a/src/Quarrel/Controls/Shell/Panels/ChannelPanel.xaml b/src/Quarrel/Controls/Panels/Channels/ChannelPanel.xaml
similarity index 73%
rename from src/Quarrel/Controls/Shell/Panels/ChannelPanel.xaml
rename to src/Quarrel/Controls/Panels/Channels/ChannelPanel.xaml
index 2f40a79f6..c3bdeab30 100644
--- a/src/Quarrel/Controls/Shell/Panels/ChannelPanel.xaml
+++ b/src/Quarrel/Controls/Panels/Channels/ChannelPanel.xaml
@@ -1,12 +1,12 @@
-
+
-
-
+
+
-
-
+
+
diff --git a/src/Quarrel/Controls/Shell/Panels/ChannelPanel.xaml.cs b/src/Quarrel/Controls/Panels/Channels/ChannelPanel.xaml.cs
similarity index 93%
rename from src/Quarrel/Controls/Shell/Panels/ChannelPanel.xaml.cs
rename to src/Quarrel/Controls/Panels/Channels/ChannelPanel.xaml.cs
index f5c24d271..8eb1036a2 100644
--- a/src/Quarrel/Controls/Shell/Panels/ChannelPanel.xaml.cs
+++ b/src/Quarrel/Controls/Panels/Channels/ChannelPanel.xaml.cs
@@ -1,13 +1,12 @@
// Quarrel © 2022
using Microsoft.Extensions.DependencyInjection;
-using Quarrel.Bindables.Channels.Abstract;
using Quarrel.Bindables.Channels.Interfaces;
using Quarrel.ViewModels.Panels;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
-namespace Quarrel.Controls.Shell.Panels
+namespace Quarrel.Controls.Panels.Channels
{
public sealed partial class ChannelPanel : UserControl
{
diff --git a/src/Quarrel/Controls/Shell/CurrentUserButton.xaml b/src/Quarrel/Controls/Panels/Channels/CurrentUserButton.xaml
similarity index 97%
rename from src/Quarrel/Controls/Shell/CurrentUserButton.xaml
rename to src/Quarrel/Controls/Panels/Channels/CurrentUserButton.xaml
index a5e78483b..add0e0d10 100644
--- a/src/Quarrel/Controls/Shell/CurrentUserButton.xaml
+++ b/src/Quarrel/Controls/Panels/Channels/CurrentUserButton.xaml
@@ -1,5 +1,5 @@
diff --git a/src/Quarrel/Controls/Shell/CurrentUserButton.xaml.cs b/src/Quarrel/Controls/Panels/Channels/CurrentUserButton.xaml.cs
similarity index 91%
rename from src/Quarrel/Controls/Shell/CurrentUserButton.xaml.cs
rename to src/Quarrel/Controls/Panels/Channels/CurrentUserButton.xaml.cs
index 3cea4fc4a..a00b97d87 100644
--- a/src/Quarrel/Controls/Shell/CurrentUserButton.xaml.cs
+++ b/src/Quarrel/Controls/Panels/Channels/CurrentUserButton.xaml.cs
@@ -4,7 +4,7 @@
using Quarrel.ViewModels;
using Windows.UI.Xaml.Controls;
-namespace Quarrel.Controls.Shell
+namespace Quarrel.Controls.Panels.Channels
{
public sealed partial class CurrentUserButton : UserControl
{
diff --git a/src/Quarrel/Controls/Panels/Channels/GuildHeader.xaml b/src/Quarrel/Controls/Panels/Channels/GuildHeader.xaml
new file mode 100644
index 000000000..48b27daea
--- /dev/null
+++ b/src/Quarrel/Controls/Panels/Channels/GuildHeader.xaml
@@ -0,0 +1,21 @@
+
+
+
+
diff --git a/src/Quarrel/Controls/Panels/Channels/GuildHeader.xaml.cs b/src/Quarrel/Controls/Panels/Channels/GuildHeader.xaml.cs
new file mode 100644
index 000000000..2c0f7a7e0
--- /dev/null
+++ b/src/Quarrel/Controls/Panels/Channels/GuildHeader.xaml.cs
@@ -0,0 +1,19 @@
+// Quarrel © 2022
+
+using Microsoft.Extensions.DependencyInjection;
+using Quarrel.ViewModels;
+using Windows.UI.Xaml.Controls;
+
+namespace Quarrel.Controls.Panels.Channels
+{
+ public sealed partial class GuildHeader : UserControl
+ {
+ public GuildHeader()
+ {
+ this.InitializeComponent();
+ DataContext = App.Current.Services.GetRequiredService();
+ }
+
+ public GuildsViewModel ViewModel => (GuildsViewModel)DataContext;
+ }
+}
diff --git a/src/Quarrel/Controls/Shell/Panels/GuildPanel.xaml b/src/Quarrel/Controls/Panels/Guilds/GuildPanel.xaml
similarity index 76%
rename from src/Quarrel/Controls/Shell/Panels/GuildPanel.xaml
rename to src/Quarrel/Controls/Panels/Guilds/GuildPanel.xaml
index cf4441527..3d24d2adb 100644
--- a/src/Quarrel/Controls/Shell/Panels/GuildPanel.xaml
+++ b/src/Quarrel/Controls/Panels/Guilds/GuildPanel.xaml
@@ -1,25 +1,27 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Visible
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Quarrel/Controls/Panels/Messages/MessageBox.xaml.cs b/src/Quarrel/Controls/Panels/Messages/MessageBox.xaml.cs
new file mode 100644
index 000000000..ec77d2168
--- /dev/null
+++ b/src/Quarrel/Controls/Panels/Messages/MessageBox.xaml.cs
@@ -0,0 +1,14 @@
+// Quarrel © 2022
+
+using Windows.UI.Xaml.Controls;
+
+namespace Quarrel.Controls.Panels.Messages
+{
+ public sealed partial class MessageBox : UserControl
+ {
+ public MessageBox()
+ {
+ this.InitializeComponent();
+ }
+ }
+}
diff --git a/src/Quarrel/Controls/Panels/Messages/MessagePanel.xaml b/src/Quarrel/Controls/Panels/Messages/MessagePanel.xaml
new file mode 100644
index 000000000..aa5eefe67
--- /dev/null
+++ b/src/Quarrel/Controls/Panels/Messages/MessagePanel.xaml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Quarrel/Controls/Shell/Panels/MessagePanel.xaml.cs b/src/Quarrel/Controls/Panels/Messages/MessagePanel.xaml.cs
similarity index 91%
rename from src/Quarrel/Controls/Shell/Panels/MessagePanel.xaml.cs
rename to src/Quarrel/Controls/Panels/Messages/MessagePanel.xaml.cs
index 163fb9377..8adb04d41 100644
--- a/src/Quarrel/Controls/Shell/Panels/MessagePanel.xaml.cs
+++ b/src/Quarrel/Controls/Panels/Messages/MessagePanel.xaml.cs
@@ -4,7 +4,7 @@
using Quarrel.ViewModels.Panels;
using Windows.UI.Xaml.Controls;
-namespace Quarrel.Controls.Shell.Panels
+namespace Quarrel.Controls.Panels.Messages
{
public sealed partial class MessagePanel : UserControl
{
diff --git a/src/Quarrel/Controls/Shell/Panels/MessagePanel.xaml b/src/Quarrel/Controls/Shell/Panels/MessagePanel.xaml
deleted file mode 100644
index 52bbac408..000000000
--- a/src/Quarrel/Controls/Shell/Panels/MessagePanel.xaml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Quarrel/Controls/Shell/QuarrelCommandBar.xaml b/src/Quarrel/Controls/Shell/QuarrelCommandBar.xaml
index 340cf6e12..9c2953efa 100644
--- a/src/Quarrel/Controls/Shell/QuarrelCommandBar.xaml
+++ b/src/Quarrel/Controls/Shell/QuarrelCommandBar.xaml
@@ -1,83 +1,101 @@
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Quarrel/Controls/Shell/QuarrelCommandBar.xaml.cs b/src/Quarrel/Controls/Shell/QuarrelCommandBar.xaml.cs
index 753a67693..e17c1acd9 100644
--- a/src/Quarrel/Controls/Shell/QuarrelCommandBar.xaml.cs
+++ b/src/Quarrel/Controls/Shell/QuarrelCommandBar.xaml.cs
@@ -9,12 +9,13 @@
using Quarrel.ViewModels.Panels;
using Quarrel.ViewModels.SubPages.DiscordStatus;
using Quarrel.ViewModels.SubPages.Meta;
+using Quarrel.ViewModels.SubPages.Settings;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace Quarrel.Controls.Shell
{
- public sealed partial class QuarrelCommandBar : CommandBar
+ public sealed partial class QuarrelCommandBar : UserControl
{
private readonly IWindowService _windowService;
private readonly IMessenger _messenger;
@@ -60,6 +61,9 @@ private void GoToDiscordStatus(object sender, RoutedEventArgs e)
private void GoToAbout(object sender, RoutedEventArgs e)
=> _messenger.Send(new NavigateToSubPageMessage(typeof(AboutPageViewModel)));
+ private void GoToSettings(object sender, RoutedEventArgs e)
+ => _messenger.Send(new NavigateToSubPageMessage(typeof(UserSettingsPageViewModel)));
+
private static void OnShowHamburgerButtonPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
QuarrelCommandBar commandBar = (QuarrelCommandBar)d;
@@ -71,7 +75,7 @@ private static void OnToggleMemberButtonPropertyChanged(DependencyObject d, Depe
{
QuarrelCommandBar commandBar = (QuarrelCommandBar)d;
bool newValue = (bool)args.NewValue;
- commandBar.ToggleMembersABB.Visibility = newValue ? Visibility.Visible : Visibility.Collapsed;
+ commandBar.ToggleMembersBTN.Visibility = newValue ? Visibility.Visible : Visibility.Collapsed;
}
private void OpenInNewWindow(object sender, RoutedEventArgs e)
diff --git a/src/Quarrel/Controls/Shell/Shell.xaml b/src/Quarrel/Controls/Shell/Shell.xaml
index f1ae1b38b..18d4b27ee 100644
--- a/src/Quarrel/Controls/Shell/Shell.xaml
+++ b/src/Quarrel/Controls/Shell/Shell.xaml
@@ -6,7 +6,9 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:qc="using:Quarrel.Controls"
- xmlns:panels="using:Quarrel.Controls.Shell.Panels"
+ xmlns:panelsg="using:Quarrel.Controls.Panels.Guilds"
+ xmlns:panelsc="using:Quarrel.Controls.Panels.Channels"
+ xmlns:panelsm="using:Quarrel.Controls.Panels.Messages"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400"
@@ -22,14 +24,25 @@
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
@@ -44,9 +57,10 @@
Background="{ThemeResource PrimaryPaneBackground}"
Visibility="Collapsed"/>
-
+
diff --git a/src/Quarrel/Converters/DataTemplates/Channels/MemberCountConverter.cs b/src/Quarrel/Converters/DataTemplates/Channels/MemberCountConverter.cs
new file mode 100644
index 000000000..1b9c6831c
--- /dev/null
+++ b/src/Quarrel/Converters/DataTemplates/Channels/MemberCountConverter.cs
@@ -0,0 +1,20 @@
+// Quarrel © 2022
+
+using Microsoft.Extensions.DependencyInjection;
+using Quarrel.Services.Localization;
+
+namespace Quarrel.Converters.DataTemplates.Channels
+{
+ ///
+ /// Localizes the member count.
+ ///
+ public class MemberCountConverter
+ {
+ private const string MemberCountResource = "Channels/MemberCount";
+
+ public static string Convert(int count)
+ {
+ return App.Current.Services.GetRequiredService()[MemberCountResource, count];
+ }
+ }
+}
diff --git a/src/Quarrel/Converters/DataTemplates/Messages/InfoMessageColorConverter.cs b/src/Quarrel/Converters/DataTemplates/Messages/InfoMessageColorConverter.cs
new file mode 100644
index 000000000..76fbba72b
--- /dev/null
+++ b/src/Quarrel/Converters/DataTemplates/Messages/InfoMessageColorConverter.cs
@@ -0,0 +1,36 @@
+// Quarrel © 2022
+
+using Discord.API.Models.Enums.Messages;
+using Windows.UI.Xaml.Media;
+
+namespace Quarrel.Converters.DataTemplates.Messages
+{
+ public class InfoMessageColorConverter
+ {
+ public static Brush Convert(MessageType type)
+ {
+ string resource = type switch
+ {
+ MessageType.RecipientAdd or
+ MessageType.GuildMemberJoin or
+ MessageType.ChannelFollowAdd or
+ MessageType.GuildDiscoveryRequalified or
+ MessageType.ThreadCreated=> "DiscordGreenBrush",
+
+ MessageType.ChannelNameChange or
+ MessageType.ChannelIconChange or
+ MessageType.GuildDiscoveryGracePeriodInitialWarning => "DiscordYellowBrush",
+
+ MessageType.GuildDiscoveryDisqualified or
+ MessageType.GuildDiscoveryGracePeriodFinalWarning or
+ MessageType.RecipientRemove => "DiscordRedBrush",
+
+ MessageType.Call or
+ MessageType.ChannelPinnedMessage or
+ _ => "InvertedBackground",
+ };
+
+ return (Brush)App.Current.Resources[resource];
+ }
+ }
+}
diff --git a/src/Quarrel/Converters/DataTemplates/Messages/InfoMessageContentConverter.cs b/src/Quarrel/Converters/DataTemplates/Messages/InfoMessageContentConverter.cs
new file mode 100644
index 000000000..a190269e2
--- /dev/null
+++ b/src/Quarrel/Converters/DataTemplates/Messages/InfoMessageContentConverter.cs
@@ -0,0 +1,29 @@
+// Quarrel © 2022
+
+using Discord.API.Models.Enums.Messages;
+using Microsoft.Extensions.DependencyInjection;
+using Quarrel.Bindables.Messages;
+using Quarrel.Services.Localization;
+
+namespace Quarrel.Converters.DataTemplates.Messages
+{
+ public class InfoMessageContentConverter
+ {
+ public static string Convert(BindableMessage message)
+ {
+ string resource = message.Message.Type switch
+ {
+ MessageType.RecipientAdd => "InfoMessage/RecipientAdd",
+ MessageType.RecipientRemove => "InfoMessage/RecipientRemove",
+ MessageType.Call => "InfoMessage/Call",
+ MessageType.ChannelNameChange => "InfoMessage/ChannelNameChange",
+ MessageType.ChannelIconChange => "InfoMessage/ChannelIconChange",
+ MessageType.ChannelPinnedMessage => "InfoMessage/ChannelPinnedMessage",
+ MessageType.GuildMemberJoin => "InfoMessage/GuildMemberJoin",
+ _ => "InfoMessage/Unknown",
+ };
+
+ return App.Current.Services.GetRequiredService()[resource];
+ }
+ }
+}
diff --git a/src/Quarrel/Converters/DataTemplates/Messages/InfoMessageIconConverter.cs b/src/Quarrel/Converters/DataTemplates/Messages/InfoMessageIconConverter.cs
new file mode 100644
index 000000000..8c3ec47a2
--- /dev/null
+++ b/src/Quarrel/Converters/DataTemplates/Messages/InfoMessageIconConverter.cs
@@ -0,0 +1,28 @@
+// Quarrel © 2022
+
+using Discord.API.Models.Enums.Messages;
+
+namespace Quarrel.Converters.DataTemplates.Messages
+{
+ public class InfoMessageIconConverter
+ {
+ public static string Convert(MessageType type)
+ {
+ return type switch
+ {
+ MessageType.Call => "",
+
+ MessageType.ChannelPinnedMessage => "",
+
+ MessageType.ChannelIconChange or
+ MessageType.ChannelNameChange => "",
+
+ MessageType.GuildMemberJoin or
+ MessageType.RecipientAdd => "",
+
+ MessageType.RecipientRemove => "",
+ _ => "?",
+ };
+ }
+ }
+}
diff --git a/src/Quarrel/Converters/Time/SmartTimeFormatConverter.cs b/src/Quarrel/Converters/Time/SmartTimeFormatConverter.cs
new file mode 100644
index 000000000..c2bf1edc8
--- /dev/null
+++ b/src/Quarrel/Converters/Time/SmartTimeFormatConverter.cs
@@ -0,0 +1,76 @@
+// Quarrel © 2022
+
+using Microsoft.Extensions.DependencyInjection;
+using Quarrel.Services.Localization;
+using System;
+
+namespace Quarrel.Converters.Time
+{
+ public class SmartTimeFormatConverter
+ {
+ public static string Convert(DateTimeOffset time)
+ {
+ ILocalizationService localizationService = App.Current.Services.GetRequiredService();
+ string resource;
+ DateTimeOffset now = DateTimeOffset.Now;
+ var timeDiff = now - time;
+
+ // Minutes
+ if (timeDiff.TotalMinutes < 1)
+ {
+ resource = "Time/LTMinuteAgo";
+ return localizationService[resource];
+ }
+ if (timeDiff.TotalMinutes < 2)
+ {
+ resource = "Time/OneMinuteAgo";
+ return localizationService[resource];
+ }
+ if (timeDiff.TotalMinutes < 3)
+ {
+ resource = "Time/TwoMinutesAgo";
+ return localizationService[resource];
+ }
+ if (timeDiff.TotalHours < 1)
+ {
+ resource = "Time/MinutesAgo";
+ int count = (int)timeDiff.TotalMinutes;
+ return localizationService[resource, count];
+ }
+
+ // Hours
+ //if (timeDiff.TotalHours < 2)
+ //{
+ // resource = "Time/OneHourAgo";
+ // return localizationService[resource];
+ //}
+ //if (timeDiff.TotalHours < 3)
+ //{
+ // resource = "Time/TwoHoursAgo";
+ // return localizationService[resource];
+ //}
+ //if (timeDiff.TotalHours < 7)
+ //{
+ // resource = "Time/HoursAgo";
+ // int count = (int)timeDiff.TotalHours;
+ // return localizationService[resource, count];
+ //}
+
+ // Day + Time
+ string shortTime = time.ToString("t");
+ if (time.DayOfYear == now.DayOfYear && time.Year == now.Year)
+ {
+ resource = "Time/TodayAt";
+ return localizationService[resource, shortTime];
+ }
+ DateTime yesterday = (DateTime.Today - TimeSpan.FromDays(1)).Date;
+ if (time.DayOfYear == yesterday.DayOfYear && time.Year == yesterday.Year)
+ {
+ resource = "Time/YesterdayAt";
+ return localizationService[resource, shortTime];
+ }
+
+ return time.ToString("d");
+ }
+ }
+}
diff --git a/src/Quarrel/DataTemplates/ChannelTemplates.xaml b/src/Quarrel/DataTemplates/ChannelTemplates.xaml
index be0dbad38..5bea45bba 100644
--- a/src/Quarrel/DataTemplates/ChannelTemplates.xaml
+++ b/src/Quarrel/DataTemplates/ChannelTemplates.xaml
@@ -2,22 +2,24 @@
x:Class="Quarrel.DataTemplates.ChannelTemplates"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:toolkit="using:Microsoft.Toolkit.Uwp.UI.Controls"
+ xmlns:cconvert="using:Quarrel.Converters.DataTemplates.Channels"
xmlns:a="using:Quarrel.Attached"
xmlns:bindablechannels="using:Quarrel.Bindables.Channels">
-
+
-
+
-
+
@@ -35,6 +37,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Quarrel/DataTemplates/GuildTemplates.xaml b/src/Quarrel/DataTemplates/GuildTemplates.xaml
index 5ffdbc694..7db364fa7 100644
--- a/src/Quarrel/DataTemplates/GuildTemplates.xaml
+++ b/src/Quarrel/DataTemplates/GuildTemplates.xaml
@@ -13,6 +13,14 @@
+
+
+
+
+
+
+
+
diff --git a/src/Quarrel/DataTemplates/MessageTemplates.xaml b/src/Quarrel/DataTemplates/MessageTemplates.xaml
new file mode 100644
index 000000000..16e7c76a0
--- /dev/null
+++ b/src/Quarrel/DataTemplates/MessageTemplates.xaml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Quarrel/DataTemplates/MessageTemplates.xaml.cs b/src/Quarrel/DataTemplates/MessageTemplates.xaml.cs
new file mode 100644
index 000000000..db6fa4295
--- /dev/null
+++ b/src/Quarrel/DataTemplates/MessageTemplates.xaml.cs
@@ -0,0 +1,14 @@
+// Quarrel © 2022
+
+using Windows.UI.Xaml;
+
+namespace Quarrel.DataTemplates
+{
+ public sealed partial class MessageTemplates : ResourceDictionary
+ {
+ public MessageTemplates()
+ {
+ this.InitializeComponent();
+ }
+ }
+}
diff --git a/src/Quarrel/MultilingualResources/Quarrel.he-IL.xlf b/src/Quarrel/MultilingualResources/Quarrel.he-IL.xlf
index 2d6d7fff2..fb624ad84 100644
--- a/src/Quarrel/MultilingualResources/Quarrel.he-IL.xlf
+++ b/src/Quarrel/MultilingualResources/Quarrel.he-IL.xlf
@@ -188,6 +188,189 @@
Quarrel Release
קווראל שחרור
+
+ Call
+ שיחה
+
+
+ Open Channel in New Window
+ פתח הערוץ בחלון חדש
+
+
+ Toggle Members Panel
+ פאנל חברים
+
+
+ Discord Status
+ סטטוס דיסקורד
+
+
+ About
+ אודות
+
+
+ Settings
+ הגדרות
+
+
+ Send message
+ שלח הודעה
+
+
+ Home
+ בית
+
+
+ {0} Members
+ {0} חברים
+
+
+ {0} and {1}
+ {0}ו {1}
+ This is used for an and list of two items
+
+
+ {0}, {1}
+ {0}, {1}
+ This is used to form a comma list {0}, {{1}, and {2}}
+
+
+ {0}, and {1}
+ {0}, ו{1}
+ This is used for the base item of and conjunction
+
+
+ My Account
+ החשבון שלי
+
+
+ Privacy
+ פרטיות
+
+
+ Connections
+ חיבורים
+
+
+ Display
+ להציג
+
+
+ Behavior
+ התנהגות
+
+
+ Notifications
+ התראות
+
+
+ Voice
+ קול
+
+
+
+ Don't analyze any DMs
+ אין לנתח הודעות ישירות
+
+
+ I live dangerously
+ אני גר בצורה מסוכנת
+
+
+
+ Analyze and automatically delete direct messages containing explicit content
+ ניתוח ומחק באופן אוטומטי הודעות ישירות המכילות תוכן מפורשת
+
+
+ DIRECT MESSAGE FILTERING
+ מסנן הודעה ישירה
+
+
+
+ Analyze all DMs, except from my friends
+ נתח את כל ההודעות הישירות, למעט מחבריי
+
+
+ My friends are nice
+ החברים שלי נחמדים
+
+
+ Analyze all DMs
+ לנתח את כל ההודעות הישירות
+
+
+ Protect me
+ הגן עליי
+
+
+
+ {author} started a call
+ {author} started a call
+
+
+ {author} added {mention.0} to the group
+ {author} added {mention.0} to the group
+
+
+ {author} removed {mention.0} from the group
+ {author} removed {mention.0} from the group
+
+
+ Unknown message
+ Unknown message
+
+
+ {author} changed the channel icon
+ {author} changed the channel icon
+
+
+ {author} changed the channel name to {content}
+ {author} changed the channel name to {content}
+
+
+ {author pinned {message_reference} to the channel
+ {author pinned {message_reference} to the channel
+
+
+ {author} joined the server
+ {author} joined the server
+
+
+ Less than a minute ago
+ Less than a minute ago
+
+
+ {0} minutes ago
+ {0} minutes ago
+
+
+ A minute ago
+ A minute ago
+
+
+ Today at {0}
+ Today at {0}
+
+
+ 2 minutes ago
+ 2 minutes ago
+
+
+ Yesterday at {0}
+ Yesterday at {0}
+