Remove `Channel.ParentNameWithFallback`

pull/1131/head
Tyrrrz 1 year ago
parent 59344cedbe
commit 5abe74894c

@ -200,7 +200,7 @@ public abstract class ExportCommandBase : DiscordCommandBase
try try
{ {
await progressContext.StartTaskAsync( await progressContext.StartTaskAsync(
$"{channel.ParentNameWithFallback} / {channel.Name}", channel.GetHierarchicalName(),
async progress => async progress =>
{ {
var guild = await Discord.GetGuildAsync( var guild = await Discord.GetGuildAsync(
@ -263,10 +263,7 @@ public abstract class ExportCommandBase : DiscordCommandBase
foreach (var (channel, error) in errorsByChannel) foreach (var (channel, error) in errorsByChannel)
{ {
await console.Error.WriteAsync( await console.Error.WriteAsync($"{channel.GetHierarchicalName()}: ");
$"{channel.ParentNameWithFallback} / {channel.Name}: "
);
using (console.WithForegroundColor(ConsoleColor.Red)) using (console.WithForegroundColor(ConsoleColor.Red))
await console.Error.WriteLineAsync(error); await console.Error.WriteLineAsync(error);
} }
@ -294,7 +291,7 @@ public abstract class ExportCommandBase : DiscordCommandBase
var channel = await Discord.GetChannelAsync(channelId, cancellationToken); var channel = await Discord.GetChannelAsync(channelId, cancellationToken);
// Unwrap categories // Unwrap categories
if (channel.Kind == ChannelKind.GuildCategory) if (channel.IsCategory)
{ {
var guildChannels = var guildChannels =
channelsByGuild.GetValueOrDefault(channel.GuildId) channelsByGuild.GetValueOrDefault(channel.GuildId)

@ -60,10 +60,10 @@ public class ExportAllCommand : ExportCommandBase
var channel in Discord.GetGuildChannelsAsync(guild.Id, cancellationToken) var channel in Discord.GetGuildChannelsAsync(guild.Id, cancellationToken)
) )
{ {
if (channel.Kind == ChannelKind.GuildCategory) if (channel.IsCategory)
continue; continue;
if (!IncludeVoiceChannels && channel.Kind.IsVoice()) if (!IncludeVoiceChannels && channel.IsVoice)
continue; continue;
channels.Add(channel); channels.Add(channel);
@ -129,15 +129,15 @@ public class ExportAllCommand : ExportCommandBase
// Filter out unwanted channels // Filter out unwanted channels
if (!IncludeDirectChannels) if (!IncludeDirectChannels)
channels.RemoveAll(c => c.Kind.IsDirect()); channels.RemoveAll(c => c.IsDirect);
if (!IncludeGuildChannels) if (!IncludeGuildChannels)
channels.RemoveAll(c => c.Kind.IsGuild()); channels.RemoveAll(c => c.IsGuild);
if (!IncludeVoiceChannels) if (!IncludeVoiceChannels)
channels.RemoveAll(c => c.Kind.IsVoice()); channels.RemoveAll(c => c.IsVoice);
if (ThreadInclusionMode == ThreadInclusionMode.None) if (ThreadInclusionMode == ThreadInclusionMode.None)
channels.RemoveAll(c => c.Kind.IsThread()); channels.RemoveAll(c => c.IsThread);
if (ThreadInclusionMode != ThreadInclusionMode.All) if (ThreadInclusionMode != ThreadInclusionMode.All)
channels.RemoveAll(c => c.Kind.IsThread() && c.IsArchived); channels.RemoveAll(c => c is { IsThread: true, IsArchived: true });
await ExportAsync(console, channels); await ExportAsync(console, channels);
} }

@ -38,10 +38,10 @@ public class ExportGuildCommand : ExportCommandBase
// Regular channels // Regular channels
await foreach (var channel in Discord.GetGuildChannelsAsync(GuildId, cancellationToken)) await foreach (var channel in Discord.GetGuildChannelsAsync(GuildId, cancellationToken))
{ {
if (channel.Kind == ChannelKind.GuildCategory) if (channel.IsCategory)
continue; continue;
if (!IncludeVoiceChannels && channel.Kind.IsVoice()) if (!IncludeVoiceChannels && channel.IsVoice)
continue; continue;
channels.Add(channel); channels.Add(channel);

@ -35,8 +35,8 @@ public class GetChannelsCommand : DiscordCommandBase
var cancellationToken = console.RegisterCancellationHandler(); var cancellationToken = console.RegisterCancellationHandler();
var channels = (await Discord.GetGuildChannelsAsync(GuildId, cancellationToken)) var channels = (await Discord.GetGuildChannelsAsync(GuildId, cancellationToken))
.Where(c => c.Kind != ChannelKind.GuildCategory) .Where(c => !c.IsCategory)
.Where(c => IncludeVoiceChannels || !c.Kind.IsVoice()) .Where(c => IncludeVoiceChannels || !c.IsVoice)
.OrderBy(c => c.Parent?.Position) .OrderBy(c => c.Parent?.Position)
.ThenBy(c => c.Name) .ThenBy(c => c.Name)
.ToArray(); .ToArray();
@ -72,11 +72,9 @@ public class GetChannelsCommand : DiscordCommandBase
using (console.WithForegroundColor(ConsoleColor.DarkGray)) using (console.WithForegroundColor(ConsoleColor.DarkGray))
await console.Output.WriteAsync(" | "); await console.Output.WriteAsync(" | ");
// Channel category / name // Channel name
using (console.WithForegroundColor(ConsoleColor.White)) using (console.WithForegroundColor(ConsoleColor.White))
await console.Output.WriteLineAsync( await console.Output.WriteLineAsync(channel.GetHierarchicalName());
$"{channel.ParentNameWithFallback} / {channel.Name}"
);
var channelThreads = threads.Where(t => t.Parent?.Id == channel.Id).ToArray(); var channelThreads = threads.Where(t => t.Parent?.Id == channel.Id).ToArray();
var channelThreadIdMaxLength = channelThreads var channelThreadIdMaxLength = channelThreads

@ -21,7 +21,6 @@ public class GetDirectChannelsCommand : DiscordCommandBase
var channels = ( var channels = (
await Discord.GetGuildChannelsAsync(Guild.DirectMessages.Id, cancellationToken) await Discord.GetGuildChannelsAsync(Guild.DirectMessages.Id, cancellationToken)
) )
.Where(c => c.Kind != ChannelKind.GuildCategory)
.OrderByDescending(c => c.LastMessageId) .OrderByDescending(c => c.LastMessageId)
.ThenBy(c => c.Name) .ThenBy(c => c.Name)
.ToArray(); .ToArray();
@ -42,11 +41,9 @@ public class GetDirectChannelsCommand : DiscordCommandBase
using (console.WithForegroundColor(ConsoleColor.DarkGray)) using (console.WithForegroundColor(ConsoleColor.DarkGray))
await console.Output.WriteAsync(" | "); await console.Output.WriteAsync(" | ");
// Channel category / name // Channel name
using (console.WithForegroundColor(ConsoleColor.White)) using (console.WithForegroundColor(ConsoleColor.White))
await console.Output.WriteLineAsync( await console.Output.WriteLineAsync(channel.GetHierarchicalName());
$"{channel.ParentNameWithFallback} / {channel.Name}"
);
} }
} }
} }

@ -1,4 +1,5 @@
using System.Linq; using System.Collections.Generic;
using System.Linq;
using System.Text.Json; using System.Text.Json;
using DiscordChatExporter.Core.Discord.Data.Common; using DiscordChatExporter.Core.Discord.Data.Common;
using DiscordChatExporter.Core.Utils.Extensions; using DiscordChatExporter.Core.Utils.Extensions;
@ -20,32 +21,36 @@ public partial record Channel(
Snowflake? LastMessageId Snowflake? LastMessageId
) : IHasId ) : IHasId
{ {
// Used for visual backwards-compatibility with old exports, where public bool IsDirect => Kind is ChannelKind.DirectTextChat or ChannelKind.DirectGroupTextChat;
// channels without a parent (i.e. mostly DM channels) or channels
// with an inaccessible parent (i.e. inside private categories) had public bool IsGuild => !IsDirect;
// a fallback category created for them.
public string ParentNameWithFallback => public bool IsCategory => Kind == ChannelKind.GuildCategory;
Parent?.Name
?? Kind switch public bool IsVoice => Kind is ChannelKind.GuildVoiceChat or ChannelKind.GuildStageVoice;
{
ChannelKind.GuildCategory => "Category", public bool IsThread =>
ChannelKind.GuildTextChat => "Text", Kind
ChannelKind.DirectTextChat => "Private", is ChannelKind.GuildNewsThread
ChannelKind.DirectGroupTextChat => "Group", or ChannelKind.GuildPublicThread
ChannelKind.GuildPrivateThread => "Private Thread", or ChannelKind.GuildPrivateThread;
ChannelKind.GuildPublicThread => "Public Thread",
ChannelKind.GuildNews => "News",
ChannelKind.GuildNewsThread => "News Thread",
_ => "Default"
};
public bool IsEmpty => LastMessageId is null; public bool IsEmpty => LastMessageId is null;
// Only needed for WPF data binding. Don't use anywhere else. public IEnumerable<Channel> GetParents()
public bool IsVoice => Kind.IsVoice(); {
var current = Parent;
while (current is not null)
{
yield return current;
current = current.Parent;
}
}
public Channel? TryGetRootParent() => GetParents().LastOrDefault();
// Only needed for WPF data binding. Don't use anywhere else. public string GetHierarchicalName() =>
public bool IsThread => Kind.IsThread(); string.Join(" / ", GetParents().Reverse().Select(c => c.Name).Append(Name));
public bool MayHaveMessagesAfter(Snowflake messageId) => !IsEmpty && messageId < LastMessageId; public bool MayHaveMessagesAfter(Snowflake messageId) => !IsEmpty && messageId < LastMessageId;

@ -16,20 +16,3 @@ public enum ChannelKind
GuildDirectory = 14, GuildDirectory = 14,
GuildForum = 15 GuildForum = 15
} }
public static class ChannelKindExtensions
{
public static bool IsDirect(this ChannelKind kind) =>
kind is ChannelKind.DirectTextChat or ChannelKind.DirectGroupTextChat;
public static bool IsGuild(this ChannelKind kind) => !kind.IsDirect();
public static bool IsVoice(this ChannelKind kind) =>
kind is ChannelKind.GuildVoiceChat or ChannelKind.GuildStageVoice;
public static bool IsThread(this ChannelKind kind) =>
kind
is ChannelKind.GuildNewsThread
or ChannelKind.GuildPublicThread
or ChannelKind.GuildPrivateThread;
}

@ -6,7 +6,12 @@ using JsonExtensions.Reading;
namespace DiscordChatExporter.Core.Discord.Data; namespace DiscordChatExporter.Core.Discord.Data;
// https://discord.com/developers/docs/resources/guild#guild-object // https://discord.com/developers/docs/resources/guild#guild-object
public record Guild(Snowflake Id, string Name, string IconUrl) : IHasId public partial record Guild(Snowflake Id, string Name, string IconUrl) : IHasId
{
public bool IsDirect => Id == DirectMessages.Id;
}
public partial record Guild
{ {
// Direct messages are encapsulated within a special pseudo-guild for consistency // Direct messages are encapsulated within a special pseudo-guild for consistency
public static Guild DirectMessages { get; } = public static Guild DirectMessages { get; } =

@ -30,7 +30,13 @@ public partial record Message(
Interaction? Interaction Interaction? Interaction
) : IHasId ) : IHasId
{ {
public bool IsReplyLike => Kind == MessageKind.Reply || Interaction is not null; public bool IsSystemNotification =>
Kind is >= MessageKind.RecipientAdd and <= MessageKind.ThreadCreated;
public bool IsReply => Kind == MessageKind.Reply;
// App interactions are rendered as replies in the Discord client, but they are not actually replies
public bool IsReplyLike => IsReply || Interaction is not null;
public IEnumerable<User> GetReferencedUsers() public IEnumerable<User> GetReferencedUsers()
{ {

@ -14,8 +14,3 @@ public enum MessageKind
ThreadCreated = 18, ThreadCreated = 18,
Reply = 19 Reply = 19
} }
public static class MessageKindExtensions
{
public static bool IsSystemNotification(this MessageKind kind) => (int)kind is >= 1 and <= 18;
}

@ -286,11 +286,12 @@ public class DiscordClient
yield break; yield break;
var tokenKind = _resolvedTokenKind ??= await GetTokenKindAsync(cancellationToken); var tokenKind = _resolvedTokenKind ??= await GetTokenKindAsync(cancellationToken);
var channels = (await GetGuildChannelsAsync(guildId, cancellationToken)) var channels = (await GetGuildChannelsAsync(guildId, cancellationToken))
// Categories cannot have threads // Categories cannot have threads
.Where(c => c.Kind != ChannelKind.GuildCategory) .Where(c => !c.IsCategory)
// Voice channels cannot have threads // Voice channels cannot have threads
.Where(c => !c.Kind.IsVoice()) .Where(c => !c.IsVoice)
// Empty channels cannot have threads // Empty channels cannot have threads
.Where(c => !c.IsEmpty) .Where(c => !c.IsEmpty)
// If the 'before' boundary is specified, skip channels that don't have messages // If the 'before' boundary is specified, skip channels that don't have messages

@ -92,7 +92,7 @@ internal partial class CsvMessageWriter : MessageWriter
await _writer.WriteAsync(','); await _writer.WriteAsync(',');
// Message content // Message content
if (message.Kind.IsSystemNotification()) if (message.IsSystemNotification)
{ {
await _writer.WriteAsync(CsvEncode(message.GetFallbackContent())); await _writer.WriteAsync(CsvEncode(message.GetFallbackContent()));
} }

@ -99,10 +99,21 @@ public partial class ExportRequest
{ {
var buffer = new StringBuilder(); var buffer = new StringBuilder();
// Guild and channel names // Guild name
buffer.Append( buffer.Append(guild.Name);
$"{guild.Name} - {channel.ParentNameWithFallback} - {channel.Name} [{channel.Id}]"
); // Parent name
if (channel.Parent is not null)
buffer.Append(" - ").Append(channel.Parent.Name);
// Channel name and ID
buffer
.Append(" - ")
.Append(channel.Name)
.Append(' ')
.Append('[')
.Append(channel.Id)
.Append(']');
// Date range // Date range
if (after is not null || before is not null) if (after is not null || before is not null)
@ -142,9 +153,8 @@ public partial class ExportRequest
Channel channel, Channel channel,
Snowflake? after, Snowflake? after,
Snowflake? before Snowflake? before
) ) =>
{ Regex.Replace(
return Regex.Replace(
path, path,
"%.", "%.",
m => m =>
@ -153,14 +163,18 @@ public partial class ExportRequest
{ {
"%g" => guild.Id.ToString(), "%g" => guild.Id.ToString(),
"%G" => guild.Name, "%G" => guild.Name,
"%t" => channel.Parent?.Id.ToString() ?? "", "%t" => channel.Parent?.Id.ToString() ?? "",
"%T" => channel.Parent?.Name ?? "", "%T" => channel.Parent?.Name ?? "",
"%c" => channel.Id.ToString(), "%c" => channel.Id.ToString(),
"%C" => channel.Name, "%C" => channel.Name,
"%p" => channel.Position?.ToString(CultureInfo.InvariantCulture) ?? "0", "%p" => channel.Position?.ToString(CultureInfo.InvariantCulture) ?? "0",
"%P" "%P"
=> channel.Parent?.Position?.ToString(CultureInfo.InvariantCulture) => channel.Parent?.Position?.ToString(CultureInfo.InvariantCulture)
?? "0", ?? "0",
"%a" "%a"
=> after?.ToDate().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) => after?.ToDate().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)
?? "", ?? "",
@ -172,12 +186,12 @@ public partial class ExportRequest
"yyyy-MM-dd", "yyyy-MM-dd",
CultureInfo.InvariantCulture CultureInfo.InvariantCulture
), ),
"%%" => "%", "%%" => "%",
_ => m.Value _ => m.Value
} }
) )
); );
}
private static string GetOutputBaseFilePath( private static string GetOutputBaseFilePath(
Guild guild, Guild guild,

@ -280,7 +280,7 @@ internal partial class HtmlMarkdownVisitor : MarkdownVisitor
else if (mention.Kind == MentionKind.Channel) else if (mention.Kind == MentionKind.Channel)
{ {
var channel = mention.TargetId?.Pipe(_context.TryGetChannel); var channel = mention.TargetId?.Pipe(_context.TryGetChannel);
var symbol = channel?.Kind.IsVoice() == true ? "🔊" : "#"; var symbol = channel?.IsVoice == true ? "🔊" : "#";
var name = channel?.Name ?? "deleted-channel"; var name = channel?.Name ?? "deleted-channel";
_buffer.Append( _buffer.Append(

@ -30,22 +30,22 @@ internal class HtmlMessageWriter : MessageWriter
if (_messageGroup.LastOrDefault() is not { } lastMessage) if (_messageGroup.LastOrDefault() is not { } lastMessage)
return true; return true;
// Reply messages cannot join existing groups because they need to appear first // Reply-like messages cannot join existing groups because they need to appear first
if (message.Kind == MessageKind.Reply) if (message.IsReplyLike)
return false; return false;
// Grouping for system notifications // Grouping for system notifications
if (message.Kind.IsSystemNotification()) if (message.IsSystemNotification)
{ {
// Can only be grouped with other system notifications // Can only be grouped with other system notifications
if (!lastMessage.Kind.IsSystemNotification()) if (!lastMessage.IsSystemNotification)
return false; return false;
} }
// Grouping for normal messages // Grouping for normal messages
else else
{ {
// Can only be grouped with other normal messages // Can only be grouped with other normal messages
if (lastMessage.Kind.IsSystemNotification()) if (lastMessage.IsSystemNotification)
return false; return false;
// Messages must be within 7 minutes of each other // Messages must be within 7 minutes of each other

@ -273,8 +273,11 @@ internal class JsonMessageWriter : MessageWriter
_writer.WriteStartObject("channel"); _writer.WriteStartObject("channel");
_writer.WriteString("id", Context.Request.Channel.Id.ToString()); _writer.WriteString("id", Context.Request.Channel.Id.ToString());
_writer.WriteString("type", Context.Request.Channel.Kind.ToString()); _writer.WriteString("type", Context.Request.Channel.Kind.ToString());
// Original schema did not account for threads, so 'category' actually refers to the parent channel
_writer.WriteString("categoryId", Context.Request.Channel.Parent?.Id.ToString()); _writer.WriteString("categoryId", Context.Request.Channel.Parent?.Id.ToString());
_writer.WriteString("category", Context.Request.Channel.ParentNameWithFallback); _writer.WriteString("category", Context.Request.Channel.Parent?.Name);
_writer.WriteString("name", Context.Request.Channel.Name); _writer.WriteString("name", Context.Request.Channel.Name);
_writer.WriteString("topic", Context.Request.Channel.Topic); _writer.WriteString("topic", Context.Request.Channel.Topic);
@ -329,7 +332,7 @@ internal class JsonMessageWriter : MessageWriter
_writer.WriteBoolean("isPinned", message.IsPinned); _writer.WriteBoolean("isPinned", message.IsPinned);
// Content // Content
if (message.Kind.IsSystemNotification()) if (message.IsSystemNotification)
{ {
_writer.WriteString("content", message.GetFallbackContent()); _writer.WriteString("content", message.GetFallbackContent());
} }

@ -47,7 +47,7 @@
<div id="chatlog__message-container-@message.Id" class="chatlog__message-container @(message.IsPinned ? "chatlog__message-container--pinned" : null)" data-message-id="@message.Id"> <div id="chatlog__message-container-@message.Id" class="chatlog__message-container @(message.IsPinned ? "chatlog__message-container--pinned" : null)" data-message-id="@message.Id">
<div class="chatlog__message"> <div class="chatlog__message">
@* System notification *@ @* System notification *@
@if (message.Kind.IsSystemNotification()) @if (message.IsSystemNotification)
{ {
<div class="chatlog__message-aside"> <div class="chatlog__message-aside">
<svg class="chatlog__system-notification-icon"> <svg class="chatlog__system-notification-icon">
@ -329,7 +329,7 @@
<div class="chatlog__embed"> <div class="chatlog__embed">
<div class="chatlog__embed-invite-container"> <div class="chatlog__embed-invite-container">
<div class="chatlog__embed-invite-title">@(invite.Channel?.Kind.IsDirect() == true ? "Invite to join a group DM" : "Invite to join a server")</div> <div class="chatlog__embed-invite-title">@(invite.Channel?.IsDirect == true ? "Invite to join a group DM" : "Invite to join a server")</div>
<div class="chatlog__embed-invite"> <div class="chatlog__embed-invite">
<div class="chatlog__embed-invite-guild-icon-container"> <div class="chatlog__embed-invite-guild-icon-container">
<img class="chatlog__embed-invite-guild-icon" src="@await ResolveAssetUrlAsync(invite.Channel?.IconUrl ?? invite.Guild.IconUrl)" alt="Guild icon" loading="lazy"> <img class="chatlog__embed-invite-guild-icon" src="@await ResolveAssetUrlAsync(invite.Channel?.IconUrl ?? invite.Guild.IconUrl)" alt="Guild icon" loading="lazy">

@ -72,7 +72,7 @@ internal partial class PlainTextMarkdownVisitor : MarkdownVisitor
_buffer.Append($"#{name}"); _buffer.Append($"#{name}");
// Voice channel marker // Voice channel marker
if (channel?.Kind.IsVoice() == true) if (channel?.IsVoice == true)
_buffer.Append(" [voice]"); _buffer.Append(" [voice]");
} }
else if (mention.Kind == MentionKind.Role) else if (mention.Kind == MentionKind.Role)

@ -200,9 +200,7 @@ internal class PlainTextMessageWriter : MessageWriter
{ {
await _writer.WriteLineAsync(new string('=', 62)); await _writer.WriteLineAsync(new string('=', 62));
await _writer.WriteLineAsync($"Guild: {Context.Request.Guild.Name}"); await _writer.WriteLineAsync($"Guild: {Context.Request.Guild.Name}");
await _writer.WriteLineAsync( await _writer.WriteLineAsync($"Channel: {Context.Request.Channel.GetHierarchicalName()}");
$"Channel: {Context.Request.Channel.ParentNameWithFallback} / {Context.Request.Channel.Name}"
);
if (!string.IsNullOrWhiteSpace(Context.Request.Channel.Topic)) if (!string.IsNullOrWhiteSpace(Context.Request.Channel.Topic))
{ {
@ -238,7 +236,7 @@ internal class PlainTextMessageWriter : MessageWriter
await WriteMessageHeaderAsync(message); await WriteMessageHeaderAsync(message);
// Content // Content
if (message.Kind.IsSystemNotification()) if (message.IsSystemNotification)
{ {
await _writer.WriteLineAsync(message.GetFallbackContent()); await _writer.WriteLineAsync(message.GetFallbackContent());
} }

@ -1004,7 +1004,7 @@
</div> </div>
<div class="preamble__entries-container"> <div class="preamble__entries-container">
<div class="preamble__entry">@Context.Request.Guild.Name</div> <div class="preamble__entry">@Context.Request.Guild.Name</div>
<div class="preamble__entry">@Context.Request.Channel.ParentNameWithFallback / @Context.Request.Channel.Name</div> <div class="preamble__entry">@Context.Request.Channel.GetHierarchicalName()</div>
@if (!string.IsNullOrWhiteSpace(Context.Request.Channel.Topic)) @if (!string.IsNullOrWhiteSpace(Context.Request.Channel.Topic))
{ {

@ -13,10 +13,10 @@ public class ChannelToGroupKeyConverter : IValueConverter
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) => public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
value switch value switch
{ {
Channel channel when channel.Kind.IsThread() Channel { IsThread: true, Parent: not null } channel
=> $"Threads in #{channel.ParentNameWithFallback}", => $"Threads in #{channel.Parent.Name}",
Channel channel => channel.ParentNameWithFallback, Channel channel => channel.Parent?.Name ?? "???",
_ => null _ => null
}; };

@ -43,8 +43,6 @@ public class DashboardViewModel : PropertyChangedBase
public Guild? SelectedGuild { get; set; } public Guild? SelectedGuild { get; set; }
public bool IsDirectMessageGuildSelected => SelectedGuild?.Id == Guild.DirectMessages.Id;
public IReadOnlyList<Channel>? AvailableChannels { get; private set; } public IReadOnlyList<Channel>? AvailableChannels { get; private set; }
public IReadOnlyList<Channel>? SelectedChannels { get; set; } public IReadOnlyList<Channel>? SelectedChannels { get; set; }
@ -164,7 +162,7 @@ public class DashboardViewModel : PropertyChangedBase
// Regular channels // Regular channels
await foreach (var channel in _discord.GetGuildChannelsAsync(SelectedGuild.Id)) await foreach (var channel in _discord.GetGuildChannelsAsync(SelectedGuild.Id))
{ {
if (channel.Kind == ChannelKind.GuildCategory) if (channel.IsCategory)
continue; continue;
channels.Add(channel); channels.Add(channel);

@ -313,10 +313,10 @@
<ListBox.Style> <ListBox.Style>
<Style BasedOn="{StaticResource {x:Type ListBox}}" TargetType="{x:Type ListBox}"> <Style BasedOn="{StaticResource {x:Type ListBox}}" TargetType="{x:Type ListBox}">
<Style.Triggers> <Style.Triggers>
<DataTrigger Binding="{Binding IsDirectMessageGuildSelected}" Value="True"> <DataTrigger Binding="{Binding SelectedGuild.IsDirect}" Value="True">
<Setter Property="ItemsSource" Value="{Binding Source={StaticResource AvailableDirectChannelsViewSource}}" /> <Setter Property="ItemsSource" Value="{Binding Source={StaticResource AvailableDirectChannelsViewSource}}" />
</DataTrigger> </DataTrigger>
<DataTrigger Binding="{Binding IsDirectMessageGuildSelected}" Value="False"> <DataTrigger Binding="{Binding SelectedGuild.IsDirect}" Value="False">
<Setter Property="ItemsSource" Value="{Binding Source={StaticResource AvailableChannelsViewSource}}" /> <Setter Property="ItemsSource" Value="{Binding Source={StaticResource AvailableChannelsViewSource}}" />
</DataTrigger> </DataTrigger>
</Style.Triggers> </Style.Triggers>

@ -60,8 +60,10 @@
FontWeight="Light" FontWeight="Light"
TextTrimming="CharacterEllipsis" TextTrimming="CharacterEllipsis"
Visibility="{Binding IsSingleChannel, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"> Visibility="{Binding IsSingleChannel, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<Run Text="{Binding Channels[0].ParentNameWithFallback, Mode=OneWay}" ToolTip="{Binding Channels[0].ParentNameWithFallback, Mode=OneWay}" /> <TextBlock Visibility="{Binding Channels[0].Parent, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<Run Text="/" /> <Run Text="{Binding Channels[0].Parent.Name, Mode=OneWay}" ToolTip="{Binding Channels[0].Parent.Name, Mode=OneWay}" />
<Run Text="/" />
</TextBlock>
<Run <Run
FontWeight="SemiBold" FontWeight="SemiBold"
Text="{Binding Channels[0].Name, Mode=OneWay}" Text="{Binding Channels[0].Name, Mode=OneWay}"

Loading…
Cancel
Save