diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index 2e106cb506..7b28d8c715 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -126,12 +126,26 @@ enum ChatInfo: Identifiable, Decodable { var localDisplayName: String { get { switch self { - case let .direct(contact): return "@\(contact.localDisplayName)" - case let .group(groupInfo): return "#\(groupInfo.localDisplayName)" - case let .contactRequest(contactRequest): return "< @\(contactRequest.localDisplayName)" + case let .direct(contact): return contact.localDisplayName + case let .group(groupInfo): return groupInfo.localDisplayName + case let .contactRequest(contactRequest): return contactRequest.localDisplayName } } } + + var fullName: String { + get { + switch self { + case let .direct(contact): return contact.profile.fullName + case let .group(groupInfo): return groupInfo.groupProfile.fullName + case let .contactRequest(contactRequest): return contactRequest.profile.fullName + } + } + } + + var chatViewName: String { + get { localDisplayName + (fullName == "" || fullName == localDisplayName ? "" : " / \(fullName)") } + } var id: String { get { @@ -162,6 +176,14 @@ enum ChatInfo: Identifiable, Decodable { } } } + + var createdAt: Date { + switch self { + case let .direct(contact): return contact.createdAt + case let .group(groupInfo): return groupInfo.createdAt + case let .contactRequest(contactRequest): return contactRequest.createdAt + } + } } let sampleDirectChatInfo = ChatInfo.direct(contact: sampleContact) @@ -200,6 +222,7 @@ struct Contact: Identifiable, Decodable { var profile: Profile var activeConn: Connection var viaGroup: Int64? + var createdAt: Date var id: String { get { "@\(contactId)" } } var apiId: Int64 { get { contactId } } @@ -210,7 +233,8 @@ let sampleContact = Contact( contactId: 1, localDisplayName: "alice", profile: sampleProfile, - activeConn: sampleConnection + activeConn: sampleConnection, + createdAt: .now ) struct Connection: Decodable { @@ -223,6 +247,7 @@ struct UserContactRequest: Decodable { var contactRequestId: Int64 var localDisplayName: ContactName var profile: Profile + var createdAt: Date var id: String { get { "<@\(contactRequestId)" } } @@ -232,13 +257,15 @@ struct UserContactRequest: Decodable { let sampleContactRequest = UserContactRequest( contactRequestId: 1, localDisplayName: "alice", - profile: sampleProfile + profile: sampleProfile, + createdAt: .now ) struct GroupInfo: Identifiable, Decodable { var groupId: Int64 var localDisplayName: GroupName var groupProfile: GroupProfile + var createdAt: Date var id: String { get { "#\(groupId)" } } @@ -248,7 +275,8 @@ struct GroupInfo: Identifiable, Decodable { let sampleGroupInfo = GroupInfo( groupId: 1, localDisplayName: "team", - groupProfile: sampleGroupProfile + groupProfile: sampleGroupProfile, + createdAt: .now ) struct GroupProfile: Codable { diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 240c565fbb..9d86361960 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -84,6 +84,7 @@ enum ChatResponse: Decodable, Error { case receivedContactRequest(contactRequest: UserContactRequest) case acceptingContactRequest(contact: Contact) case contactRequestRejected + case contactUpdated(toContact: Contact) case newChatItem(chatItem: AChatItem) case chatCmdError(chatError: ChatError) @@ -106,6 +107,7 @@ enum ChatResponse: Decodable, Error { case .receivedContactRequest: return "receivedContactRequest" case .acceptingContactRequest: return "acceptingContactRequest" case .contactRequestRejected: return "contactRequestRejected" + case .contactUpdated: return "contactUpdated" case .newChatItem: return "newChatItem" case .chatCmdError: return "chatCmdError" } @@ -131,6 +133,7 @@ enum ChatResponse: Decodable, Error { case let .receivedContactRequest(contactRequest): return String(describing: contactRequest) case let .acceptingContactRequest(contact): return String(describing: contact) case .contactRequestRejected: return noDetails + case let .contactUpdated(toContact): return String(describing: toContact) case let .newChatItem(chatItem): return String(describing: chatItem) case let .chatCmdError(chatError): return String(describing: chatError) } @@ -293,7 +296,7 @@ func apiRejectContactRequest(contactReqId: Int64) throws { func processReceivedMsg(_ chatModel: ChatModel, _ res: ChatResponse) { DispatchQueue.main.async { - chatModel.terminalItems.append(.resp(Date.now, res)) + chatModel.terminalItems.append(.resp(.now, res)) switch res { case let .contactConnected(contact): let cInfo = ChatInfo.direct(contact: contact) @@ -307,6 +310,11 @@ func processReceivedMsg(_ chatModel: ChatModel, _ res: ChatResponse) { chatInfo: ChatInfo.contactRequest(contactRequest: contactRequest), chatItems: [] )) + case let .contactUpdated(toContact): + let cInfo = ChatInfo.direct(contact: toContact) + if chatModel.hasChat(toContact.id) { + chatModel.updateChatInfo(cInfo) + } case let .newChatItem(aChatItem): chatModel.addChatItem(aChatItem.chatInfo, aChatItem.chatItem) default: diff --git a/apps/ios/Shared/Views/Chat/ChatItem/EmojiItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/EmojiItemView.swift new file mode 100644 index 0000000000..04abdfd9fe --- /dev/null +++ b/apps/ios/Shared/Views/Chat/ChatItem/EmojiItemView.swift @@ -0,0 +1,43 @@ +// +// EmojiItemView.swift +// SimpleX +// +// Created by Evgeny Poberezkin on 04/02/2022. +// Copyright © 2022 SimpleX Chat. All rights reserved. +// + +import SwiftUI + +struct EmojiItemView: View { + var chatItem: ChatItem + + var body: some View { + let sent = chatItem.chatDir.sent + + VStack { + Text(chatItem.content.text) + .font(Font.custom("Emoji", size: 48, relativeTo: .largeTitle)) + .padding(.top, 8) + .padding(.horizontal, 6) + .frame(maxWidth: .infinity, alignment: sent ? .trailing : .leading) + Text(getDateFormatter().string(from: chatItem.meta.itemTs)) + .font(.caption) + .foregroundColor(.secondary) + .padding(.bottom, 8) + .padding(.horizontal, 12) + .frame(maxWidth: .infinity, alignment: sent ? .trailing : .leading) + } + .padding(.horizontal) + .frame(maxWidth: .infinity, alignment: sent ? .trailing : .leading) + } +} + +struct EmojiItemView_Previews: PreviewProvider { + static var previews: some View { + Group{ + EmojiItemView(chatItem: chatItemSample(1, .directSnd, .now, "🙂")) + EmojiItemView(chatItem: chatItemSample(2, .directRcv, .now, "👍")) + } + .previewLayout(.fixed(width: 360, height: 70)) + } +} diff --git a/apps/ios/Shared/Views/Chat/ChatItem/TextItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/TextItemView.swift new file mode 100644 index 0000000000..a9a25b01f2 --- /dev/null +++ b/apps/ios/Shared/Views/Chat/ChatItem/TextItemView.swift @@ -0,0 +1,55 @@ +// +// TextItemView.swift +// SimpleX +// +// Created by Evgeny Poberezkin on 04/02/2022. +// Copyright © 2022 SimpleX Chat. All rights reserved. +// + +import SwiftUI + +struct TextItemView: View { + var chatItem: ChatItem + var width: CGFloat + + var body: some View { + let sent = chatItem.chatDir.sent + let minWidth = min(200, width) + let maxWidth = min(300, width * 0.78) + + return VStack { + Text(chatItem.content.text) + .padding(.top, 8) + .padding(.horizontal, 12) + .frame(minWidth: minWidth, maxWidth: maxWidth, alignment: .leading) + .foregroundColor(sent ? .white : .primary) + .textSelection(.enabled) + Text(getDateFormatter().string(from: chatItem.meta.itemTs)) + .font(.caption) + .foregroundColor(sent ? .white : .secondary) + .padding(.bottom, 8) + .padding(.horizontal, 12) + .frame(minWidth: minWidth, maxWidth: maxWidth, alignment: .trailing) + } + .background(sent ? .blue : Color(uiColor: .tertiarySystemGroupedBackground)) + .cornerRadius(10) + .padding(.horizontal) + .frame( + minWidth: 200, + maxWidth: .infinity, + minHeight: 0, + maxHeight: .infinity, + alignment: sent ? .trailing : .leading + ) + } +} + +struct TextItemView_Previews: PreviewProvider { + static var previews: some View { + Group{ + TextItemView(chatItem: chatItemSample(1, .directSnd, .now, "hello"), width: 360) + TextItemView(chatItem: chatItemSample(2, .directRcv, .now, "hello there too"), width: 360) + } + .previewLayout(.fixed(width: 360, height: 70)) + } +} diff --git a/apps/ios/Shared/Views/Chat/ChatItemView.swift b/apps/ios/Shared/Views/Chat/ChatItemView.swift index 039e64ae72..5375b3304d 100644 --- a/apps/ios/Shared/Views/Chat/ChatItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItemView.swift @@ -12,36 +12,14 @@ private var dateFormatter: DateFormatter? struct ChatItemView: View { var chatItem: ChatItem + var width: CGFloat var body: some View { - let sent = chatItem.chatDir.sent - - return VStack { - Group { - Text(chatItem.content.text) - .padding(.top, 8) - .padding(.horizontal, 12) - .frame(minWidth: 200, maxWidth: 300, alignment: .leading) - .foregroundColor(sent ? .white : .primary) - .textSelection(.enabled) - Text(getDateFormatter().string(from: chatItem.meta.itemTs)) - .font(.subheadline) - .foregroundColor(sent ? .white : .secondary) - .padding(.bottom, 8) - .padding(.horizontal, 12) - .frame(minWidth: 200, maxWidth: 300, alignment: .trailing) - } + if (isShortEmoji(chatItem.content.text)) { + EmojiItemView(chatItem: chatItem) + } else { + TextItemView(chatItem: chatItem, width: width) } - .background(sent ? .blue : Color(uiColor: .tertiarySystemGroupedBackground)) - .cornerRadius(10) - .padding(.horizontal) - .frame( - minWidth: 200, - maxWidth: .infinity, - minHeight: 0, - maxHeight: .infinity, - alignment: sent ? .trailing : .leading - ) } } @@ -56,9 +34,12 @@ func getDateFormatter() -> DateFormatter { struct ChatItemView_Previews: PreviewProvider { static var previews: some View { Group{ - ChatItemView(chatItem: chatItemSample(1, .directSnd, Date.now, "hello")) - ChatItemView(chatItem: chatItemSample(2, .directRcv, Date.now, "hello there too")) + ChatItemView(chatItem: chatItemSample(1, .directSnd, .now, "hello"), width: 360) + ChatItemView(chatItem: chatItemSample(2, .directRcv, .now, "hello there too"), width: 360) + ChatItemView(chatItem: chatItemSample(1, .directSnd, .now, "🙂"), width: 360) + ChatItemView(chatItem: chatItemSample(2, .directRcv, .now, "👍👍👍"), width: 360) + ChatItemView(chatItem: chatItemSample(2, .directRcv, .now, "👍👍👍👍"), width: 360) } - .previewLayout(.fixed(width: 300, height: 70)) + .previewLayout(.fixed(width: 360, height: 70)) } } diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index d6e8849b1f..ce186a3986 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -15,14 +15,16 @@ struct ChatView: View { var body: some View { VStack { - ScrollViewReader { proxy in - ScrollView { - VStack(spacing: 5) { - ForEach(chatModel.chatItems, id: \.id) { - ChatItemView(chatItem: $0) + GeometryReader { g in + ScrollViewReader { proxy in + ScrollView { + VStack(spacing: 5) { + ForEach(chatModel.chatItems, id: \.id) { + ChatItemView(chatItem: $0, width: g.size.width) + } + .onAppear { scrollToBottom(proxy) } + .onChange(of: chatModel.chatItems.count) { _ in scrollToBottom(proxy) } } - .onAppear { scrollToBottom(proxy) } - .onChange(of: chatModel.chatItems.count) { _ in scrollToBottom(proxy) } } } } @@ -31,7 +33,7 @@ struct ChatView: View { SendMessageView(sendMessage: sendMessage, inProgress: inProgress) } - .navigationTitle(chatInfo.localDisplayName) + .navigationTitle(chatInfo.chatViewName) .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button { chatModel.chatId = nil } label: { @@ -68,13 +70,13 @@ struct ChatView_Previews: PreviewProvider { let chatModel = ChatModel() chatModel.chatId = "@1" chatModel.chatItems = [ - chatItemSample(1, .directSnd, Date.now, "hello"), - chatItemSample(2, .directRcv, Date.now, "hi"), - chatItemSample(3, .directRcv, Date.now, "hi there"), - chatItemSample(4, .directRcv, Date.now, "hello again"), - chatItemSample(5, .directSnd, Date.now, "hi there!!!"), - chatItemSample(6, .directSnd, Date.now, "how are you?"), - chatItemSample(7, .directSnd, Date.now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") + chatItemSample(1, .directSnd, .now, "hello"), + chatItemSample(2, .directRcv, .now, "hi"), + chatItemSample(3, .directRcv, .now, "hi there"), + chatItemSample(4, .directRcv, .now, "hello again"), + chatItemSample(5, .directSnd, .now, "hi there!!!"), + chatItemSample(6, .directSnd, .now, "how are you?"), + chatItemSample(7, .directSnd, .now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") ] return ChatView(chatInfo: sampleDirectChatInfo) .environmentObject(chatModel) diff --git a/apps/ios/Shared/Views/Chat/Emoji.swift b/apps/ios/Shared/Views/Chat/Emoji.swift new file mode 100644 index 0000000000..034c12c837 --- /dev/null +++ b/apps/ios/Shared/Views/Chat/Emoji.swift @@ -0,0 +1,27 @@ +// +// Emoji.swift +// SimpleX +// +// Created by Evgeny Poberezkin on 04/02/2022. +// Copyright © 2022 SimpleX Chat. All rights reserved. +// + +import Foundation + +private func isSimpleEmoji(_ c: Character) -> Bool { + guard let firstScalar = c.unicodeScalars.first else { return false } + return firstScalar.properties.isEmoji && firstScalar.value > 0x238C +} + +private func isCombinedIntoEmoji(_ c: Character) -> Bool { + c.unicodeScalars.count > 1 && c.unicodeScalars.first?.properties.isEmoji ?? false +} + +func isEmoji(_ c: Character) -> Bool { + isSimpleEmoji(c) || isCombinedIntoEmoji(c) +} + +func isShortEmoji(_ str: String) -> Bool { + let s = str.trimmingCharacters(in: .whitespaces) + return s.count <= 3 && s.allSatisfy(isEmoji) +} diff --git a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift index 7a4317610b..7899627f55 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift @@ -176,11 +176,11 @@ struct ChatListNavLink_Previews: PreviewProvider { return Group { ChatListNavLink(chat: Chat( chatInfo: sampleDirectChatInfo, - chatItems: [chatItemSample(1, .directSnd, Date.now, "hello")] + chatItems: [chatItemSample(1, .directSnd, .now, "hello")] )) ChatListNavLink(chat: Chat( chatInfo: sampleDirectChatInfo, - chatItems: [chatItemSample(1, .directSnd, Date.now, "hello")] + chatItems: [chatItemSample(1, .directSnd, .now, "hello")] )) ChatListNavLink(chat: Chat( chatInfo: sampleContactRequestChatInfo, diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 3f98418f77..5e24ae3b3a 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -92,11 +92,11 @@ struct ChatListView_Previews: PreviewProvider { chatModel.chats = [ Chat( chatInfo: sampleDirectChatInfo, - chatItems: [chatItemSample(1, .directSnd, Date.now, "hello")] + chatItems: [chatItemSample(1, .directSnd, .now, "hello")] ), Chat( chatInfo: sampleGroupChatInfo, - chatItems: [chatItemSample(1, .directSnd, Date.now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")] + chatItems: [chatItemSample(1, .directSnd, .now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")] ), Chat( chatInfo: sampleContactRequestChatInfo, diff --git a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift index 7447b8cd83..5f4244a98c 100644 --- a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift @@ -13,38 +13,46 @@ struct ChatPreviewView: View { var body: some View { let cItem = chat.chatItems.last - return VStack(spacing: 4) { - HStack(alignment: .top) { - Text(chat.chatInfo.localDisplayName) - .font(.title3) - .fontWeight(.bold) - .padding(.leading, 8) - .padding(.top, 4) - .frame(maxHeight: .infinity, alignment: .topLeading) - Spacer() - if let cItem = cItem { - Text(getDateFormatter().string(from: cItem.meta.itemTs)) + var iconName: String + switch chat.chatInfo { + case .direct: iconName = "person.crop.circle.fill" + case .group: iconName = "person.2.circle.fill" + default: iconName = "circle.fill" + } + return HStack(spacing: 8) { + Image(systemName: iconName) + .resizable() + .foregroundColor(Color(uiColor: .secondarySystemBackground)) + .frame(width: 63, height: 63) + .padding(.leading, 4) + VStack(spacing: 0) { + HStack(alignment: .top) { + Text(chat.chatInfo.chatViewName) + .font(.title3) + .fontWeight(.bold) + .frame(maxHeight: .infinity, alignment: .topLeading) + Spacer() + Text(getDateFormatter().string(from: cItem?.meta.itemTs ?? chat.chatInfo.createdAt)) .font(.subheadline) - .padding(.trailing, 8) - .padding(.top, 4) .frame(minWidth: 60, alignment: .trailing) .foregroundColor(.secondary) } + .padding(.top, 4) + .padding(.horizontal, 8) + + if let cItem = cItem { + Text(cItem.content.text) + .frame(minWidth: 0, maxWidth: .infinity, minHeight: 44, maxHeight: 44, alignment: .topLeading) + .padding([.leading, .trailing], 8) + .padding(.bottom, 4) + } + else if case let .direct(contact) = chat.chatInfo, !contact.connected { + Text("Connecting...") + .frame(minWidth: 0, maxWidth: .infinity, minHeight: 44, maxHeight: 44, alignment: .topLeading) + .padding([.leading, .trailing], 8) + .padding(.bottom, 4) + } } - if let cItem = cItem { - Text(cItem.content.text) - .frame(minWidth: 0, maxWidth: .infinity, minHeight: 44, maxHeight: 44, alignment: .topLeading) - .padding([.leading, .trailing], 8) - .padding(.bottom, 4) - .padding(.top, 1) - } -// else if case let .direct(contact) = chatPreview.chatInfo, !contact.connected { -// Text("Connecting...") -// .frame(minWidth: 0, maxWidth: .infinity, minHeight: 44, maxHeight: 44, alignment: .topLeading) -// .padding([.leading, .trailing], 8) -// .padding(.bottom, 4) -// .padding(.top, 1) -// } } } } @@ -58,13 +66,13 @@ struct ChatPreviewView_Previews: PreviewProvider { )) ChatPreviewView(chat: Chat( chatInfo: sampleDirectChatInfo, - chatItems: [chatItemSample(1, .directSnd, Date.now, "hello")] + chatItems: [chatItemSample(1, .directSnd, .now, "hello")] )) ChatPreviewView(chat: Chat( chatInfo: sampleGroupChatInfo, - chatItems: [chatItemSample(1, .directSnd, Date.now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")] + chatItems: [chatItemSample(1, .directSnd, .now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")] )) } - .previewLayout(.fixed(width: 360, height: 80)) + .previewLayout(.fixed(width: 360, height: 78)) } } diff --git a/apps/ios/Shared/Views/ChatList/ContactRequestView.swift b/apps/ios/Shared/Views/ChatList/ContactRequestView.swift index 140c398d91..3a9e945009 100644 --- a/apps/ios/Shared/Views/ChatList/ContactRequestView.swift +++ b/apps/ios/Shared/Views/ChatList/ContactRequestView.swift @@ -14,7 +14,7 @@ struct ContactRequestView: View { var body: some View { return VStack(alignment: .leading, spacing: 4) { HStack(alignment: .top) { - Text("@\(contactRequest.localDisplayName)") + Text(ChatInfo.contactRequest(contactRequest: contactRequest).chatViewName) .font(.title3) .fontWeight(.bold) .foregroundColor(.blue) @@ -22,7 +22,7 @@ struct ContactRequestView: View { .padding(.top, 4) .frame(maxHeight: .infinity, alignment: .topLeading) Spacer() - Text("12:34")// getDateFormatter().string(from: cItem.meta.itemTs)) + Text(getDateFormatter().string(from: contactRequest.createdAt)) .font(.subheadline) .padding(.trailing, 28) .padding(.top, 4) diff --git a/apps/ios/Shared/Views/TerminalView.swift b/apps/ios/Shared/Views/TerminalView.swift index ee7052f057..0170786053 100644 --- a/apps/ios/Shared/Views/TerminalView.swift +++ b/apps/ios/Shared/Views/TerminalView.swift @@ -52,14 +52,14 @@ struct TerminalView: View { func sendMessage(_ cmdStr: String) { let cmd = ChatCommand.string(cmdStr) - chatModel.terminalItems.append(.cmd(Date.now, cmd)) + chatModel.terminalItems.append(.cmd(.now, cmd)) DispatchQueue.global().async { inProgress = true do { let r = try chatSendCmd(cmd) DispatchQueue.main.async { - chatModel.terminalItems.append(.resp(Date.now, r)) + chatModel.terminalItems.append(.resp(.now, r)) } } catch { print(error) @@ -73,8 +73,8 @@ struct TerminalView_Previews: PreviewProvider { static var previews: some View { let chatModel = ChatModel() chatModel.terminalItems = [ - .resp(Date.now, ChatResponse.response(type: "contactSubscribed", json: "{}")), - .resp(Date.now, ChatResponse.response(type: "newChatItem", json: "{}")) + .resp(.now, ChatResponse.response(type: "contactSubscribed", json: "{}")), + .resp(.now, ChatResponse.response(type: "newChatItem", json: "{}")) ] return NavigationView { TerminalView() diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 91c57f5d57..28a608d78d 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -73,6 +73,12 @@ 5CCD403B27A5F9BE00368C90 /* CreateGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403927A5F9BE00368C90 /* CreateGroupView.swift */; }; 5CE4406F27AD2648007B033A /* libHSsimplex-chat-1.1.0-1RUev578BUjGkBObUSYLQi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE4406D27AD2648007B033A /* libHSsimplex-chat-1.1.0-1RUev578BUjGkBObUSYLQi.a */; }; 5CE4407027AD2648007B033A /* libHSsimplex-chat-1.1.0-1RUev578BUjGkBObUSYLQi-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE4406E27AD2648007B033A /* libHSsimplex-chat-1.1.0-1RUev578BUjGkBObUSYLQi-ghc8.10.7.a */; }; + 5CE4407227ADB1D0007B033A /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE4407127ADB1D0007B033A /* Emoji.swift */; }; + 5CE4407327ADB1D0007B033A /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE4407127ADB1D0007B033A /* Emoji.swift */; }; + 5CE4407627ADB66A007B033A /* TextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE4407527ADB66A007B033A /* TextItemView.swift */; }; + 5CE4407727ADB66A007B033A /* TextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE4407527ADB66A007B033A /* TextItemView.swift */; }; + 5CE4407927ADB701007B033A /* EmojiItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE4407827ADB701007B033A /* EmojiItemView.swift */; }; + 5CE4407A27ADB701007B033A /* EmojiItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE4407827ADB701007B033A /* EmojiItemView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -138,6 +144,9 @@ 5CCD403927A5F9BE00368C90 /* CreateGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateGroupView.swift; sourceTree = ""; }; 5CE4406D27AD2648007B033A /* libHSsimplex-chat-1.1.0-1RUev578BUjGkBObUSYLQi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.1.0-1RUev578BUjGkBObUSYLQi.a"; sourceTree = ""; }; 5CE4406E27AD2648007B033A /* libHSsimplex-chat-1.1.0-1RUev578BUjGkBObUSYLQi-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.1.0-1RUev578BUjGkBObUSYLQi-ghc8.10.7.a"; sourceTree = ""; }; + 5CE4407127ADB1D0007B033A /* Emoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Emoji.swift; sourceTree = ""; }; + 5CE4407527ADB66A007B033A /* TextItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextItemView.swift; sourceTree = ""; }; + 5CE4407827ADB701007B033A /* EmojiItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiItemView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -198,9 +207,11 @@ 5C5F4AC227A5E9AF00B51EF1 /* Chat */ = { isa = PBXGroup; children = ( + 5CE4407427ADB657007B033A /* ChatItem */, 5C2E260E27A30FDC00F70299 /* ChatView.swift */, 5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */, 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */, + 5CE4407127ADB1D0007B033A /* Emoji.swift */, ); path = Chat; sourceTree = ""; @@ -337,6 +348,15 @@ path = ChatList; sourceTree = ""; }; + 5CE4407427ADB657007B033A /* ChatItem */ = { + isa = PBXGroup; + children = ( + 5CE4407527ADB66A007B033A /* TextItemView.swift */, + 5CE4407827ADB701007B033A /* EmojiItemView.swift */, + ); + path = ChatItem; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -506,7 +526,9 @@ files = ( 5C6AD81327A834E300348BD7 /* NewChatButton.swift in Sources */, 5CB924D727A8563F00ACCCDD /* SettingsView.swift in Sources */, + 5CE4407627ADB66A007B033A /* TextItemView.swift in Sources */, 5CB924E127A867BA00ACCCDD /* UserProfile.swift in Sources */, + 5CE4407927ADB701007B033A /* EmojiItemView.swift in Sources */, 5C764E80279C7276000C6508 /* dummy.m in Sources */, 5CB924E427A8683A00ACCCDD /* UserAddress.swift in Sources */, 5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */, @@ -528,6 +550,7 @@ 5CC1C99527A6CF7F000D9FF6 /* ShareSheet.swift in Sources */, 5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */, 5CB924D427A853F100ACCCDD /* SettingsButton.swift in Sources */, + 5CE4407227ADB1D0007B033A /* Emoji.swift in Sources */, 5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -538,7 +561,9 @@ files = ( 5C6AD81427A834E300348BD7 /* NewChatButton.swift in Sources */, 5CB924D827A8563F00ACCCDD /* SettingsView.swift in Sources */, + 5CE4407727ADB66A007B033A /* TextItemView.swift in Sources */, 5CB924E227A867BA00ACCCDD /* UserProfile.swift in Sources */, + 5CE4407A27ADB701007B033A /* EmojiItemView.swift in Sources */, 5C764E81279C7276000C6508 /* dummy.m in Sources */, 5CB924E527A8683A00ACCCDD /* UserAddress.swift in Sources */, 5C063D2827A4564100AEC577 /* ChatPreviewView.swift in Sources */, @@ -560,6 +585,7 @@ 5CC1C99627A6CF7F000D9FF6 /* ShareSheet.swift in Sources */, 5C2E260827A2941F00F70299 /* SimpleXAPI.swift in Sources */, 5CB924D527A853F100ACCCDD /* SettingsButton.swift in Sources */, + 5CE4407327ADB1D0007B033A /* Emoji.swift in Sources */, 5C1A4C1F27A715B700EAD5AD /* ChatItemView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0;