copinism-ios/copinism/Views/Message/MessageDetail.swift
2024-06-07 09:42:34 +08:00

329 lines
12 KiB
Swift

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
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 {
@State private var messages: [Message] = [
Message(text: "来了条消息", sender: "系统消息", timestamp: "4:00 PM", isSelf: false, avatar: "avatar")
]
@State private var replyText = ""
@State private var selectedImage: UIImage?
@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 {
VStack {
HStack {
Button(action: {
presentationMode.wrappedValue.dismiss()
}) {
Image(systemName: "chevron.left")
.font(.system(size: 18))
.foregroundColor(.black)
}
Spacer()
Text("详细信息")
.font(.system(size: 18))
.fontWeight(.bold)
Spacer()
Button(action: {}) {
Image(systemName: "ellipsis")
.font(.system(size: 18))
.foregroundColor(.black)
}
.opacity(0) //
}
.padding(.horizontal, 12)
.padding(.vertical, 8)
ScrollView {
VStack(alignment: .leading, spacing: 10) {
ForEach(messages) { message in
HStack(alignment: .top, spacing: 10) {
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)
}
}
.padding(.vertical, 5)
}
}
.padding()
}
Spacer()
HStack {
Button(action: {
isImagePickerPresented = true
}) {
Image(systemName: "paperclip")
.font(.system(size: 18))
.foregroundColor(.white)
.padding(10)
.background(Color.black.opacity(0.1))
.clipShape(Circle())
}
TextField("给“系统消息”发送消息", text: $replyText)
.padding(10)
.background(Color.black.opacity(0.1))
.cornerRadius(20)
Button(action: {
sendMessage()
}) {
Image(systemName: "arrow.up.circle.fill")
.font(.system(size: 18))
.foregroundColor(.white)
.padding(10)
.background(Color.black.opacity(0.1))
.clipShape(Circle())
}
}
.padding()
.background(Color.black.opacity(0.2))
.cornerRadius(30)
.padding(.horizontal, 12)
.padding(.bottom, 8)
.sheet(isPresented: $isImagePickerPresented) {
ImagePicker(selectedImage: $selectedImage, onImagePicked: { image in
print(image)
sendImageMessage(image: image)
})
}
.sheet(isPresented: $isDocumentPickerPresented) {
DocumentPicker(selectedFileURL: $selectedFileURL)
}
}
.navigationBarBackButtonHidden(true)
.onTapGesture {
hideKeyboard()
}
}
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"
return formatter.string(from: Date())
}
private func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
struct TextBlackbble: View {
var message: String
var body: some View {
Text(message)
.padding(10)
.background(Color.black.opacity(0.1))
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.black, lineWidth: 1)
)
}
}
struct TextBubble: View {
var message: String
var body: some View {
Text(message)
.padding(10)
.background(Color.blue.opacity(0.1))
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.blue, lineWidth: 1)
)
}
}
// ImagePicker implementation
struct ImagePicker: UIViewControllerRepresentable {
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
let parent: ImagePicker
let onImagePicked: (UIImage) -> Void
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)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true)
}
}
@Binding var selectedImage: UIImage?
let onImagePicked: (UIImage) -> Void
func makeCoordinator() -> Coordinator {
Coordinator(parent: self, onImagePicked: onImagePicked)
}
func makeUIViewController(context: Context) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {}
}
// DocumentPicker implementation
struct DocumentPicker: UIViewControllerRepresentable {
@Binding var selectedFileURL: URL?
class Coordinator: NSObject, UIDocumentPickerDelegate {
let parent: DocumentPicker
init(parent: DocumentPicker) {
self.parent = parent
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
parent.selectedFileURL = urls.first
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
parent.selectedFileURL = nil
}
}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
let controller = UIDocumentPickerViewController(forOpeningContentTypes: [.item])
controller.delegate = context.coordinator
return controller
}
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {}
}
#Preview {
MessageDetailView()
}