发送消息

This commit is contained in:
huangshijie 2024-06-07 09:42:34 +08:00
parent ed146df357
commit 2431df67df
7 changed files with 152 additions and 38 deletions

View File

@ -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 = "<group>"; };
DE9C3A132C0E390200951DEE /* TestSwiftUIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSwiftUIView.swift; sourceTree = "<group>"; };
DE9C3A342C0E420400951DEE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
DE9C3A352C10AA8000951DEE /* MessageBack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageBack.swift; sourceTree = "<group>"; };
/* 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 = "<group>";
@ -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 */,

View File

@ -4,6 +4,10 @@
<dict>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
<key>CFBundleLocalizations</key>
<array>
<string>zh_CN</string>
</array>
<key>IDEPreferLogStreaming</key>
<true/>
<key>NSAppTransportSecurity</key>

View File

@ -1,6 +1,5 @@
import SwiftUI
import Alamofire
struct Message: Identifiable {
let id: UUID
@ -10,8 +9,9 @@ struct Message: Identifiable {
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) {
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
@ -19,6 +19,7 @@ struct Message: Identifiable {
self.isSelf = isSelf
self.avatar = avatar
self.num = num
self.image = image
}
}
@ -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)
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()
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<HTTPBinResponse<Message>, 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<HTTPBinResponse<Token>, 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()
}

View File

@ -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"

View File

@ -0,0 +1,8 @@
//
// MessageBack.swift
// copinism
//
// Created by on 2024/6/5.
//
import Foundation

View File

@ -33,3 +33,22 @@ func makeAlamofireRequest<T: Decodable,Parame: Encodable>(api: String,
}
func uploadFile<T: Decodable>(api: String,file: Data,progressHandler: @escaping (Double) -> Void,completion: @escaping (Result<HTTPBinResponse<T>, 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<T>.self) { response in
completion(response.result)
}
}