From 3f5336925f56c074012eaccfede43021c6d1f98d Mon Sep 17 00:00:00 2001 From: evelyneee Date: Tue, 17 May 2022 20:03:10 -0400 Subject: [PATCH] fix: main thread checking ref: serverlistview modularizing --- .periphery.yml | 5 ++ Accord.xcodeproj/project.pbxproj | 8 +++ Accord/App/AccordApp.swift | 66 ++++++++++-------- Accord/Backend/Markdown/AsyncMarkdown.swift | 2 +- Accord/Backend/RPC/MediaRemoteWrapper.swift | 2 +- Accord/Misc/PlusPlus/Extensions.swift | 5 ++ Accord/Objects/DiscordTypes/ReadState.swift | 4 +- Accord/UI/Base/DMButton.swift | 60 ++++++++++++++++ Accord/UI/Base/FolderListView.swift | 18 ++--- Accord/UI/Base/PrivateChannelsView.swift | 59 ++++++++++++++++ Accord/UI/Base/ServerListView+Mentions.swift | 4 +- Accord/UI/Base/ServerListView.swift | 68 +++---------------- .../ChannelView/ChannelViewViewModel.swift | 10 +-- .../UI/Chat/ChannelView/MessageCellView.swift | 8 +-- .../UI/Chat/TextField/ChatControlsView.swift | 3 - .../TextField/ChatControlsViewModel.swift | 6 ++ Accord/UI/Profile/SettingsView.swift | 5 +- 17 files changed, 212 insertions(+), 121 deletions(-) create mode 100644 .periphery.yml create mode 100644 Accord/UI/Base/DMButton.swift create mode 100644 Accord/UI/Base/PrivateChannelsView.swift diff --git a/.periphery.yml b/.periphery.yml new file mode 100644 index 00000000..8503570e --- /dev/null +++ b/.periphery.yml @@ -0,0 +1,5 @@ +project: Accord.xcodeproj +schemes: +- Accord +targets: +- Accord diff --git a/Accord.xcodeproj/project.pbxproj b/Accord.xcodeproj/project.pbxproj index a8b57daa..86a3d867 100644 --- a/Accord.xcodeproj/project.pbxproj +++ b/Accord.xcodeproj/project.pbxproj @@ -46,6 +46,8 @@ 9E8F8CA82774037F00A77600 /* MentionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E8F8CA72774037F00A77600 /* MentionsView.swift */; }; 9E96EB7A27DEC33D00BB3C8A /* Gateway+VoiceState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E96EB7927DEC33D00BB3C8A /* Gateway+VoiceState.swift */; }; 9EA295212753D1490014927D /* MemberList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA295202753D1480014927D /* MemberList.swift */; }; + 9EB3303828344929007D38EF /* PrivateChannelsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB3303728344929007D38EF /* PrivateChannelsView.swift */; }; + 9EB3303A28344A10007D38EF /* DMButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB3303928344A10007D38EF /* DMButton.swift */; }; 9EB3582427BFFD3E0046A136 /* Collection++.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB3582327BFFD3E0046A136 /* Collection++.swift */; }; 9ECB0F3F2766D3DA0019ADAE /* MessageCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9ECB0F3E2766D3DA0019ADAE /* MessageCellView.swift */; }; 9ECE08F5277286E3001BA0F7 /* PinsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9ECE08F4277286E3001BA0F7 /* PinsView.swift */; }; @@ -171,6 +173,8 @@ 9E8F8CA72774037F00A77600 /* MentionsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MentionsView.swift; sourceTree = ""; }; 9E96EB7927DEC33D00BB3C8A /* Gateway+VoiceState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Gateway+VoiceState.swift"; sourceTree = ""; }; 9EA295202753D1480014927D /* MemberList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberList.swift; sourceTree = ""; }; + 9EB3303728344929007D38EF /* PrivateChannelsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateChannelsView.swift; sourceTree = ""; }; + 9EB3303928344A10007D38EF /* DMButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DMButton.swift; sourceTree = ""; }; 9EB3582327BFFD3E0046A136 /* Collection++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection++.swift"; sourceTree = ""; }; 9ECB0F3E2766D3DA0019ADAE /* MessageCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageCellView.swift; sourceTree = ""; }; 9ECE08F4277286E3001BA0F7 /* PinsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinsView.swift; sourceTree = ""; }; @@ -539,6 +543,8 @@ 370AF4112834504C0055AA1D /* JoinServerSheetView.swift */, 9E82874E27BB522600953A7B /* ServerListView+Init.swift */, 9E3B48DA280C348E00B131B7 /* ServerListViewCell.swift */, + 9EB3303728344929007D38EF /* PrivateChannelsView.swift */, + 9EB3303928344A10007D38EF /* DMButton.swift */, ); path = Base; sourceTree = ""; @@ -715,6 +721,7 @@ A82A062426D98259007B9B27 /* ReadState.swift in Sources */, A8B1F29826CB166C00E8FDC5 /* Events.swift in Sources */, A89BE786266BDFB3007B0CBF /* Socket.swift in Sources */, + 9EB3303828344929007D38EF /* PrivateChannelsView.swift in Sources */, 9E7834D22781F2D500ABB9F8 /* Combine++.swift in Sources */, A8C73D1226F5812D00CF0350 /* Songlink.swift in Sources */, 9E7BC56D27472317008E3FAB /* Markdown.swift in Sources */, @@ -781,6 +788,7 @@ A8CD4CA5267D27F300E2C4F1 /* ServerListView.swift in Sources */, 9EB3582427BFFD3E0046A136 /* Collection++.swift in Sources */, 9E7E4D30279B69D7008FAF15 /* Storage.swift in Sources */, + 9EB3303A28344A10007D38EF /* DMButton.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Accord/App/AccordApp.swift b/Accord/App/AccordApp.swift index 518e8931..11efb408 100644 --- a/Accord/App/AccordApp.swift +++ b/Accord/App/AccordApp.swift @@ -10,7 +10,22 @@ import Foundation import SwiftUI import UserNotifications -var reachability: Reachability? +var reachability: Reachability? = { + var reachability = try? Reachability() + reachability?.whenReachable = { status in + print("reconnecting reachable") + concurrentQueue.async { + if wss?.connection?.state != .preparing { + wss?.reset() + } + } + } + reachability?.whenUnreachable = { + print($0, "unreachable") + } + try? reachability?.startNotifier() + return reachability +}() @main struct AccordApp: App { @@ -23,6 +38,10 @@ struct AccordApp: App { case general, rpc } + init() { + _ = reachability + } + @SceneBuilder var body: some Scene { WindowGroup { @@ -62,23 +81,24 @@ struct AccordApp: App { // DispatchQueue(label: "socket").async { // let rpc = IPC().start() // } - Request.fetch(url: URL(string: "https://accounts.spotify.com/api/token"), headers: Headers( - contentType: "application/x-www-form-urlencoded", - token: "Basic " + ("b5d5657a93c248a88b83c630a4488a78" + ":" + "faa98c11d92e493689fd797761bc1849").toBase64(), - bodyObject: ["grant_type":"client_credentials"], - type: .POST - )) { - switch $0 { - case .success(let data): - let packet = try? JSONSerialization.jsonObject(with: data, options: []) as? [String:Any] - if let token = packet?["access_token"] as? String { - spotifyToken = token + + DispatchQueue.global().async { + Request.fetch(url: URL(string: "https://accounts.spotify.com/api/token"), headers: Headers( + contentType: "application/x-www-form-urlencoded", + token: "Basic " + ("b5d5657a93c248a88b83c630a4488a78" + ":" + "faa98c11d92e493689fd797761bc1849").toBase64(), + bodyObject: ["grant_type":"client_credentials"], + type: .POST + )) { + switch $0 { + case .success(let data): + let packet = try? JSONSerialization.jsonObject(with: data, options: []) as? [String:Any] + if let token = packet?["access_token"] as? String { + spotifyToken = token + } + case .failure(let error): + print(error) } - case .failure(let error): - print(error) } - } - DispatchQueue.global().async { NetworkCore.shared = NetworkCore() } DispatchQueue.global(qos: .background).async { @@ -176,18 +196,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } func applicationDidFinishLaunching(_: Notification) { - - reachability = try? Reachability() - reachability?.whenReachable = { status in - print("reconnecting reachable") - concurrentQueue.async { - wss?.reset() - } - } - reachability?.whenUnreachable = { - print($0, "unreachable") - } - try? reachability?.startNotifier() + NSApp.dockTile.badgeLabel = nil + NSApp.dockTile.showsApplicationBadge = false guard UserDefaults.standard.bool(forKey: "MentionsMenuBarItemEnabled") else { return } diff --git a/Accord/Backend/Markdown/AsyncMarkdown.swift b/Accord/Backend/Markdown/AsyncMarkdown.swift index 64e18429..15fba1c7 100644 --- a/Accord/Backend/Markdown/AsyncMarkdown.swift +++ b/Accord/Backend/Markdown/AsyncMarkdown.swift @@ -49,7 +49,7 @@ extension View { struct AsyncMarkdown: View, Equatable { static func == (_ lhs: AsyncMarkdown, _ rhs: AsyncMarkdown) -> Bool { - lhs.model.markdown == rhs.model.markdown + lhs.text == rhs.text } @StateObject var model: AsyncMarkdownModel diff --git a/Accord/Backend/RPC/MediaRemoteWrapper.swift b/Accord/Backend/RPC/MediaRemoteWrapper.swift index 12f84495..9cc0f262 100644 --- a/Accord/Backend/RPC/MediaRemoteWrapper.swift +++ b/Accord/Backend/RPC/MediaRemoteWrapper.swift @@ -147,7 +147,7 @@ final class MediaRemoteWrapper { class func getCurrentlyPlayingSong() -> Future { Future { promise in // Get song info - MRMediaRemoteGetNowPlayingInfo(DispatchQueue.main) { information in + MRMediaRemoteGetNowPlayingInfo(DispatchQueue.global()) { information in guard let name = information["kMRMediaRemoteNowPlayingInfoTitle"] as? String else { return promise(.failure(NowPlayingErrors.noName)) } let isMusic = information["kMRMediaRemoteNowPlayingInfoIsMusicApp"] as? Bool ?? false let timestamp = information["kMRMediaRemoteNowPlayingInfoTimestamp"] as? String diff --git a/Accord/Misc/PlusPlus/Extensions.swift b/Accord/Misc/PlusPlus/Extensions.swift index 1b64a02b..0cf125ac 100644 --- a/Accord/Misc/PlusPlus/Extensions.swift +++ b/Accord/Misc/PlusPlus/Extensions.swift @@ -10,6 +10,11 @@ import Combine import Foundation import SwiftUI +// thanks osy +extension String: Error { + var localizedString: String { self } +} + public var doNothing: (Any) -> Void = { _ in } @propertyWrapper diff --git a/Accord/Objects/DiscordTypes/ReadState.swift b/Accord/Objects/DiscordTypes/ReadState.swift index ab961748..8b370099 100644 --- a/Accord/Objects/DiscordTypes/ReadState.swift +++ b/Accord/Objects/DiscordTypes/ReadState.swift @@ -15,8 +15,8 @@ class ReadState: Decodable { } class ReadStateEntry: Decodable, Identifiable { - var mention_count: Int - var last_pin_timestamp: String + var mention_count: Int? + var last_pin_timestamp: String? var last_message_id: String? var id: String // Channel ID } diff --git a/Accord/UI/Base/DMButton.swift b/Accord/UI/Base/DMButton.swift new file mode 100644 index 00000000..cb7ad9a6 --- /dev/null +++ b/Accord/UI/Base/DMButton.swift @@ -0,0 +1,60 @@ +// +// DMButton.swift +// Accord +// +// Created by evelyn on 2022-05-17. +// + +import SwiftUI + +struct DMButton: View { + @Binding var selection: Int? + @Binding var selectedServer: Int? + @StateObject var updater: ServerListView.UpdateView + @State var mentionCount: Int? + @State var iconHovered: Bool = false + var body: some View { + ZStack(alignment: .bottomTrailing) { + Button(action: { + selection = nil + DispatchQueue.global().async { + wss?.cachedMemberRequest.removeAll() + ServerListView.privateChannels = ServerListView.privateChannels.sorted(by: { $0.last_message_id ?? "" > $1.last_message_id ?? "" }) + } + selectedServer = 201 + let prevSelection = selection + if let selectionPrevious = UserDefaults.standard.object(forKey: "AccordChannelDMs") as? Int { + self.selection = selectionPrevious + } + if let selection = prevSelection { + UserDefaults.standard.set(selection, forKey: "AccordChannelDMs") + } + }) { + Image(systemName: "bubble.right.fill") + .imageScale(.medium) + .frame(width: 45, height: 45) + .background(selectedServer == 201 ? Color.accentColor.opacity(0.5) : Color(NSColor.windowBackgroundColor)) + .cornerRadius(iconHovered || selectedServer == 201 ? 13.5 : 23.5) + .if(selectedServer == 201, transform: { $0.foregroundColor(Color.white) }) + .onHover(perform: { h in withAnimation(Animation.linear(duration: 0.1)) { self.iconHovered = h } }) + } + if let mentionCount = mentionCount, mentionCount != 0 { + ZStack { + Circle() + .foregroundColor(Color.red) + .frame(width: 15, height: 15) + Text(String(mentionCount)) + .foregroundColor(Color.white) + .fontWeight(.semibold) + .font(.caption) + } + } + } + .buttonStyle(BorderlessButtonStyle()) + .onReceive(self.updater.$updater, perform: { _ in + DispatchQueue.global().async { + self.mentionCount = ServerListView.privateChannels.compactMap({ $0.read_state?.mention_count }).reduce(0, +) + } + }) + } +} diff --git a/Accord/UI/Base/FolderListView.swift b/Accord/UI/Base/FolderListView.swift index c503a5c5..ca146784 100644 --- a/Accord/UI/Base/FolderListView.swift +++ b/Accord/UI/Base/FolderListView.swift @@ -62,28 +62,22 @@ struct ServerIconCell: View { func updateSelection(old: Int?, new: Int?) { DispatchQueue.global().async { - if old == 201 { - if let selection = selection { - UserDefaults.standard.set(selection, forKey: "AccordChannelDMs") - } + if let selection = selection, old == 201 { + UserDefaults.standard.set(selection, forKey: "AccordChannelDMs") } - let map = Array(ServerListView.folders.compactMap { $0.guilds }.joined()) - guard let selectedServer = old, - let new = new, - let newID = map[safe: new]?.id else { - DispatchQueue.main.async { + guard let new = new else { + return DispatchQueue.main.async { self.selectedServer = new self.selectedGuild = guild } - return } - if let selection = selection, let id = map[safe: selectedServer]?.id { + if let selection = selection, let id = selectedGuild?.id { UserDefaults.standard.set(selection, forKey: "AccordChannelIn\(id)") } DispatchQueue.main.async { self.selection = nil withAnimation(old == 201 ? nil : Animation.linear(duration: 0.1)) { - if let value = UserDefaults.standard.object(forKey: "AccordChannelIn\(newID)") as? Int { + if let value = UserDefaults.standard.object(forKey: "AccordChannelIn\(guild.id)") as? Int { self.selection = value self.selectedGuild = guild self.selectedServer = new diff --git a/Accord/UI/Base/PrivateChannelsView.swift b/Accord/UI/Base/PrivateChannelsView.swift new file mode 100644 index 00000000..955e50a7 --- /dev/null +++ b/Accord/UI/Base/PrivateChannelsView.swift @@ -0,0 +1,59 @@ +// +// PrivateChannelsView.swift +// Accord +// +// Created by evelyn on 2022-05-17. +// + +import SwiftUI + +struct PrivateChannelsView: View { + var privateChannels: [Channel] + @Binding var selection: Int? + @StateObject var viewUpdater: ServerListView.UpdateView + var body: some View { + ForEach(privateChannels, id: \.id) { channel in + NavigationLink(destination: NavigationLazyView(ChannelView(channel).equatable()), tag: Int(channel.id) ?? 0, selection: self.$selection) { + ServerListViewCell(channel: channel, updater: self.viewUpdater) + .onChange(of: self.selection, perform: { [selection] new in + if new == Int(channel.id) { + channel.read_state?.mention_count = 0 + channel.read_state?.last_message_id = channel.last_message_id + viewUpdater.updateView() + } else if selection == Int(channel.id) { + print("wow") + channel.read_state?.mention_count = 0 + channel.read_state?.last_message_id = channel.last_message_id + } + }) + } + .contextMenu { + Button("Copy Channel ID") { + NSPasteboard.general.clearContents() + NSPasteboard.general.setString(channel.id, forType: .string) + } + Button("Close DM") { + let headers = Headers( + userAgent: discordUserAgent, + contentType: nil, + token: AccordCoreVars.token, + type: .DELETE, + discordHeaders: true, + referer: "https://discord.com/channels/@me", + empty: true + ) + Request.ping(url: URL(string: "\(rootURL)/channels/\(channel.id)"), headers: headers) + guard let index = ServerListView.privateChannels[indexOf: channel.id] else { return } + ServerListView.privateChannels.remove(at: index) + } + Button("Mark as read") { + channel.read_state?.mention_count = 0 + channel.read_state?.last_message_id = channel.last_message_id + } + Button("Open in new window") { + showWindow(channel) + } + } + } + } +} diff --git a/Accord/UI/Base/ServerListView+Mentions.swift b/Accord/UI/Base/ServerListView+Mentions.swift index 30c436d8..71afc10b 100644 --- a/Accord/UI/Base/ServerListView+Mentions.swift +++ b/Accord/UI/Base/ServerListView+Mentions.swift @@ -13,7 +13,7 @@ extension ServerListView: MentionSenderDelegate { if guild == "@me" { guard channel != String(self.selection ?? 0) else { print("currently reading already"); return } guard let index = Self.privateChannels.generateKeyMap()[channel] else { return } - Self.privateChannels[index].read_state?.mention_count += 1 + Self.privateChannels[index].read_state?.mention_count? += 1 } guard channel != String(self.selection ?? 0) else { print("currently reading already"); return } let index = Self.folders.map { ServerListView.fastIndexGuild(guild, array: $0.guilds) } @@ -21,7 +21,7 @@ extension ServerListView: MentionSenderDelegate { guard let v = v, var folderList = Self.folders[i].guilds[v].channels else { continue } folderList.append(contentsOf: Self.privateChannels) if let index = fastIndexChannels(channel, array: folderList) { - Self.folders[i].guilds[v].channels?[index].read_state?.mention_count += 1 + Self.folders[i].guilds[v].channels?[index].read_state?.mention_count? += 1 } } DispatchQueue.main.async { diff --git a/Accord/UI/Base/ServerListView.swift b/Accord/UI/Base/ServerListView.swift index b2eec51c..934e17a8 100644 --- a/Accord/UI/Base/ServerListView.swift +++ b/Accord/UI/Base/ServerListView.swift @@ -186,21 +186,11 @@ struct ServerListView: View { onlineButton .buttonStyle(BorderlessButtonStyle()) } - ZStack(alignment: .bottomTrailing) { - dmButton - if let count = Self.privateChannels.compactMap({ $0.read_state?.mention_count }).reduce(0, +), count != 0 { - ZStack { - Circle() - .foregroundColor(Color.red) - .frame(width: 15, height: 15) - Text(String(count)) - .foregroundColor(Color.white) - .fontWeight(.semibold) - .font(.caption) - } - } - } - .buttonStyle(BorderlessButtonStyle()) + DMButton( + selection: self.$selection, + selectedServer: self.$selectedServer, + updater: self.viewUpdater + ) Color.gray .frame(height: 1) .opacity(0.75) @@ -227,49 +217,11 @@ struct ServerListView: View { List { settingsLink Divider() - ForEach(Self.privateChannels, id: \.id) { channel in - NavigationLink(destination: NavigationLazyView(ChannelView(channel).equatable()), tag: Int(channel.id) ?? 0, selection: self.$selection) { - ServerListViewCell(channel: channel, updater: self.viewUpdater) - .onChange(of: self.selection, perform: { [selection] new in - if new == Int(channel.id) { - channel.read_state?.mention_count = 0 - channel.read_state?.last_message_id = channel.last_message_id - viewUpdater.updateView() - } else if selection == Int(channel.id) { - print("wow") - channel.read_state?.mention_count = 0 - channel.read_state?.last_message_id = channel.last_message_id - } - }) - } - .contextMenu { - Button("Copy Channel ID") { - NSPasteboard.general.clearContents() - NSPasteboard.general.setString(channel.id, forType: .string) - } - Button("Close DM") { - let headers = Headers( - userAgent: discordUserAgent, - contentType: nil, - token: AccordCoreVars.token, - type: .DELETE, - discordHeaders: true, - referer: "https://discord.com/channels/@me", - empty: true - ) - Request.ping(url: URL(string: "\(rootURL)/channels/\(channel.id)"), headers: headers) - guard let index = ServerListView.privateChannels[indexOf: channel.id] else { return } - ServerListView.privateChannels.remove(at: index) - } - Button("Mark as read") { - channel.read_state?.mention_count = 0 - channel.read_state?.last_message_id = channel.last_message_id - } - Button("Open in new window") { - showWindow(channel) - } - } - } + PrivateChannelsView( + privateChannels: Self.privateChannels, + selection: self.$selection, + viewUpdater: self.viewUpdater + ) } .padding(.top, 5) .listStyle(.sidebar) diff --git a/Accord/UI/Chat/ChannelView/ChannelViewViewModel.swift b/Accord/UI/Chat/ChannelView/ChannelViewViewModel.swift index ca962992..041eb398 100644 --- a/Accord/UI/Chat/ChannelView/ChannelViewViewModel.swift +++ b/Accord/UI/Chat/ChannelView/ChannelViewViewModel.swift @@ -35,9 +35,9 @@ final class ChannelViewViewModel: ObservableObject, Equatable { } else { try? wss.subscribe(to: guildID) } + self.getMessages(channelID: channelID, guildID: guildID) MentionSender.shared.removeMentions(server: guildID) } - getMessages(channelID: channelID, guildID: guildID) connect() } @@ -64,7 +64,7 @@ final class ChannelViewViewModel: ObservableObject, Equatable { } guard let author = message.author else { return } Storage.usernames[author.id] = author.username - withAnimation { + withAnimation(Animation.linear(duration: 0.1)) { self?.messages.insert(message, at: 0) } } @@ -109,7 +109,7 @@ final class ChannelViewViewModel: ObservableObject, Equatable { guard let message = gatewayMessage.d else { return } guard let index = messageMap?[message.id] else { return } DispatchQueue.main.async { - withAnimation { + withAnimation(Animation.linear(duration: 0.1)) { let i: Int = index self?.messages.remove(at: i) } @@ -311,10 +311,6 @@ final class ChannelViewViewModel: ObservableObject, Equatable { } .store(in: &cancellable) } - - deinit { - SlashCommandStorage.commands[guildID]?.removeAll() - } } extension Array where Array.Element: Hashable { diff --git a/Accord/UI/Chat/ChannelView/MessageCellView.swift b/Accord/UI/Chat/ChannelView/MessageCellView.swift index dab5e76c..b342b77a 100644 --- a/Accord/UI/Chat/ChannelView/MessageCellView.swift +++ b/Accord/UI/Chat/ChannelView/MessageCellView.swift @@ -34,8 +34,6 @@ struct MessageCellView: View, Equatable { @Binding var replyingTo: Message? @State var editing: Bool = false @State var popup: Bool = false - @State var textElement: Text? - @State var bag = Set() @State var editedText: String = "" @AppStorage("GifProfilePictures") @@ -126,15 +124,15 @@ struct MessageCellView: View, Equatable { .font(.chatTextFont) .fontWeight(.semibold) + - Text(" \(message.processedTimestamp ?? "")") + Text(" \(message.processedTimestamp ?? "")") .foregroundColor(Color.secondary) .font(.subheadline) + - Text(message.edited_timestamp != nil ? " (edited at \(message.edited_timestamp?.makeProperHour() ?? "unknown time"))" : "") + Text(message.edited_timestamp != nil ? " (edited at \(message.edited_timestamp?.makeProperHour() ?? "unknown time"))" : "") .foregroundColor(Color.secondary) .font(.subheadline) + - Text((pronouns != nil) ? " • \(pronouns ?? "Use my name")" : "") + Text((pronouns != nil) ? " • \(pronouns ?? "Use my name")" : "") .foregroundColor(Color.secondary) .font(.subheadline) if message.author?.bot == true { diff --git a/Accord/UI/Chat/TextField/ChatControlsView.swift b/Accord/UI/Chat/TextField/ChatControlsView.swift index 88b36521..ad9db3ea 100644 --- a/Accord/UI/Chat/TextField/ChatControlsView.swift +++ b/Accord/UI/Chat/TextField/ChatControlsView.swift @@ -336,9 +336,6 @@ struct ChatControls: View { } } } - .onAppear { - viewModel.findView() - } .textFieldStyle(PlainTextFieldStyle()) .fileImporter(isPresented: $fileImport, allowedContentTypes: [.data]) { result in fileUpload = try! Data(contentsOf: try! result.get()) diff --git a/Accord/UI/Chat/TextField/ChatControlsViewModel.swift b/Accord/UI/Chat/TextField/ChatControlsViewModel.swift index 2ca68b6d..d12a30ae 100644 --- a/Accord/UI/Chat/TextField/ChatControlsViewModel.swift +++ b/Accord/UI/Chat/TextField/ChatControlsViewModel.swift @@ -30,6 +30,12 @@ final class ChatControlsViewModel: ObservableObject { var locked: Bool = false var runOnUnlock: (() -> Void)? + init() { + DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: { + self.findView() + }) + } + func checkText(guildID: String, channelID: String) { let mentions = textFieldContents.matches(precomputed: Regex.chatTextMentionsRegex) let channels = textFieldContents.matches(precomputed: Regex.chatTextChannelsRegex) diff --git a/Accord/UI/Profile/SettingsView.swift b/Accord/UI/Profile/SettingsView.swift index 9c6ccbad..d77211c0 100644 --- a/Accord/UI/Profile/SettingsView.swift +++ b/Accord/UI/Profile/SettingsView.swift @@ -40,7 +40,7 @@ struct SettingsView: View { SettingsToggleView(key: "MetalRenderer", title: "Enable the Metal Renderer for the chat view", detail: "Experimental") SettingsToggleView(key: "GifProfilePictures", title: "Enable Gif Profile Pictures", detail: "Experimental") SettingsToggleView(key: "ShowHiddenChannels", title: "Show hidden channels", detail: "Please don't use this") - SettingsToggleView(key: "CompressGateway", title: "Enable Gateway Stream Compression", detail: "Recommended") + SettingsToggleView(key: "CompressGateway", title: "Enable Gateway Stream Compression", detail: "Recommended", defaultToggle: true) } HStack(alignment: .top) { @@ -129,6 +129,7 @@ struct SettingsToggleView: View { var key: String var title: String var detail: String? + var defaultToggle: Bool? @State var toggled: Bool = false var body: some View { HStack { @@ -149,7 +150,7 @@ struct SettingsToggleView: View { }) .padding() .onAppear { - self.toggled = UserDefaults.standard.bool(forKey: self.key) + self.toggled = UserDefaults.standard.object(forKey: self.key) as? Bool ?? defaultToggle ?? false } } }