diff --git a/ConversationsClassic/AppCore/Database/Database+Migrations.swift b/ConversationsClassic/AppCore/Database/Database+Migrations.swift index 902f652..f8d4c59 100644 --- a/ConversationsClassic/AppCore/Database/Database+Migrations.swift +++ b/ConversationsClassic/AppCore/Database/Database+Migrations.swift @@ -55,6 +55,7 @@ extension Database { table.column("subject", .text) table.column("thread", .text) table.column("oobUrl", .text) + table.column("date", .datetime).notNull() } } diff --git a/ConversationsClassic/AppCore/Models/Message.swift b/ConversationsClassic/AppCore/Models/Message.swift index 4065e83..b5f0beb 100644 --- a/ConversationsClassic/AppCore/Models/Message.swift +++ b/ConversationsClassic/AppCore/Models/Message.swift @@ -26,6 +26,8 @@ struct Message: Stateable, Identifiable, DatabaseValueConvertible { let subject: String? let thread: String? let oobUrl: String? + + let date: Date } extension Message { @@ -69,7 +71,8 @@ extension Message { body: martinMessage.body, subject: martinMessage.subject, thread: martinMessage.thread, - oobUrl: martinMessage.oob + oobUrl: martinMessage.oob, + date: Date() ) return msg } diff --git a/ConversationsClassic/Resources/Assets/Colors.xcassets/material/greenDark100.colorset/Contents.json b/ConversationsClassic/Resources/Assets/Colors.xcassets/material/greenDark100.colorset/Contents.json new file mode 100644 index 0000000..72469b0 --- /dev/null +++ b/ConversationsClassic/Resources/Assets/Colors.xcassets/material/greenDark100.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "201", + "green" : "227", + "red" : "199" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ConversationsClassic/Resources/Assets/Colors.xcassets/material/greenDark200.colorset/Contents.json b/ConversationsClassic/Resources/Assets/Colors.xcassets/material/greenDark200.colorset/Contents.json index e25608b..c7b6100 100644 --- a/ConversationsClassic/Resources/Assets/Colors.xcassets/material/greenDark200.colorset/Contents.json +++ b/ConversationsClassic/Resources/Assets/Colors.xcassets/material/greenDark200.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.655", - "green" : "0.839", - "red" : "0.647" + "blue" : "167", + "green" : "214", + "red" : "165" } }, "idiom" : "universal" diff --git a/ConversationsClassic/Resources/Assets/Colors.xcassets/material/greenDark300.colorset/Contents.json b/ConversationsClassic/Resources/Assets/Colors.xcassets/material/greenDark300.colorset/Contents.json index 4c19725..0f3b846 100644 --- a/ConversationsClassic/Resources/Assets/Colors.xcassets/material/greenDark300.colorset/Contents.json +++ b/ConversationsClassic/Resources/Assets/Colors.xcassets/material/greenDark300.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.518", - "green" : "0.780", - "red" : "0.506" + "blue" : "132", + "green" : "199", + "red" : "129" } }, "idiom" : "universal" diff --git a/ConversationsClassic/Resources/Strings/Localizable.strings b/ConversationsClassic/Resources/Strings/Localizable.strings index 8dadfa1..d0a1d7d 100644 --- a/ConversationsClassic/Resources/Strings/Localizable.strings +++ b/ConversationsClassic/Resources/Strings/Localizable.strings @@ -41,6 +41,7 @@ "Chats.title" = "Chats"; "Chat.title" = "Chat"; +"Chat.textfieldPrompt" = "Type a message"; // MARK: Accounts add screen "Accounts.Add.or" = "or"; diff --git a/ConversationsClassic/View/Components/MessageContainer.swift b/ConversationsClassic/View/Components/MessageContainer.swift deleted file mode 100644 index 8127904..0000000 --- a/ConversationsClassic/View/Components/MessageContainer.swift +++ /dev/null @@ -1,22 +0,0 @@ -import Foundation -import SwiftUI - -struct MessageContainer: View { - let message: Message - let isOutgoing: Bool - - var body: some View { - ZStack { - // bg - Color.Main.backgroundDark - .ignoresSafeArea() - - // TODO: make custom body for different message types - // body - Text(message.body ?? "...") - .multilineTextAlignment(.leading) - .foregroundColor(Color.Main.black) - .background(isOutgoing ? Color.Material.greenDark200 : Color.Main.white) - } - } -} diff --git a/ConversationsClassic/View/Screens/ConversationScreen.swift b/ConversationsClassic/View/Screens/ConversationScreen.swift index a0b4062..e97ed31 100644 --- a/ConversationsClassic/View/Screens/ConversationScreen.swift +++ b/ConversationsClassic/View/Screens/ConversationScreen.swift @@ -32,6 +32,47 @@ struct ConversationScreen: View { } } } + .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 { + messageStr = "" + UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) + } + } + } + .padding(.vertical, 8) + .background(Color.Main.backgroundDark) } } @@ -78,56 +119,133 @@ private struct ConversationMessageRow: View { let message: Message var body: some View { - VStack { - if isIncoming() { - HStack { - MessageContainer(message: message, isOutgoing: false) - .padding(.all, 8) + VStack(spacing: 0) { + HStack(spacing: 0) { + if isOutgoing() { Spacer() - .frame(minWidth: 48, maxWidth: .infinity, alignment: .leading) + VStack(spacing: 0) { + MessageTime(message: message) + Spacer() + } + .padding(.trailing, 4) } - } else { - HStack { + MessageContainer(message: message, isOutgoing: isOutgoing()) + .background(isOutgoing() ? Color.Material.greenDark100 : Color.Main.white) + .clipShape(MessageBubble(isOutgoing: isOutgoing())) + if !isOutgoing() { + VStack(spacing: 0) { + MessageTime(message: message) + Spacer() + } + .padding(.leading, 4) Spacer() - .frame(minWidth: 48, maxWidth: .infinity, alignment: .leading) - MessageContainer(message: message, isOutgoing: true) - .padding(.all, 8) } } - // HStack { - // if isIncoming() { - // HStack - // } - // // if isIncoming() { - // // Image(systemName: "person.fill") - // // .foregroundColor(Color.Main.black) - // // .frame(width: 32, height: 32) - // // .background(Color.Main.backgroundLight) - // // .clipShape(Circle()) - // // Text(message.body ?? "...") - // // .padding(.all, 8) - // // .background(Color.Main.backgroundLight) - // // .clipShape(RoundedRectangle(cornerRadius: 8)) - // // .foregroundColor(Color.Main.black) - // // } else { - // // Text(message.body ?? "--NO BODY?--") - // // .padding(.all, 8) - // // .background(Color.Main.backgroundLight) - // // .clipShape(RoundedRectangle(cornerRadius: 8)) - // // .foregroundColor(Color.Main.black) - // // Image(systemName: "person.fill") - // // .foregroundColor(Color.Main.black) - // // .frame(width: 32, height: 32) - // // .background(Color.Main.backgroundLight) - // // .clipShape(Circle()) - // // } - // } - // .padding(.horizontal, 16) + .padding(.vertical, 10) + .padding(.horizontal, 16) } .sharedListRow() } - private func isIncoming() -> Bool { - message.from != store.state.conversationsState.currentChat?.account + 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 MessageTime: View { + let message: Message + + var body: some View { + Text(message.date, style: .time) + .font(.sub2) + .foregroundColor(Color.Main.gray) + } +} + +// 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() + ), + 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()), + Message(id: "3", type: .chat, contentType: .text, from: contact, to: acc, body: "this is for test", subject: nil, thread: nil, oobUrl: nil, date: Date()), + 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()), + 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()), + 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()), + 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() + ), + Message(id: "8", type: .chat, contentType: .text, from: acc, to: contact, body: "so test", subject: nil, thread: nil, oobUrl: nil, date: Date()), + Message(id: "9", type: .chat, contentType: .text, from: contact, to: acc, body: "so test", subject: nil, thread: nil, oobUrl: nil, date: Date()), + 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()), + Message(id: "11", type: .chat, contentType: .text, from: contact, to: acc, body: "xD", subject: nil, thread: nil, oobUrl: nil, date: Date()) + ] + return state + } + } +#endif diff --git a/ConversationsClassic/View/UIToolkit/Typography.swift b/ConversationsClassic/View/UIToolkit/Typography.swift index 17ed3a9..db856f3 100644 --- a/ConversationsClassic/View/UIToolkit/Typography.swift +++ b/ConversationsClassic/View/UIToolkit/Typography.swift @@ -9,4 +9,5 @@ extension Font { static let body2 = Font.system(size: 16, weight: .regular, design: .rounded) static let body3 = Font.system(size: 14, weight: .regular, design: .rounded) static let sub1 = Font.system(size: 10, weight: .regular, design: .rounded) + static let sub2 = Font.system(size: 8, weight: .regular, design: .rounded) }