✨ Able to send message on watchOS
This commit is contained in:
		| @@ -261,6 +261,8 @@ struct ChatRoomView: View { | |||||||
|     @State private var error: Error? |     @State private var error: Error? | ||||||
|     @State private var wsState: WebSocketState = .disconnected // New state for WebSocket status |     @State private var wsState: WebSocketState = .disconnected // New state for WebSocket status | ||||||
|     @State private var hasLoadedMessages = false // Track if messages have been loaded |     @State private var hasLoadedMessages = false // Track if messages have been loaded | ||||||
|  |     @State private var messageText = "" // Text input for sending messages | ||||||
|  |     @State private var isSending = false // Track sending state | ||||||
|  |  | ||||||
|     @State private var cancellables = Set<AnyCancellable>() // For managing subscriptions |     @State private var cancellables = Set<AnyCancellable>() // For managing subscriptions | ||||||
|  |  | ||||||
| @@ -316,7 +318,7 @@ struct ChatRoomView: View { | |||||||
|                             scrollView.scrollTo(lastMessage.id, anchor: .bottom) |                             scrollView.scrollTo(lastMessage.id, anchor: .bottom) | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                     .onChange(of: messages.count) { _ in |                     .onChange(of: messages.count) { _, _ in | ||||||
|                         // Scroll to bottom when new messages arrive |                         // Scroll to bottom when new messages arrive | ||||||
|                         if let lastMessage = messages.last { |                         if let lastMessage = messages.last { | ||||||
|                             withAnimation { |                             withAnimation { | ||||||
| @@ -326,6 +328,35 @@ struct ChatRoomView: View { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             // Message input area | ||||||
|  |             HStack(spacing: 8) { | ||||||
|  |                 TextField("Send message...", text: $messageText) | ||||||
|  |                     .font(.system(size: 14)) | ||||||
|  |                     .disabled(isSending) | ||||||
|  |                     .frame(height: 40) | ||||||
|  |  | ||||||
|  |                 Button { | ||||||
|  |                     Task { | ||||||
|  |                         await sendMessage() | ||||||
|  |                     } | ||||||
|  |                 } label: { | ||||||
|  |                     if isSending { | ||||||
|  |                         ProgressView() | ||||||
|  |                             .frame(width: 20, height: 20) | ||||||
|  |                     } else { | ||||||
|  |                         Image(systemName: "arrow.up.circle.fill") | ||||||
|  |                             .resizable() | ||||||
|  |                             .frame(width: 20, height: 20) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 .labelStyle(.iconOnly) | ||||||
|  |                 .buttonStyle(.glass) | ||||||
|  |                 .disabled(messageText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || isSending) | ||||||
|  |                 .frame(width: 40, height: 40) | ||||||
|  |             } | ||||||
|  |             .padding(.horizontal) | ||||||
|  |             .padding(.top, 8) | ||||||
|         } |         } | ||||||
|         .navigationTitle(room.name ?? "Chat") |         .navigationTitle(room.name ?? "Chat") | ||||||
|         .task { |         .task { | ||||||
| @@ -380,6 +411,66 @@ struct ChatRoomView: View { | |||||||
|         isLoading = false |         isLoading = false | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private func sendMessage() async { | ||||||
|  |         let content = messageText.trimmingCharacters(in: .whitespacesAndNewlines) | ||||||
|  |         guard !content.isEmpty, | ||||||
|  |               let token = appState.token, | ||||||
|  |               let serverUrl = appState.serverUrl else { return } | ||||||
|  |  | ||||||
|  |         isSending = true | ||||||
|  |  | ||||||
|  |         do { | ||||||
|  |             // Generate a nonce for the message | ||||||
|  |             let nonce = UUID().uuidString | ||||||
|  |  | ||||||
|  |             // Prepare the request data | ||||||
|  |             let messageData: [String: Any] = [ | ||||||
|  |                 "content": content, | ||||||
|  |                 "attachments_id": [], // Empty for now, can be extended for attachments | ||||||
|  |                 "meta": [:], | ||||||
|  |                 "nonce": nonce | ||||||
|  |             ] | ||||||
|  |  | ||||||
|  |             // Create the URL | ||||||
|  |             guard let url = URL(string: "\(serverUrl)/sphere/chat/\(room.id)/messages") else { | ||||||
|  |                 throw URLError(.badURL) | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Create the request | ||||||
|  |             var request = URLRequest(url: url) | ||||||
|  |             request.httpMethod = "POST" | ||||||
|  |             request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") | ||||||
|  |             request.setValue("application/json", forHTTPHeaderField: "Content-Type") | ||||||
|  |             request.httpBody = try JSONSerialization.data(withJSONObject: messageData, options: []) | ||||||
|  |  | ||||||
|  |             // Send the request | ||||||
|  |             let (data, response) = try await URLSession.shared.data(for: request) | ||||||
|  |  | ||||||
|  |             guard let httpResponse = response as? HTTPURLResponse, | ||||||
|  |                   (200...299).contains(httpResponse.statusCode) else { | ||||||
|  |                 throw URLError(.badServerResponse) | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Parse the response to get the sent message | ||||||
|  |             let decoder = JSONDecoder() | ||||||
|  |             decoder.dateDecodingStrategy = .iso8601 | ||||||
|  |             decoder.keyDecodingStrategy = .convertFromSnakeCase | ||||||
|  |             let sentMessage = try decoder.decode(SnChatMessage.self, from: data) | ||||||
|  |  | ||||||
|  |             // Add the message to the local list | ||||||
|  |             messages.append(sentMessage) | ||||||
|  |  | ||||||
|  |             // Clear the input | ||||||
|  |             messageText = "" | ||||||
|  |  | ||||||
|  |         } catch { | ||||||
|  |             print("[watchOS] Error sending message: \(error.localizedDescription)") | ||||||
|  |             // Could show an error alert here | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         isSending = false | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private func sendReadReceipt() { |     private func sendReadReceipt() { | ||||||
|         let data: [String: Any] = ["chat_room_id": room.id] |         let data: [String: Any] = ["chat_room_id": room.id] | ||||||
|         let packet: [String: Any] = ["type": "messages.read", "data": data, "endpoint": "sphere"] |         let packet: [String: Any] = ["type": "messages.read", "data": data, "endpoint": "sphere"] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user