diff --git a/copinism.xcodeproj/project.pbxproj b/copinism.xcodeproj/project.pbxproj index 8d5afdd..23ab6ee 100644 --- a/copinism.xcodeproj/project.pbxproj +++ b/copinism.xcodeproj/project.pbxproj @@ -39,6 +39,7 @@ DE9C3A312C0E390200951DEE /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9C3A112C0E390200951DEE /* ContentView.swift */; }; DE9C3A322C0E390200951DEE /* copinismApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9C3A122C0E390200951DEE /* copinismApp.swift */; }; DE9C3A332C0E390200951DEE /* TestSwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9C3A132C0E390200951DEE /* TestSwiftUIView.swift */; }; + DE9C3A362C10AA8000951DEE /* MessageBack.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9C3A352C10AA8000951DEE /* MessageBack.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -78,6 +79,7 @@ DE9C3A122C0E390200951DEE /* copinismApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = copinismApp.swift; sourceTree = ""; }; DE9C3A132C0E390200951DEE /* TestSwiftUIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSwiftUIView.swift; sourceTree = ""; }; DE9C3A342C0E420400951DEE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + DE9C3A352C10AA8000951DEE /* MessageBack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageBack.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -124,6 +126,7 @@ DE9C39E62C0E390200951DEE /* Api.swift */, DE9C39E72C0E390200951DEE /* Req.swift */, DE9C39E82C0E390200951DEE /* Target.swift */, + DE9C3A352C10AA8000951DEE /* MessageBack.swift */, ); path = api; sourceTree = ""; @@ -420,6 +423,7 @@ DE9C3A292C0E390200951DEE /* Login.swift in Sources */, DE9C3A2E2C0E390200951DEE /* ShoppingView.swift in Sources */, DE9C3A2C2C0E390200951DEE /* TargetItamSwift.swift in Sources */, + DE9C3A362C10AA8000951DEE /* MessageBack.swift in Sources */, DE9C3A282C0E390200951DEE /* MessageView.swift in Sources */, DE9C3A1F2C0E390200951DEE /* ArticleCardView.swift in Sources */, DE9C3A182C0E390200951DEE /* TabbarView.swift in Sources */, diff --git a/copinism/Info.plist b/copinism/Info.plist index 7ea78b2..5721eef 100644 --- a/copinism/Info.plist +++ b/copinism/Info.plist @@ -4,6 +4,10 @@ CFBundleAllowMixedLocalizations + CFBundleLocalizations + + zh_CN + IDEPreferLogStreaming NSAppTransportSecurity diff --git a/copinism/Views/Message/MessageDetail.swift b/copinism/Views/Message/MessageDetail.swift index 484348b..a6af04c 100644 --- a/copinism/Views/Message/MessageDetail.swift +++ b/copinism/Views/Message/MessageDetail.swift @@ -1,25 +1,26 @@ - - import SwiftUI +import Alamofire struct Message: Identifiable { let id: UUID - let text: String - let sender: String - let timestamp: String - let isSelf: Bool - let avatar: String - let num: Int - - init(id: UUID = UUID(), text: String, sender: String, timestamp: String, isSelf: Bool, avatar: String, num: Int = 0) { - self.id = id - self.text = text - self.sender = sender - self.timestamp = timestamp - self.isSelf = isSelf - self.avatar = avatar - self.num = num - } + let text: String + let sender: String + let timestamp: String + let isSelf: Bool + let avatar: String + let num: Int + let image: UIImage? + + init(id: UUID = UUID(), text: String = "", sender: String, timestamp: String, isSelf: Bool, avatar: String, num: Int = 0, image: UIImage? = nil) { + self.id = id + self.text = text + self.sender = sender + self.timestamp = timestamp + self.isSelf = isSelf + self.avatar = avatar + self.num = num + self.image = image + } } struct MessageDetailView: View { @@ -31,6 +32,7 @@ struct MessageDetailView: View { @State private var selectedFileURL: URL? @State private var isImagePickerPresented = false @State private var isDocumentPickerPresented = false + @State private var uploadProgress: Double = 0.0 // 用于跟踪上传进度 @Environment(\.presentationMode) var presentationMode var body: some View { @@ -69,11 +71,49 @@ struct MessageDetailView: View { if !message.isSelf { Image("avatar") .CircleImage(size: 30) - TextBlackbble(message: message.text) + if let image = message.image { + ZStack { + Image(uiImage: image) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 200, height: 200) + .cornerRadius(10) + + if uploadProgress < 1.0 { + ProgressView(value: uploadProgress) + .progressViewStyle(CircularProgressViewStyle()) + .scaleEffect(2) + .frame(width: 50, height: 50) + .background(Color.white.opacity(0.7)) + .cornerRadius(25) + } + } + } else { + TextBlackbble(message: message.text) + } Spacer() } else { Spacer() - TextBubble(message: message.text) + if let image = message.image { + ZStack { + Image(uiImage: image) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 200, height: 200) + .cornerRadius(10) + + if uploadProgress < 1.0 { + ProgressView(value: uploadProgress) + .progressViewStyle(CircularProgressViewStyle()) + .scaleEffect(2) + .frame(width: 50, height: 50) + .background(Color.white.opacity(0.7)) + .cornerRadius(25) + } + } + } else { + TextBubble(message: message.text) + } Image("avatar") .CircleImage(size: 30) } @@ -88,7 +128,7 @@ struct MessageDetailView: View { HStack { Button(action: { - isDocumentPickerPresented = true + isImagePickerPresented = true }) { Image(systemName: "paperclip") .font(.system(size: 18)) @@ -120,7 +160,10 @@ struct MessageDetailView: View { .padding(.horizontal, 12) .padding(.bottom, 8) .sheet(isPresented: $isImagePickerPresented) { - ImagePicker(selectedImage: $selectedImage) + ImagePicker(selectedImage: $selectedImage, onImagePicked: { image in + print(image) + sendImageMessage(image: image) + }) } .sheet(isPresented: $isDocumentPickerPresented) { DocumentPicker(selectedFileURL: $selectedFileURL) @@ -135,9 +178,38 @@ struct MessageDetailView: View { private func sendMessage() { let newMessage = Message(text: replyText, sender: "你", timestamp: currentTimestamp(), isSelf: true, avatar: "avatar") messages.append(newMessage) +// let messageData = ["text": replyText, "sender": "你", "timestamp": currentTimestamp(), "isSelf": true, "avatar": "avatar"] +// makeAlamofireRequest(api: "YOUR_API_ENDPOINT_HERE", method: .post, param: messageData) { (result: Result, AFError>) in +// switch result { +// case .success(let response): +// print("Message sent successfully: \(response)") +// case .failure(let error): +// print("Error sending message: \(error)") +// } +// } + replyText = "" } + private func sendImageMessage(image: UIImage) { + let newMessage = Message(sender: "你", timestamp: currentTimestamp(), isSelf: true, avatar: "avatar", image: image) + messages.append(newMessage) + + // 将进度重置为 0.0 + uploadProgress = 0.0 + + // 假设你想以 base64 字符串的形式发送图片 + if let imageData = image.jpegData(compressionQuality: 0.8) { + uploadFile(api: apiprefixV1+upload, file: imageData) { progress in + // 更新进度 + self.uploadProgress = progress + } completion: { (result: Result, AFError>) in + print(result) + } + } + } + + private func currentTimestamp() -> String { let formatter = DateFormatter() formatter.dateFormat = "h:mm a" @@ -177,23 +249,21 @@ struct TextBubble: View { } } - -#Preview { - MessageDetailView() -} - // ImagePicker implementation struct ImagePicker: UIViewControllerRepresentable { class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { let parent: ImagePicker + let onImagePicked: (UIImage) -> Void - init(parent: ImagePicker) { + init(parent: ImagePicker, onImagePicked: @escaping (UIImage) -> Void) { self.parent = parent + self.onImagePicked = onImagePicked } func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { if let image = info[.originalImage] as? UIImage { parent.selectedImage = image + onImagePicked(image) } picker.dismiss(animated: true) } @@ -204,9 +274,10 @@ struct ImagePicker: UIViewControllerRepresentable { } @Binding var selectedImage: UIImage? + let onImagePicked: (UIImage) -> Void func makeCoordinator() -> Coordinator { - Coordinator(parent: self) + Coordinator(parent: self, onImagePicked: onImagePicked) } func makeUIViewController(context: Context) -> UIImagePickerController { @@ -220,6 +291,8 @@ struct ImagePicker: UIViewControllerRepresentable { // DocumentPicker implementation struct DocumentPicker: UIViewControllerRepresentable { + @Binding var selectedFileURL: URL? + class Coordinator: NSObject, UIDocumentPickerDelegate { let parent: DocumentPicker @@ -229,25 +302,27 @@ struct DocumentPicker: UIViewControllerRepresentable { func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { parent.selectedFileURL = urls.first - controller.dismiss(animated: true) } func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { - controller.dismiss(animated: true) + parent.selectedFileURL = nil } } - @Binding var selectedFileURL: URL? - func makeCoordinator() -> Coordinator { Coordinator(parent: self) } func makeUIViewController(context: Context) -> UIDocumentPickerViewController { - let picker = UIDocumentPickerViewController(forOpeningContentTypes: [.item]) - picker.delegate = context.coordinator - return picker + let controller = UIDocumentPickerViewController(forOpeningContentTypes: [.item]) + controller.delegate = context.coordinator + return controller } func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {} } + +#Preview { + MessageDetailView() +} + diff --git a/copinism/api/Api.swift b/copinism/api/Api.swift index e4a7fe5..24c8c2f 100644 --- a/copinism/api/Api.swift +++ b/copinism/api/Api.swift @@ -11,13 +11,15 @@ import Foundation let local = "http://127.0.0.1:9999" -let dev = "http://192.168.0.125:9999" +let dev = "http://192.168.1.5:9999" + +let dev1 = "http://192.168.0.121:9999" let pp = "http://43.136.169.205:9999" let release = "https://api.flyaha.top" -let apiprefixV1 = release+"/api/v1" +let apiprefixV1 = local+"/api/v1" var loginApi = "/user/login" @@ -31,3 +33,5 @@ var targetApi = "/target/list" var targeMetApi = "/target/me/list" +var upload = "/todo/message" + diff --git a/copinism/api/MessageBack.swift b/copinism/api/MessageBack.swift new file mode 100644 index 0000000..d854e97 --- /dev/null +++ b/copinism/api/MessageBack.swift @@ -0,0 +1,8 @@ +// +// MessageBack.swift +// copinism +// +// Created by 黄仕杰 on 2024/6/5. +// + +import Foundation diff --git a/copinism/utils/Http.swift b/copinism/utils/Http.swift index f495f0b..0311b7e 100644 --- a/copinism/utils/Http.swift +++ b/copinism/utils/Http.swift @@ -33,3 +33,22 @@ func makeAlamofireRequest(api: String, } +func uploadFile(api: String,file: Data,progressHandler: @escaping (Double) -> Void,completion: @escaping (Result, AFError>) -> Void) { + var headers: HTTPHeaders = [ + "Accept": "application/json", + "Content-Type":"application/octet-stream" + + ] + let loginStatus = checkLoginStatus() + if loginStatus.login { + headers.add(name: "Authorization", value: loginStatus.token) + } + AF.upload(file, to: api,headers: headers) + .uploadProgress { progress in + progressHandler(progress.fractionCompleted) + } + .validate().responseDecodable(of: HTTPBinResponse.self) { response in + completion(response.result) + } +} + diff --git a/【凡人修仙传】那些无法超越的台词和画面!.mp4 b/【凡人修仙传】那些无法超越的台词和画面!.mp4 new file mode 100644 index 0000000..152852d Binary files /dev/null and b/【凡人修仙传】那些无法超越的台词和画面!.mp4 differ