Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drag'n'drop to attach files #52

Merged
merged 4 commits into from
May 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Swiftcord.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
DA54D5762844B9C500B11857 /* CurrentUser+.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA54D5752844B9C500B11857 /* CurrentUser+.swift */; };
DA54D5782844DA1400B11857 /* UserSettingsProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA54D5772844DA1400B11857 /* UserSettingsProfileView.swift */; };
DA54D57A2844E41A00B11857 /* ProfileBadges.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA54D5792844E41A00B11857 /* ProfileBadges.swift */; };
DA54D57C2845C36E00B11857 /* MessagesView+.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA54D57B2845C36E00B11857 /* MessagesView+.swift */; };
DA57F44428056718001DC46E /* ChannelList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA57F44328056718001DC46E /* ChannelList.swift */; };
DA57F44628065209001DC46E /* ChannelButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA57F44528065209001DC46E /* ChannelButton.swift */; };
DA585C9927E1F6AC00FA4EE0 /* View+.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA585C9827E1F6AC00FA4EE0 /* View+.swift */; };
Expand Down Expand Up @@ -142,6 +143,7 @@
DA54D5752844B9C500B11857 /* CurrentUser+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CurrentUser+.swift"; sourceTree = "<group>"; };
DA54D5772844DA1400B11857 /* UserSettingsProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsProfileView.swift; sourceTree = "<group>"; };
DA54D5792844E41A00B11857 /* ProfileBadges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileBadges.swift; sourceTree = "<group>"; };
DA54D57B2845C36E00B11857 /* MessagesView+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessagesView+.swift"; sourceTree = "<group>"; };
DA57F44328056718001DC46E /* ChannelList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelList.swift; sourceTree = "<group>"; };
DA57F44528065209001DC46E /* ChannelButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelButton.swift; sourceTree = "<group>"; };
DA585C9827E1F6AC00FA4EE0 /* View+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -360,6 +362,7 @@
E7AF1C35282FC2E8001F78DF /* NSTextView+.swift */,
DA520ACA27D4A23A009FD740 /* String+.swift */,
DA585C9827E1F6AC00FA4EE0 /* View+.swift */,
DA54D57B2845C36E00B11857 /* MessagesView+.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -629,6 +632,7 @@
DA32EF5027C8D7E000A9ED72 /* Message+.swift in Sources */,
DAAFB5C5282AB37500807B54 /* MediaControllerView.swift in Sources */,
DAAFB5CC282B879200807B54 /* Double+.swift in Sources */,
DA54D57C2845C36E00B11857 /* MessagesView+.swift in Sources */,
DA520AC927D3A55D009FD740 /* SettingsView.swift in Sources */,
DA32EF2827C633FE00A9ED72 /* UserAvatarView.swift in Sources */,
DA585C9927E1F6AC00FA4EE0 /* View+.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"location" : "https://github.com/SwiftcordApp/DiscordKit",
"state" : {
"branch" : "main",
"revision" : "ab5add39584f2cd1304ad08675422d294b11067e"
"revision" : "c32383146fc45e6917a4e3b646efba1e0622240d"
}
},
{
Expand Down
6 changes: 5 additions & 1 deletion Swiftcord/SwiftcordApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import DiscordKit
import SwiftUI

@main
struct SwiftcordApp: App {
struct SwiftcordApp: App, Equatable {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
let persistenceController = PersistenceController.shared
@StateObject var updaterViewModel = UpdaterViewModel()
Expand Down Expand Up @@ -42,4 +42,8 @@ struct SwiftcordApp: App {
.environmentObject(state)
}
}

static func == (lhs: SwiftcordApp, rhs: SwiftcordApp) -> Bool {
lhs.gateway == rhs.gateway && lhs.state == rhs.state
}
}
102 changes: 102 additions & 0 deletions Swiftcord/Utils/Extensions/MessagesView+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//
// MessagesView+.swift
// Swiftcord
//
// Created by Vincent Kwok on 31/5/22.
//

import Foundation
import DiscordKit

extension MessagesView {
internal func fetchMoreMessages() {
guard let channel = ctx.channel else { return }
if let oldTask = fetchMessagesTask {
oldTask.cancel()
fetchMessagesTask = nil
}

if loadError { showingInfoBar = false }
loadError = false

fetchMessagesTask = Task {
let lastMsg = messages.isEmpty ? nil : messages[messages.count - 1].id

guard let newMessages = await DiscordAPI.getChannelMsgs(
id: channel.id,
before: lastMsg
) else {
try Task.checkCancellation() // Check if the task is cancelled before continuing

fetchMessagesTask = nil
loadError = true
showingInfoBar = true
infoBarData = InfoBarData(
message: "Messages failed to load",
buttonLabel: "Try again",
color: .red,
buttonIcon: "arrow.clockwise",
clickHandler: { fetchMoreMessages() }
)
state.loadingState = .messageLoad
return
}
state.loadingState = .messageLoad
try Task.checkCancellation()

reachedTop = newMessages.count < 50
messages.append(contentsOf: newMessages)
fetchMessagesTask = nil
}
}

internal func sendMessage(with message: String, attachments: [URL]) {
lastSentTyping = Date(timeIntervalSince1970: 0)
newMessage = ""
showingInfoBar = false
Task {
guard (await DiscordAPI.createChannelMsg(
message: NewMessage(
content: message,
attachments: attachments.isEmpty ? nil : attachments.enumerated()
.map { (idx, attachment) in
NewAttachment(
id: String(idx),
filename: try! attachment.resourceValues(forKeys: [URLResourceKey.nameKey]).name!
)
}
),
attachments: attachments,
id: ctx.channel!.id
)) != nil else {
showingInfoBar = true
infoBarData = InfoBarData(
message: "Could not send message",
buttonLabel: "Try again",
color: .red,
buttonIcon: "arrow.clockwise",
clickHandler: { sendMessage(with: message, attachments: attachments) }
)
return
}
}
}

internal func preAttachChecks(for attachment: URL) -> Bool {
guard let size = try? attachment.resourceValues(forKeys: [URLResourceKey.fileSizeKey]).fileSize, size < 8*1024*1024 else {
newAttachmentErr = NewAttachmentError(
title: "Your files are too powerful",
message: "The max file size is 8MB."
)
return false
}
guard attachments.count <= 10 else {
newAttachmentErr = NewAttachmentError(
title: "Too many uploads!",
message: "You can only upload 10 files at a time!"
)
return false
}
return true
}
}
2 changes: 1 addition & 1 deletion Swiftcord/Views/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ struct ContentView: View {
}
_ = gateway.socket.onSessionInvalid.addHandler { state.loadingState = .initial }
}
}
}

/*private func addItem() {
withAnimation {
Expand Down
11 changes: 9 additions & 2 deletions Swiftcord/Views/EnvObjects/UIStateEnv.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,16 @@ enum LoadingState {
case messageLoad
}

class UIState: ObservableObject {
class UIState: ObservableObject, Equatable {
@Published var loadingState: LoadingState = .initial
@Published var attemptLogin = false
@Published var selfMute = false
@Published var selfDeaf = false
@Published var selfDeaf = false

static func == (lhs: UIState, rhs: UIState) -> Bool {
return lhs.loadingState == rhs.loadingState &&
lhs.attemptLogin == rhs.attemptLogin &&
lhs.selfMute == rhs.selfMute &&
lhs.selfDeaf == rhs.selfDeaf
}
}
5 changes: 4 additions & 1 deletion Swiftcord/Views/Message/AttachmentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ struct AttachmentView: View {
"application/json": "doc.text",
// Archives
"application/gzip": "doc.zipper",
"application/zip": "doc.zipper"
"application/zip": "doc.zipper",
// Videos
"video/mp4": "film",
"video/quicktime": "film"
]

/// Resizes image dimensions the way the official client does
Expand Down
24 changes: 7 additions & 17 deletions Swiftcord/Views/Message/MessageInputView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ struct MessageAttachmentView: View {
struct MessageInputView: View {
let placeholder: String
@Binding var message: String
@State private var attachments: [URL] = []
@Binding var attachments: [URL]
@State private var inhibitingSend = false
@State private var showingAttachmentErr = false
@State private var attachmentErr = ""
let onSend: (String, [URL]) -> Void
let preAttach: (URL) -> Bool

private func send() {
guard message.hasContent() || !attachments.isEmpty else { return }
Expand All @@ -72,6 +73,7 @@ struct MessageInputView: View {
HStack {
ForEach(attachments.indices, id: \.self) { idx in
MessageAttachmentView(attachment: attachments[idx]) {
guard idx < attachments.count else { return }
withAnimation { _ = attachments.remove(at: idx) }
}
}
Expand All @@ -86,26 +88,14 @@ struct MessageInputView: View {
panel.allowsMultipleSelection = false
panel.canChooseDirectories = false
panel.treatsFilePackagesAsDirectories = true
panel.beginSheetModal(for: NSApp.mainWindow!, completionHandler: { num in
panel.beginSheetModal(for: NSApp.mainWindow!) { num in
if num == NSApplication.ModalResponse.OK {
guard let size = try? panel.url?.resourceValues(forKeys: [URLResourceKey.fileSizeKey]).fileSize, size < 8*1024*1024 else {
attachmentErr = "That file's too huge! Choose something that's <= 8MiB."
showingAttachmentErr = true
return
}

guard !attachments.contains(panel.url!) else {
attachmentErr = "You've already selected that file"
showingAttachmentErr = true
return
if let fileURL = panel.url, preAttach(fileURL) {
withAnimation { attachments.append(fileURL) }
}
withAnimation { attachments.append(panel.url!) }
}
})
}
} label: { Image(systemName: "plus.circle.fill").font(.system(size: 20)).opacity(0.75) }
.alert(attachmentErr, isPresented: $showingAttachmentErr) {
Button("Got It!", role: .cancel) { }
}
.buttonStyle(.plain)
.padding(.leading, 18)

Expand Down
Loading