diff --git a/ConversationsClassic/AppCore/Actions/ConversationActions.swift b/ConversationsClassic/AppCore/Actions/ConversationActions.swift index 4e5f182..9294677 100644 --- a/ConversationsClassic/AppCore/Actions/ConversationActions.swift +++ b/ConversationsClassic/AppCore/Actions/ConversationActions.swift @@ -4,5 +4,5 @@ enum ConversationAction: Codable { case messagesUpdated(messages: [Message]) case sendMessage(from: String, to: String, body: String) - case setReplyText(String?) + case setReplyText(String) } diff --git a/ConversationsClassic/AppCore/Reducers/ConversationReducer.swift b/ConversationsClassic/AppCore/Reducers/ConversationReducer.swift index 2ef0f4b..cc76c62 100644 --- a/ConversationsClassic/AppCore/Reducers/ConversationReducer.swift +++ b/ConversationsClassic/AppCore/Reducers/ConversationReducer.swift @@ -11,7 +11,11 @@ extension ConversationState { state.currentMessages = messages case .setReplyText(let text): - state.replyText = text + if text.isEmpty { + state.replyText = "" + } else { + state.replyText = text.makeReply + } default: break diff --git a/ConversationsClassic/AppCore/State/ConversationState.swift b/ConversationsClassic/AppCore/State/ConversationState.swift index 18d90aa..9267bbd 100644 --- a/ConversationsClassic/AppCore/State/ConversationState.swift +++ b/ConversationsClassic/AppCore/State/ConversationState.swift @@ -3,12 +3,13 @@ struct ConversationState: Stateable { var currentRoster: Roster? var currentMessages: [Message] - var replyText: String? + var replyText: String } // MARK: Init extension ConversationState { init() { currentMessages = [] + replyText = "" } } diff --git a/ConversationsClassic/Helpers/String+Extensions.swift b/ConversationsClassic/Helpers/String+Extensions.swift index 8fc4cfb..2423c88 100644 --- a/ConversationsClassic/Helpers/String+Extensions.swift +++ b/ConversationsClassic/Helpers/String+Extensions.swift @@ -4,4 +4,12 @@ extension String { var firstLetter: String { String(prefix(1)).uppercased() } + + var makeReply: String { + let allLines = components(separatedBy: .newlines) + let nonBlankLines = allLines.filter { !$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty } + var result = nonBlankLines.joined(separator: "\n") + result = "> \(result)" + return result + } } diff --git a/ConversationsClassic/View/Screens/Conversation/ConversationHeader.swift b/ConversationsClassic/View/Screens/Conversation/ConversationHeader.swift new file mode 100644 index 0000000..33181f3 --- /dev/null +++ b/ConversationsClassic/View/Screens/Conversation/ConversationHeader.swift @@ -0,0 +1,33 @@ +import SwiftUI + +struct ConversationHeader: View { + @EnvironmentObject var store: AppStore + + var body: some View { + ZStack { + // bg + Color.Main.backgroundDark + .ignoresSafeArea() + + // title + let name = ( + store.state.conversationsState.currentRoster?.name ?? + store.state.conversationsState.currentRoster?.contactBareJid + ) ?? L10n.Chat.title + Text(name) + .font(.head2) + .foregroundColor(Color.Main.black) + + HStack { + Image(systemName: "chevron.left") + .foregroundColor(Color.Tango.orangeMedium) + .tappablePadding(.symmetric(12)) { + store.dispatch(.changeFlow(store.state.previousFlow)) + } + Spacer() + } + .padding(.horizontal, 16) + } + .frame(height: 44) + } +} diff --git a/ConversationsClassic/View/Screens/Conversation/ConversationMessageContainer.swift b/ConversationsClassic/View/Screens/Conversation/ConversationMessageContainer.swift new file mode 100644 index 0000000..850191e --- /dev/null +++ b/ConversationsClassic/View/Screens/Conversation/ConversationMessageContainer.swift @@ -0,0 +1,36 @@ +import SwiftUI + +struct ConversationMessageContainer: View { + let message: Message + let isOutgoing: Bool + + var body: some View { + Text(message.body ?? "...") + .font(.body2) + .foregroundColor(Color.Main.black) + .multilineTextAlignment(.leading) + .padding(10) + } +} + +struct MessageAttr: View { + let message: Message + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + Text(message.date, style: .time) + .font(.sub2) + .foregroundColor(Color.Main.gray) + Spacer() + if message.sentError { + Image(systemName: "exclamationmark.circle") + .font(.body3) + .foregroundColor(Color.Tango.redLight) + } else if message.pending { + Image(systemName: "clock") + .font(.body3) + .foregroundColor(Color.Main.gray) + } + } + } +} diff --git a/ConversationsClassic/View/Screens/Conversation/ConversationMessageRow.swift b/ConversationsClassic/View/Screens/Conversation/ConversationMessageRow.swift new file mode 100644 index 0000000..fa4f623 --- /dev/null +++ b/ConversationsClassic/View/Screens/Conversation/ConversationMessageRow.swift @@ -0,0 +1,70 @@ +import Foundation +import SwiftUI + +struct ConversationMessageRow: View { + @EnvironmentObject var store: AppStore + + let message: Message + @State private var offset: CGSize = .zero + + var body: some View { + VStack(spacing: 0) { + HStack(spacing: 0) { + if isOutgoing() { + Spacer() + MessageAttr(message: message) + .padding(.trailing, 4) + } + ConversationMessageContainer(message: message, isOutgoing: isOutgoing()) + .background(isOutgoing() ? Color.Material.greenDark100 : Color.Main.white) + .clipShape(ConversationMessageBubble(isOutgoing: isOutgoing())) + if !isOutgoing() { + MessageAttr(message: message) + .padding(.leading, 4) + Spacer() + } + } + .padding(.vertical, 10) + .padding(.horizontal, 16) + .background(Color.clearTappable) + .offset(offset) + .gesture( + DragGesture(minimumDistance: 20, coordinateSpace: .local) + .onEnded { value in + withAnimation(.easeOut(duration: 0.1)) { + if value.translation.width < 0 { + offset = CGSize(width: -50, height: 0) + Vibration.success.vibrate() + DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { + store.dispatch(.conversationAction(.setReplyText(message.body ?? ""))) + withAnimation(.easeOut(duration: 0.1)) { + offset = .zero + } + } + } else { + offset = .zero + } + } + } + ) + } + .sharedListRow() + } + + private func isOutgoing() -> Bool { + message.from == store.state.conversationsState.currentChat?.account + } +} + +struct ConversationMessageBubble: Shape { + let isOutgoing: Bool + + func path(in rect: CGRect) -> Path { + let path = UIBezierPath( + roundedRect: rect, + byRoundingCorners: isOutgoing ? [.topLeft, .bottomLeft, .bottomRight] : [.topRight, .bottomLeft, .bottomRight], + cornerRadii: CGSize(width: 8, height: 10) + ) + return Path(path.cgPath) + } +} diff --git a/ConversationsClassic/View/Screens/Conversation/ConversationScreen.swift b/ConversationsClassic/View/Screens/Conversation/ConversationScreen.swift new file mode 100644 index 0000000..1cfd342 --- /dev/null +++ b/ConversationsClassic/View/Screens/Conversation/ConversationScreen.swift @@ -0,0 +1,134 @@ +import Combine +import Foundation +import Martin +import SwiftUI + +struct ConversationScreen: View { + @EnvironmentObject var store: AppStore + + var body: some View { + ZStack { + // Background color + Color.Main.backgroundLight + .ignoresSafeArea() + + // Content + VStack(spacing: 0) { + // Header + ConversationHeader() + + // Msg list + let messages = store.state.conversationsState.currentMessages + if !messages.isEmpty { + List { + ForEach(messages) { message in + ConversationMessageRow(message: message) + } + } + .listStyle(.plain) + .background(Color.Main.backgroundLight) + .scrollDismissesKeyboard(.immediately) + } else { + Spacer() + } + } + .onTapGesture { + UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) + } + } + .safeAreaInset(edge: .bottom, spacing: 0) { + ConversationTextInput() + } + } +} + +// Preview +#if DEBUG + struct ConversationScreen_Previews: PreviewProvider { + static var previews: some View { + ConversationScreen() + .environmentObject(pStore) + } + + static var pStore: AppStore { + let state = pState + return AppStore(initialState: state, reducer: AppState.reducer, middlewares: []) + } + + static var pState: AppState { + var state = AppState() + + let acc = "user@test.com" + let contact = "some@test.com" + + state.conversationsState.currentChat = Chat(id: "1", account: acc, participant: contact, type: .chat) + state.conversationsState.currentMessages = [ + Message( + id: "1", + type: .chat, + contentType: .text, + from: contact, + to: acc, + body: "this is for test sdgdsfg dsfg dsfgdg dsfgdfgsdgsdfgdfg sdfgdsfgdfsg dsfgdsfgsdfg dsfgdfgsdg fgf fgfg sdfsdf sdfsdf sdf sdfsdf sdf sdfsdf sdfsdfsdf sdfsdf ", + subject: nil, + thread: nil, + oobUrl: nil, + date: Date(), + pending: true, sentError: false + ), + Message( + id: "2", + type: .chat, + contentType: .text, + from: contact, + to: acc, + body: "this is for testsdfsdf sdfsdf sdfs sdf sdffsdf sdf sdf sdf sdf sdf sdff sdfffwwe ", + subject: nil, + thread: nil, + oobUrl: nil, + date: Date(), + pending: false, + sentError: false + ), + Message(id: "3", type: .chat, contentType: .text, from: contact, to: acc, body: "this is for test", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: true), + Message( + id: "4", + type: .chat, + contentType: .text, + from: acc, + to: contact, + body: "this is for test sdfkjwek jwkjfh jwerf jdfhskjdhf jsdhfjhwefh sjdhfh fsdjhfh sd ", + subject: nil, + thread: nil, + oobUrl: nil, + date: Date(), + pending: false, + sentError: false + ), + Message(id: "5", type: .chat, contentType: .text, from: contact, to: acc, body: "this is for test sdfjkkeke kekkddjw;; w;edkdjfj l kjwekrjfk wef", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), + Message(id: "6", type: .chat, contentType: .text, from: acc, to: contact, body: "this is for testsdf dsdkkekkddn wejkjfj ", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), + Message( + id: "7", + type: .chat, + contentType: .text, + from: acc, + to: contact, + + body: "this is for test sdgdsfg dsfg dsfgdg dsfgdfgsdgsdfgdfg sdfgdsfgdfsg dsfgdsfgsdfg dsfgdfgsdg fgf fgfg sdfsdf sdfsdf sdf sdfsdf sdf sdfsdf sdfsdfsdf sdfsdf ", + subject: nil, + thread: nil, + oobUrl: nil, + date: Date(), pending: false, sentError: false + ), + Message(id: "8", type: .chat, contentType: .text, from: acc, to: contact, body: "so test", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), + Message(id: "9", type: .chat, contentType: .text, from: contact, to: acc, body: "so test", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), + Message(id: "10", type: .chat, contentType: .text, from: acc, to: contact, body: "so test so test so test", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), + Message(id: "11", type: .chat, contentType: .text, from: contact, to: acc, body: "xD", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false) + ] + + state.conversationsState.replyText = "> Some Text here! And if it a long and very long text sdfsadfsadfsafsadfsadfsadfsadfassadfsadfsafsafdsadfsafdsadfsadfas sdf sdf asdf sdfasdfsd sdfasdf sdfsdfdsasdfsdfa dsafsaf" + + return state + } + } +#endif diff --git a/ConversationsClassic/View/Screens/Conversation/ConversationTextInput.swift b/ConversationsClassic/View/Screens/Conversation/ConversationTextInput.swift new file mode 100644 index 0000000..9e970a3 --- /dev/null +++ b/ConversationsClassic/View/Screens/Conversation/ConversationTextInput.swift @@ -0,0 +1,103 @@ +import SwiftUI +import UIKit + +struct ConversationTextInput: View { + @EnvironmentObject var store: AppStore + + @State private var messageStr = "" + @FocusState private var isFocused: Bool + + var body: some View { + VStack(spacing: 0) { + Rectangle() + .foregroundColor(.Main.separator) + .frame(height: 0.5) + .padding(.bottom, 8) + if !replyText.isEmpty { + VStack(spacing: 0) { + HStack(alignment: .top) { + Text(replyText) + .font(.body3) + .foregroundColor(Color.Main.black) + .multilineTextAlignment(/*@START_MENU_TOKEN@*/ .leading/*@END_MENU_TOKEN@*/) + .lineLimit(3) + .padding(8) + Spacer() + Image(systemName: "xmark") + .font(.title2) + .foregroundColor(.Tango.blueLight) + .padding(.leading, 8) + .tappablePadding(.symmetric(8)) { + store.dispatch(.conversationAction(.setReplyText(""))) + } + .padding(8) + } + .frame(maxWidth: .infinity) + .background(RoundedRectangle(cornerRadius: 4) + .foregroundColor(.Main.backgroundLight) + .shadow(radius: 0.5) + ) + .padding(.bottom, 8) + .padding(.horizontal, 8) + } + .padding(.horizontal, 8) + } + HStack { + Image(systemName: "paperclip") + .font(.title2) + .foregroundColor(.Tango.blueLight) + .padding(.leading, 8) + .tappablePadding(.symmetric(8)) { + print("Attach file") + } + TextField(L10n.Chat.textfieldPrompt, text: $messageStr) + .font(.body1) + .focused($isFocused) + .padding(.horizontal, 8) + .padding(.vertical, 4) + .background(Color.Main.white) + .clipShape(RoundedRectangle(cornerRadius: 8)) + .padding(.vertical, 4) + let img = messageStr.isEmpty ? "paperplane" : "paperplane.fill" + Image(systemName: img) + .font(.title2) + .foregroundColor(messageStr.isEmpty ? .Main.separator : .Tango.blueLight) + .padding(.trailing, 8) + .tappablePadding(.symmetric(8)) { + if !messageStr.isEmpty { + guard let acc = store.state.conversationsState.currentChat?.account else { return } + guard let contact = store.state.conversationsState.currentChat?.participant else { return } + store.dispatch(.conversationAction(.sendMessage( + from: acc, + to: contact, + body: composedMessage + ))) + messageStr = "" + UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) + store.dispatch(.conversationAction(.setReplyText(""))) + } + } + } + } + .padding(.bottom, 8) + .background(Color.Main.backgroundDark) + .onChange(of: store.state.conversationsState.replyText) { new in + if !new.isEmpty { + isFocused = true + } + } + } + + private var replyText: String { + store.state.conversationsState.replyText + } + + private var composedMessage: String { + var result = "" + if !replyText.isEmpty { + result += replyText + "\n" + } + result += messageStr + return result + } +} diff --git a/ConversationsClassic/View/Screens/ConversationScreen.swift b/ConversationsClassic/View/Screens/ConversationScreen.swift deleted file mode 100644 index bfe770a..0000000 --- a/ConversationsClassic/View/Screens/ConversationScreen.swift +++ /dev/null @@ -1,327 +0,0 @@ -import Combine -import Foundation -import Martin -import SwiftUI - -struct ConversationScreen: View { - @EnvironmentObject var store: AppStore - - var body: some View { - ZStack { - // Background color - Color.Main.backgroundLight - .ignoresSafeArea() - - // Content - VStack(spacing: 0) { - // Header - ConversationScreenHeader() - - // Msg list - let messages = store.state.conversationsState.currentMessages - if !messages.isEmpty { - List { - ForEach(messages) { message in - ConversationMessageRow(message: message) - } - } - .listStyle(.plain) - .background(Color.Main.backgroundLight) - .scrollDismissesKeyboard(.immediately) - } else { - Spacer() - } - } - .onTapGesture { - UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) - } - } - .safeAreaInset(edge: .bottom, spacing: 0) { - ConversationScreenTextInput() - } - } -} - -struct ConversationScreenTextInput: View { - @EnvironmentObject var store: AppStore - - @State private var messageStr = "" - - var body: some View { - HStack { - Image(systemName: "paperclip") - .font(.title2) - .foregroundColor(.Tango.blueLight) - .padding(.leading, 8) - .tappablePadding(.symmetric(8)) { - print("Attach file") - } - TextField(L10n.Chat.textfieldPrompt, text: $messageStr) - .font(.body1) - .padding(.horizontal, 8) - .padding(.vertical, 4) - .background(Color.Main.white) - .clipShape(RoundedRectangle(cornerRadius: 8)) - .padding(.vertical, 4) - let img = messageStr.isEmpty ? "paperplane" : "paperplane.fill" - Image(systemName: img) - .font(.title2) - .foregroundColor(messageStr.isEmpty ? .Main.separator : .Tango.blueLight) - .padding(.trailing, 8) - .tappablePadding(.symmetric(8)) { - if !messageStr.isEmpty { - guard let acc = store.state.conversationsState.currentChat?.account else { return } - guard let contact = store.state.conversationsState.currentChat?.participant else { return } - store.dispatch(.conversationAction(.sendMessage( - from: acc, - to: contact, - body: messageStr - ))) - messageStr = "" - UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) - } - } - } - .padding(.vertical, 8) - .background(Color.Main.backgroundDark) - } -} - -private struct ConversationScreenHeader: View { - @EnvironmentObject var store: AppStore - - var body: some View { - ZStack { - // bg - Color.Main.backgroundDark - .ignoresSafeArea() - - // title - let name = ( - store.state.conversationsState.currentRoster?.name ?? - store.state.conversationsState.currentRoster?.contactBareJid - ) ?? L10n.Chat.title - Text(name) - .font(.head2) - .foregroundColor(Color.Main.black) - - HStack { - Image(systemName: "chevron.left") - .foregroundColor(Color.Tango.orangeMedium) - .tappablePadding(.symmetric(12)) { - store.dispatch(.changeFlow(store.state.previousFlow)) - } - Spacer() - } - .padding(.horizontal, 16) - } - .frame(height: 44) - } -} - -private struct ConversationMessageRow: View { - @EnvironmentObject var store: AppStore - - let message: Message - @State private var offset: CGSize = .zero - - var body: some View { - VStack(spacing: 0) { - HStack(spacing: 0) { - if isOutgoing() { - Spacer() - MessageAttr(message: message) - .padding(.trailing, 4) - } - MessageContainer(message: message, isOutgoing: isOutgoing()) - .background(isOutgoing() ? Color.Material.greenDark100 : Color.Main.white) - .clipShape(MessageBubble(isOutgoing: isOutgoing())) - if !isOutgoing() { - MessageAttr(message: message) - .padding(.leading, 4) - Spacer() - } - } - .padding(.vertical, 10) - .padding(.horizontal, 16) - .background(Color.clearTappable) - .offset(offset) - .gesture( - DragGesture(minimumDistance: 20, coordinateSpace: .local) - .onEnded { value in - withAnimation(.easeOut(duration: 0.1)) { - if value.translation.width < 0 { - offset = CGSize(width: -50, height: 0) - Vibration.success.vibrate() - store.dispatch(.conversationAction(.setReplyText(message.body))) - DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { - withAnimation(.easeOut(duration: 0.1)) { - offset = .zero - } - } - } else { - offset = .zero - } - } - } - ) - } - .sharedListRow() - } - - private func isOutgoing() -> Bool { - message.from == store.state.conversationsState.currentChat?.account - } -} - -struct MessageContainer: View { - let message: Message - let isOutgoing: Bool - - var body: some View { - Text(message.body ?? "...") - .font(.body2) - .foregroundColor(Color.Main.black) - .multilineTextAlignment(.leading) - .padding(10) - } -} - -struct MessageBubble: Shape { - let isOutgoing: Bool - - func path(in rect: CGRect) -> Path { - let path = UIBezierPath( - roundedRect: rect, - byRoundingCorners: isOutgoing ? [.topLeft, .bottomLeft, .bottomRight] : [.topRight, .bottomLeft, .bottomRight], - cornerRadii: CGSize(width: 8, height: 10) - ) - return Path(path.cgPath) - } -} - -struct MessageAttr: View { - let message: Message - - var body: some View { - VStack(alignment: .leading, spacing: 0) { - Text(message.date, style: .time) - .font(.sub2) - .foregroundColor(Color.Main.gray) - Spacer() - if message.sentError { - Image(systemName: "exclamationmark.circle") - .font(.body3) - .foregroundColor(Color.Tango.redLight) - } else if message.pending { - Image(systemName: "clock") - .font(.body3) - .foregroundColor(Color.Main.gray) - } - } - } -} - - // self.conversationLogController?.getTextOfSelectedRows(paths: [indexPath], withTimestamps: false, handler: { [weak self] texts in - // let text: String = texts.flatMap { $0.split(separator: "\n")}.map { - // if $0.starts(with: ">") { - // return ">\($0)"; - // } else { - // return "> \($0)" - // } - // }.joined(separator: "\n"); - // - // if let current = self?.messageText, !current.isEmpty { - // self?.messageText = "\(current)\n\(text)\n"; - // } else { - // self?.messageText = "\(text)\n"; - // } - // }) - -// Preview -#if DEBUG - struct ConversationScreen_Previews: PreviewProvider { - static var previews: some View { - ConversationScreen() - .environmentObject(pStore) - } - - static var pStore: AppStore { - let state = pState - return AppStore(initialState: state, reducer: AppState.reducer, middlewares: []) - } - - static var pState: AppState { - var state = AppState() - - let acc = "user@test.com" - let contact = "some@test.com" - - state.conversationsState.currentChat = Chat(id: "1", account: acc, participant: contact, type: .chat) - state.conversationsState.currentMessages = [ - Message( - id: "1", - type: .chat, - contentType: .text, - from: contact, - to: acc, - body: "this is for test sdgdsfg dsfg dsfgdg dsfgdfgsdgsdfgdfg sdfgdsfgdfsg dsfgdsfgsdfg dsfgdfgsdg fgf fgfg sdfsdf sdfsdf sdf sdfsdf sdf sdfsdf sdfsdfsdf sdfsdf ", - subject: nil, - thread: nil, - oobUrl: nil, - date: Date(), - pending: true, sentError: false - ), - Message( - id: "2", - type: .chat, - contentType: .text, - from: contact, - to: acc, - body: "this is for testsdfsdf sdfsdf sdfs sdf sdffsdf sdf sdf sdf sdf sdf sdff sdfffwwe ", - subject: nil, - thread: nil, - oobUrl: nil, - date: Date(), - pending: false, - sentError: false - ), - Message(id: "3", type: .chat, contentType: .text, from: contact, to: acc, body: "this is for test", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: true), - Message( - id: "4", - type: .chat, - contentType: .text, - from: acc, - to: contact, - body: "this is for test sdfkjwek jwkjfh jwerf jdfhskjdhf jsdhfjhwefh sjdhfh fsdjhfh sd ", - subject: nil, - thread: nil, - oobUrl: nil, - date: Date(), - pending: false, - sentError: false - ), - Message(id: "5", type: .chat, contentType: .text, from: contact, to: acc, body: "this is for test sdfjkkeke kekkddjw;; w;edkdjfj l kjwekrjfk wef", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), - Message(id: "6", type: .chat, contentType: .text, from: acc, to: contact, body: "this is for testsdf dsdkkekkddn wejkjfj ", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), - Message( - id: "7", - type: .chat, - contentType: .text, - from: acc, - to: contact, - - body: "this is for test sdgdsfg dsfg dsfgdg dsfgdfgsdgsdfgdfg sdfgdsfgdfsg dsfgdsfgsdfg dsfgdfgsdg fgf fgfg sdfsdf sdfsdf sdf sdfsdf sdf sdfsdf sdfsdfsdf sdfsdf ", - subject: nil, - thread: nil, - oobUrl: nil, - date: Date(), pending: false, sentError: false - ), - Message(id: "8", type: .chat, contentType: .text, from: acc, to: contact, body: "so test", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), - Message(id: "9", type: .chat, contentType: .text, from: contact, to: acc, body: "so test", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), - Message(id: "10", type: .chat, contentType: .text, from: acc, to: contact, body: "so test so test so test", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), - Message(id: "11", type: .chat, contentType: .text, from: contact, to: acc, body: "xD", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false) - ] - return state - } - } -#endif