diff --git a/Swiftcord.xcodeproj/project.pbxproj b/Swiftcord.xcodeproj/project.pbxproj index ef90dc77..80801122 100644 --- a/Swiftcord.xcodeproj/project.pbxproj +++ b/Swiftcord.xcodeproj/project.pbxproj @@ -110,6 +110,7 @@ 368B6731287A211F00E37B33 /* HorizontalDividerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4350032879C38C001DEC81 /* HorizontalDividerView.swift */; }; 36BC29F3285C162500A8B316 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 36BC29F2285C162500A8B316 /* Credits.rtf */; }; 900F6DA1284A1C0C000B6D29 /* GeneratedBuildSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 900F6DA0284A1C0C000B6D29 /* GeneratedBuildSettings.swift */; }; + 938A58442A4EA2AC0088A5FC /* CommandMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 938A58432A4EA2AC0088A5FC /* CommandMessageView.swift */; }; 9FCE7B1D28C7140100213A3F /* ServerFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FCE7B1C28C7140100213A3F /* ServerFolder.swift */; }; 9FCE7B1E28C7140100213A3F /* ServerFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FCE7B1C28C7140100213A3F /* ServerFolder.swift */; }; DA03DA3F284F1E9200257790 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA03DA3E284F1E9200257790 /* Keychain.swift */; }; @@ -283,6 +284,7 @@ 900F6D9F284A1AE6000B6D29 /* Project Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Project Release.xcconfig"; sourceTree = ""; }; 900F6DA0284A1C0C000B6D29 /* GeneratedBuildSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedBuildSettings.swift; sourceTree = ""; }; 90F77AAA284C87E900166BF3 /* AppCenter.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppCenter.xcconfig; sourceTree = ""; }; + 938A58432A4EA2AC0088A5FC /* CommandMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandMessageView.swift; sourceTree = ""; }; 9FCE7B1C28C7140100213A3F /* ServerFolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerFolder.swift; sourceTree = ""; usesTabs = 0; }; DA03DA3E284F1E9200257790 /* Keychain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = ""; }; DA0FC06929AC385B00ADB012 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; @@ -775,6 +777,7 @@ DAB1E48528A50D3600645FCD /* DefaultMessageView.swift */, DAAFB5C0282A64CD00807B54 /* LoFiMessageView.swift */, DA54D57E28460F3A00B11857 /* ReferenceMessageView.swift */, + 938A58432A4EA2AC0088A5FC /* CommandMessageView.swift */, DA32EF2527C62E6900A9ED72 /* MessageView.swift */, ); path = MessageRenderViews; @@ -1271,6 +1274,7 @@ DA54D5712841D6CF00B11857 /* MiniUserProfileView.swift in Sources */, DAB1E47628A2189700645FCD /* MessagesViewModel.swift in Sources */, DA4350022879BFCA001DEC81 /* ServerJoinView.swift in Sources */, + 938A58442A4EA2AC0088A5FC /* CommandMessageView.swift in Sources */, DA32EF5227C8FBB200A9ED72 /* User+.swift in Sources */, DA520AD127D4CFCF009FD740 /* BillingSettingsView.swift in Sources */, DABE05032A0A80FE00722F6F /* UserSecurity.swift in Sources */, @@ -1425,6 +1429,7 @@ CURRENT_PROJECT_VERSION = 17; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"Swiftcord/Preview Content\""; + DEVELOPMENT_TEAM = KYZSZP83JV; DEVELOPMENT_TEAM = Q382QLKDG3; ENABLE_APP_SANDBOX = YES; ENABLE_HARDENED_RUNTIME = YES; @@ -1689,6 +1694,7 @@ CURRENT_PROJECT_VERSION = 17; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"Swiftcord/Preview Content\""; + DEVELOPMENT_TEAM = KYZSZP83JV; DEVELOPMENT_TEAM = Q382QLKDG3; ENABLE_APP_SANDBOX = YES; ENABLE_HARDENED_RUNTIME = YES; diff --git a/Swiftcord/Views/Message/MessageRenderViews/ActionMessageView.swift b/Swiftcord/Views/Message/MessageRenderViews/ActionMessageView.swift index b023ebcc..643cd8b1 100644 --- a/Swiftcord/Views/Message/MessageRenderViews/ActionMessageView.swift +++ b/Swiftcord/Views/Message/MessageRenderViews/ActionMessageView.swift @@ -43,6 +43,12 @@ struct ActionMessageView: View { icon: "arrow.left", color: .red ) + case .chNameChange: + return ActionMessageData( + message: "**\(message.author.username)** just changed the channel name: **\(message.content)**.", + icon: "pencil", + color: .gray + ) case .userPremiumGuildSub: return ActionMessageData( message: "**\(message.author.username)** just boosted the server!", @@ -93,6 +99,24 @@ struct ActionMessageView: View { color: .red ) } + case .chPinnedMsg: + return ActionMessageData( + message: "**\(message.author.username)** just pinned a message to this channel.", + icon: "pin.fill", + color: .gray + ) + case .threadCreated: + return ActionMessageData( + message: "**\(message.author.username)** started a thread: **\(message.content)**.", + icon: "number", + color: .gray + ) + case .chFollowAdd: + return ActionMessageData( + message: "**\(message.author.username)** has added **\(message.content)** to this channel. Its most important updates will show up here.", + icon: "arrow.right", + color: .green + ) default: return ActionMessageData( message: "Oops, rendering `\(String(describing: message.type))` messages aren't supported yet :(", diff --git a/Swiftcord/Views/Message/MessageRenderViews/CommandMessageView.swift b/Swiftcord/Views/Message/MessageRenderViews/CommandMessageView.swift new file mode 100644 index 00000000..289ced43 --- /dev/null +++ b/Swiftcord/Views/Message/MessageRenderViews/CommandMessageView.swift @@ -0,0 +1,57 @@ +// +// CommandMessageView.swift +// Swiftcord +// +// Created by King Fish on 6/30/23. +// + +import SwiftUI +import DiscordKitCore + +/// For rendering chat commands +struct CommandMessageView: View { + let message: Message + + @EnvironmentObject var serverCtx: ServerContext + + var body: some View { + HStack(alignment: .top, spacing: 4) { + RoundedRectangle(cornerRadius: 5) + .trim(from: 0.5, to: 0.75) + .stroke(.gray.opacity(0.4), lineWidth: 2) + .frame(width: 60, height: 20) + .padding(.top, 8) + .padding(.bottom, -12) + .padding(.trailing, -30) + + if let interaction = message.interaction { + Group { + UserAvatarView( + user: interaction.user, + guildID: serverCtx.guild?.id, + webhookID: nil, + size: 16 + ) + + Group { + Text("\(interaction.user.username) used") + .font(.system(size: 14)) + .opacity(0.9) + + if message.type == .chatInputCmd { + Text("/\(interaction.name)") + .font(.system(size: 14)) + .foregroundColor(.accentColor) + } else if message.type == .contextMenuCmd { + Text(interaction.name) + .font(.system(size: 14)) + .foregroundColor(.accentColor) + } + } + } + } + Spacer() + } + .padding(.leading, 20) + } +} diff --git a/Swiftcord/Views/Message/MessageRenderViews/MessageView.swift b/Swiftcord/Views/Message/MessageRenderViews/MessageView.swift index a452c7e7..720dec68 100644 --- a/Swiftcord/Views/Message/MessageRenderViews/MessageView.swift +++ b/Swiftcord/Views/Message/MessageRenderViews/MessageView.swift @@ -59,7 +59,8 @@ struct MessageView: View, Equatable { static let lineSpacing: CGFloat = 4 // Messages that can be rendered as "default" messages - static let defaultTypes: [MessageType] = [.defaultMsg, .reply] + static let defaultTypes: [MessageType] = [.defaultMsg, .reply, .chatInputCmd, .contextMenuCmd] + static let commandTypes: [MessageType] = [.chatInputCmd, .contextMenuCmd] var body: some View { VStack(alignment: .leading, spacing: 6) { @@ -71,6 +72,9 @@ struct MessageView: View, Equatable { } } } + if MessageView.commandTypes.contains(message.type) { + CommandMessageView(message: message) + } HStack( alignment: MessageView.defaultTypes.contains(message.type) ? .top : .center, spacing: 16 @@ -95,7 +99,7 @@ struct MessageView: View, Equatable { // just try both to see which is present NonUserBadge( flags: message.author.flags ?? message.author.public_flags, - isWebhook: message.webhook_id != nil + isWebhook: message.webhook_id != nil && !MessageView.commandTypes.contains(message.type) ) } HStack(spacing: 0) { diff --git a/Swiftcord/Views/Message/MessageRenderViews/ReferenceMessageView.swift b/Swiftcord/Views/Message/MessageRenderViews/ReferenceMessageView.swift index 6ca1d27e..24d7c62d 100644 --- a/Swiftcord/Views/Message/MessageRenderViews/ReferenceMessageView.swift +++ b/Swiftcord/Views/Message/MessageRenderViews/ReferenceMessageView.swift @@ -43,7 +43,7 @@ struct ReferenceMessageView: View { if quotedMsg.author.bot == true || quotedMsg.webhook_id != nil { NonUserBadge( flags: quotedMsg.author.public_flags, - isWebhook: quotedMsg.webhook_id != nil + isWebhook: quotedMsg.webhook_id != nil && !MessageView.commandTypes.contains(quotedMsg.type) ) } @@ -51,14 +51,21 @@ struct ReferenceMessageView: View { .font(.system(size: 14)) .opacity(0.75) .lineLimit(1) - if quotedMsg.content.isEmpty { - Text("message.reply.attachment") + + if MessageView.commandTypes.contains(quotedMsg.type) { + Text("message.reply.command") .font(.system(size: 14).italic()) .opacity(0.75) - } - - if !quotedMsg.attachments.isEmpty || !quotedMsg.embeds.isEmpty { - Image(systemName: "photo.fill").font(.system(size: 16)).opacity(0.75) + Image(systemName: "slash.circle.fill").font(.system(size: 16)).opacity(0.75) + } else { + if quotedMsg.content.isEmpty { + Text("message.reply.attachment") + .font(.system(size: 14).italic()) + .opacity(0.75) + } + if !quotedMsg.attachments.isEmpty || !quotedMsg.embeds.isEmpty { + Image(systemName: "photo.fill").font(.system(size: 16)).opacity(0.75) + } } } } else { diff --git a/Swiftcord/en.lproj/Localizable.strings b/Swiftcord/en.lproj/Localizable.strings index acfe5898..3b2637b2 100644 --- a/Swiftcord/en.lproj/Localizable.strings +++ b/Swiftcord/en.lproj/Localizable.strings @@ -43,6 +43,7 @@ "message.edited" = " • Edited: "; "message.gone" = "Original message was deleted."; "message.reply.attachment" = "Click to see attachment"; +"message.reply.command" = "Click to see command"; /* ====== Server ====== */ "server.noChannels.header" = "No Text Channels";