From 34a6686a58bf953db354e178168ee87fadf8bc2f Mon Sep 17 00:00:00 2001 From: "Artemas J. Radik" Date: Thu, 2 Jul 2020 21:38:58 -0400 Subject: [PATCH 01/17] Resolved a few typos. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5800462e..ce5e09ac 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ The `MessageInputBar`, derrived from [InputBarAccessoryView](https://github.com/ Please have a look at the [Quick Start guide](https://github.com/MessageKit/MessageKit/blob/master/Documentation/QuickStart.md) and the [FAQs](https://github.com/MessageKit/MessageKit/blob/master/Documentation/FAQs.md). -We recommend you start by looking at the [Example](https://github.com/MessageKit/MessageKit/tree/master/Example) project or write a question with the "messagekit" tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/messagekit). You can also look at previous issues here on GitHib with the **"Question"** tag. +We recommend you start by looking at the [Example](https://github.com/MessageKit/MessageKit/tree/master/Example) project or write a question with the "messagekit" tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/messagekit). You can also look at previous issues here on GitHub with the **"Question"** tag. For more on how to use the MessageInputBar, see the dependency it is based on [InputBarAccessoryView](https://github.com/nathantannar4/InputBarAccessoryView). You can also see this [short guide]([https://github.com/MessageKit/MessageKit/blob/master/Documentation/MessageInputBar.md) @@ -138,7 +138,7 @@ Great! Look over these things first. - Download the project and check out the current code base. Suggest any improvements by opening a new issue. - Check out the [What's Next](#whats-next) section :point_down: to see where we are headed. - Check [StackOverflow](https://stackoverflow.com/questions/tagged/messagekit) -- Install [SwiftLint](https://github.com/realm/SwiftLint) too keep yourself in :neckbeard: style. +- Install [SwiftLint](https://github.com/realm/SwiftLint) to keep yourself in :neckbeard: style. - Be kind and helpful. From 28fb0b9fa7b20f935cfd0250f91525ec5ac617ff Mon Sep 17 00:00:00 2001 From: Artemas Radik Date: Thu, 2 Jul 2020 22:02:13 -0400 Subject: [PATCH 02/17] empty commit for test re-run CL job From 555b750409bda7079b8f10442913b5e21e358fdb Mon Sep 17 00:00:00 2001 From: Kevin Dice Date: Mon, 6 Jul 2020 13:19:36 -0500 Subject: [PATCH 03/17] Add HitchPin to apps using list in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ce5e09ac..2c3a2601 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,7 @@ Add your app to the list of apps using this library and make a pull request. - [Studievenn](https://studievenn.no) - [SmooveText](https://apps.apple.com/np/app/smoove-text/id1362792811) - [COYO Engage](https://apps.apple.com/app/coyo-engage/id1341588804) +- [HitchPin](https://www.hitchpin.com) *Please provide attribution, it is greatly appreciated.* From 5bb16cbf038b1d3aa5628e0d441c1d9da7d93e14 Mon Sep 17 00:00:00 2001 From: Kino Date: Sat, 18 Jul 2020 13:41:49 -0700 Subject: [PATCH 04/17] Add MessagesView wrapping MessageViewController --- Example/ChatExample.xcodeproj/project.pbxproj | 8 ++ Example/Podfile.lock | 2 +- Example/Sources/Views/MessagesView.swift | 95 +++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 Example/Sources/Views/MessagesView.swift diff --git a/Example/ChatExample.xcodeproj/project.pbxproj b/Example/ChatExample.xcodeproj/project.pbxproj index 89a85340..7ae86dd0 100644 --- a/Example/ChatExample.xcodeproj/project.pbxproj +++ b/Example/ChatExample.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 1C5433DD24C389C300A5383B /* MessagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5433DC24C389C300A5383B /* MessagesView.swift */; }; + 1C5433DF24C38DBF00A5383B /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C5433DE24C38DBF00A5383B /* SwiftUI.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 383B9EB32172A1C4008AB91A /* MockUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383B9EB22172A1C4008AB91A /* MockUser.swift */; }; 385C2922211FF32E0010B4BA /* CustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 385C2920211FF32E0010B4BA /* CustomCell.swift */; }; 385C2923211FF32E0010B4BA /* TableViewCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = 385C2921211FF32E0010B4BA /* TableViewCells.swift */; }; @@ -71,6 +73,8 @@ /* Begin PBXFileReference section */ 0364943D08CDBE656E6F6DF8 /* Pods-ChatExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChatExampleTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ChatExampleTests/Pods-ChatExampleTests.debug.xcconfig"; sourceTree = ""; }; + 1C5433DC24C389C300A5383B /* MessagesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesView.swift; sourceTree = ""; }; + 1C5433DE24C38DBF00A5383B /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; 2AC6E3F5C11E39F57598DBE6 /* Pods_ChatExampleUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ChatExampleUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 383B9EB22172A1C4008AB91A /* MockUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUser.swift; sourceTree = ""; }; 385C2920211FF32E0010B4BA /* CustomCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomCell.swift; sourceTree = ""; }; @@ -119,6 +123,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 1C5433DF24C38DBF00A5383B /* SwiftUI.framework in Frameworks */, C7CA53A1B85256A5097E7DC7 /* Pods_ChatExample.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -147,6 +152,7 @@ children = ( 385C2920211FF32E0010B4BA /* CustomCell.swift */, 385C2921211FF32E0010B4BA /* TableViewCells.swift */, + 1C5433DC24C389C300A5383B /* MessagesView.swift */, ); path = Views; sourceTree = ""; @@ -295,6 +301,7 @@ B0B06214A325DCCE2620950A /* Frameworks */ = { isa = PBXGroup; children = ( + 1C5433DE24C38DBF00A5383B /* SwiftUI.framework */, 3B316705C4717C3B4C916D62 /* Pods_ChatExample.framework */, 56F0AC85B38034EC92CCBC7D /* Pods_ChatExampleTests.framework */, 2AC6E3F5C11E39F57598DBE6 /* Pods_ChatExampleUITests.framework */, @@ -550,6 +557,7 @@ 385C2943211FF38F0010B4BA /* SettingsViewController.swift in Sources */, 385C2927211FF33B0010B4BA /* MockSocket.swift in Sources */, 385C2947211FF38F0010B4BA /* BasicExampleViewController.swift in Sources */, + 1C5433DD24C389C300A5383B /* MessagesView.swift in Sources */, 882B5E811CF7D53600B6E160 /* AppDelegate.swift in Sources */, 385C292D211FF3520010B4BA /* CustomMessageFlowLayout.swift in Sources */, 38CCCC592258419300DD5482 /* AutocompleteExampleViewController.swift in Sources */, diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 8bd75481..0d697a90 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -22,4 +22,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 90bd12ca685503630d7fe716609f4974660ed5ee -COCOAPODS: 1.9.1 +COCOAPODS: 1.9.3 diff --git a/Example/Sources/Views/MessagesView.swift b/Example/Sources/Views/MessagesView.swift new file mode 100644 index 00000000..936f6e96 --- /dev/null +++ b/Example/Sources/Views/MessagesView.swift @@ -0,0 +1,95 @@ +// +// MessagesView.swift +// ChatExample +// +// Created by Kino Roy on 2020-07-18. +// Copyright © 2020 MessageKit. All rights reserved. +// + +#if canImport(SwiftUI) + +import SwiftUI +import MessageKit + +class MessageSwiftUIVC: MessagesViewController { + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + becomeFirstResponder() + } +} + +@available(iOS 13.0.0, *) +struct MessagesView: UIViewControllerRepresentable { + + @Binding var messages: [MessageType] + + func makeUIViewController(context: Context) -> MessagesViewController { + let messagesVC = MessageSwiftUIVC() + + messagesVC.messagesCollectionView.messagesDisplayDelegate = context.coordinator + messagesVC.messagesCollectionView.messagesLayoutDelegate = context.coordinator + messagesVC.messagesCollectionView.messagesDataSource = context.coordinator + + return messagesVC + } + + func updateUIViewController(_ uiViewController: MessagesViewController, context: Context) { + if !uiViewController.isFirstResponder { + uiViewController.becomeFirstResponder() + } + uiViewController.messagesCollectionView.reloadData() + } + + func makeCoordinator() -> Coordinator { + return Coordinator(messages: $messages) + } + + final class Coordinator { + var messages: Binding<[MessageType]> + init(messages: Binding<[MessageType]>) { + self.messages = messages + } + } + +} + +@available(iOS 13.0.0, *) +extension MessagesView.Coordinator: MessagesDataSource { + func currentSender() -> SenderType { + return MockUser(senderId: "", displayName: "") + } + + func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType { + return messages.wrappedValue[indexPath.section] + } + + func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int { + return messages.wrappedValue.count + } +} + +@available(iOS 13.0.0, *) +extension MessagesView.Coordinator: MessagesLayoutDelegate, MessagesDisplayDelegate { + +} + +@available(iOS 13.0.0, *) +struct MessageViewPreviewWrapper: View { + @State var messages = [MessageType]() + var body: some View { + MessagesView(messages: $messages).onAppear { + SampleData.shared.getMessages(count: 20) { messages in + self.messages.append(contentsOf: messages) + } + } + } +} + +@available(iOS 13.0.0, *) +struct MessagesView_Previews: PreviewProvider { + static var previews: some View { + MessageViewPreviewWrapper() + } +} + +#endif From 2436db9f5d7ee5a625069972b751bbe70414753f Mon Sep 17 00:00:00 2001 From: Kino Date: Sat, 18 Jul 2020 14:14:53 -0700 Subject: [PATCH 05/17] Add SwiftUI Example to launchVC --- .../Sources/View Controllers/LaunchViewController.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Example/Sources/View Controllers/LaunchViewController.swift b/Example/Sources/View Controllers/LaunchViewController.swift index 50794115..eb421c3f 100644 --- a/Example/Sources/View Controllers/LaunchViewController.swift +++ b/Example/Sources/View Controllers/LaunchViewController.swift @@ -25,6 +25,9 @@ import UIKit import MessageKit import SafariServices +#if canImport(SwiftUI) +import SwiftUI +#endif final internal class LaunchViewController: UITableViewController { @@ -32,7 +35,7 @@ final internal class LaunchViewController: UITableViewController { return .lightContent } - let cells = ["Basic Example", "Advanced Example", "Autocomplete Example", "Embedded Example", "Settings", "Source Code", "Contributors"] + let cells = ["Basic Example", "Advanced Example", "Autocomplete Example", "Embedded Example", "SwiftUI Example", "Settings", "Source Code", "Contributors"] // MARK: - View Life Cycle @@ -84,6 +87,10 @@ final internal class LaunchViewController: UITableViewController { navigationController?.pushViewController(AutocompleteExampleViewController(), animated: true) case "Embedded Example": navigationController?.pushViewController(MessageContainerController(), animated: true) + case "SwiftUI Example": + if #available(iOS 13, *) { + navigationController?.pushViewController(UIHostingController(rootView: MessageViewPreviewWrapper()), animated: true) + } case "Settings": navigationController?.pushViewController(SettingsViewController(), animated: true) case "Source Code": From 2f6a2a14a0d2b86ee79470341bcdae39694ecd7d Mon Sep 17 00:00:00 2001 From: Kino Date: Sat, 18 Jul 2020 14:32:51 -0700 Subject: [PATCH 06/17] Configure avatarView, currentSender --- Example/Sources/Views/MessagesView.swift | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Example/Sources/Views/MessagesView.swift b/Example/Sources/Views/MessagesView.swift index 936f6e96..d0799b55 100644 --- a/Example/Sources/Views/MessagesView.swift +++ b/Example/Sources/Views/MessagesView.swift @@ -7,8 +7,8 @@ // #if canImport(SwiftUI) - import SwiftUI +#endif import MessageKit class MessageSwiftUIVC: MessagesViewController { @@ -56,7 +56,7 @@ struct MessagesView: UIViewControllerRepresentable { @available(iOS 13.0.0, *) extension MessagesView.Coordinator: MessagesDataSource { func currentSender() -> SenderType { - return MockUser(senderId: "", displayName: "") + return SampleData.shared.currentSender } func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType { @@ -70,7 +70,10 @@ extension MessagesView.Coordinator: MessagesDataSource { @available(iOS 13.0.0, *) extension MessagesView.Coordinator: MessagesLayoutDelegate, MessagesDisplayDelegate { - + func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) { + let avatar = SampleData.shared.getAvatarFor(sender: message.sender) + avatarView.set(avatar: avatar) + } } @available(iOS 13.0.0, *) @@ -91,5 +94,3 @@ struct MessagesView_Previews: PreviewProvider { MessageViewPreviewWrapper() } } - -#endif From f481519da487855dd42ff5f3461fc915e63a0137 Mon Sep 17 00:00:00 2001 From: Kino Date: Sat, 18 Jul 2020 15:04:37 -0700 Subject: [PATCH 07/17] Create SwiftUIExampleView to show use of MessagesView and data binding --- Example/ChatExample.xcodeproj/project.pbxproj | 14 +++++++- .../LaunchViewController.swift | 2 +- .../Views/{ => SwiftUI}/MessagesView.swift | 27 +++----------- .../Views/SwiftUI/SwiftUIExampleView.swift | 35 +++++++++++++++++++ 4 files changed, 54 insertions(+), 24 deletions(-) rename Example/Sources/Views/{ => SwiftUI}/MessagesView.swift (79%) create mode 100644 Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift diff --git a/Example/ChatExample.xcodeproj/project.pbxproj b/Example/ChatExample.xcodeproj/project.pbxproj index 7ae86dd0..61469c22 100644 --- a/Example/ChatExample.xcodeproj/project.pbxproj +++ b/Example/ChatExample.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 1C5433DD24C389C300A5383B /* MessagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5433DC24C389C300A5383B /* MessagesView.swift */; }; 1C5433DF24C38DBF00A5383B /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C5433DE24C38DBF00A5383B /* SwiftUI.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 1C5433E224C3A33600A5383B /* SwiftUIExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5433E124C3A33600A5383B /* SwiftUIExampleView.swift */; }; 383B9EB32172A1C4008AB91A /* MockUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383B9EB22172A1C4008AB91A /* MockUser.swift */; }; 385C2922211FF32E0010B4BA /* CustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 385C2920211FF32E0010B4BA /* CustomCell.swift */; }; 385C2923211FF32E0010B4BA /* TableViewCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = 385C2921211FF32E0010B4BA /* TableViewCells.swift */; }; @@ -75,6 +76,7 @@ 0364943D08CDBE656E6F6DF8 /* Pods-ChatExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChatExampleTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ChatExampleTests/Pods-ChatExampleTests.debug.xcconfig"; sourceTree = ""; }; 1C5433DC24C389C300A5383B /* MessagesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesView.swift; sourceTree = ""; }; 1C5433DE24C38DBF00A5383B /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; + 1C5433E124C3A33600A5383B /* SwiftUIExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIExampleView.swift; sourceTree = ""; }; 2AC6E3F5C11E39F57598DBE6 /* Pods_ChatExampleUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ChatExampleUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 383B9EB22172A1C4008AB91A /* MockUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUser.swift; sourceTree = ""; }; 385C2920211FF32E0010B4BA /* CustomCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomCell.swift; sourceTree = ""; }; @@ -147,12 +149,21 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1C5433E024C3A32400A5383B /* SwiftUI */ = { + isa = PBXGroup; + children = ( + 1C5433DC24C389C300A5383B /* MessagesView.swift */, + 1C5433E124C3A33600A5383B /* SwiftUIExampleView.swift */, + ); + path = SwiftUI; + sourceTree = ""; + }; 385C2924211FF3310010B4BA /* Views */ = { isa = PBXGroup; children = ( + 1C5433E024C3A32400A5383B /* SwiftUI */, 385C2920211FF32E0010B4BA /* CustomCell.swift */, 385C2921211FF32E0010B4BA /* TableViewCells.swift */, - 1C5433DC24C389C300A5383B /* MessagesView.swift */, ); path = Views; sourceTree = ""; @@ -541,6 +552,7 @@ files = ( 385C2922211FF32E0010B4BA /* CustomCell.swift in Sources */, 385C2946211FF38F0010B4BA /* LaunchViewController.swift in Sources */, + 1C5433E224C3A33600A5383B /* SwiftUIExampleView.swift in Sources */, 385C2939211FF37B0010B4BA /* Lorem.swift in Sources */, 385C2928211FF33B0010B4BA /* MockMessage.swift in Sources */, 385C2923211FF32E0010B4BA /* TableViewCells.swift in Sources */, diff --git a/Example/Sources/View Controllers/LaunchViewController.swift b/Example/Sources/View Controllers/LaunchViewController.swift index eb421c3f..17a57e88 100644 --- a/Example/Sources/View Controllers/LaunchViewController.swift +++ b/Example/Sources/View Controllers/LaunchViewController.swift @@ -89,7 +89,7 @@ final internal class LaunchViewController: UITableViewController { navigationController?.pushViewController(MessageContainerController(), animated: true) case "SwiftUI Example": if #available(iOS 13, *) { - navigationController?.pushViewController(UIHostingController(rootView: MessageViewPreviewWrapper()), animated: true) + navigationController?.pushViewController(UIHostingController(rootView: SwiftUIExampleView()), animated: true) } case "Settings": navigationController?.pushViewController(SettingsViewController(), animated: true) diff --git a/Example/Sources/Views/MessagesView.swift b/Example/Sources/Views/SwiftUI/MessagesView.swift similarity index 79% rename from Example/Sources/Views/MessagesView.swift rename to Example/Sources/Views/SwiftUI/MessagesView.swift index d0799b55..631c3f50 100644 --- a/Example/Sources/Views/MessagesView.swift +++ b/Example/Sources/Views/SwiftUI/MessagesView.swift @@ -14,7 +14,9 @@ import MessageKit class MessageSwiftUIVC: MessagesViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) + // Because SwiftUI wont automatically make our controller the first responder, we need to do it on viewDidAppear becomeFirstResponder() + messagesCollectionView.scrollToBottom(animated: true) } } @@ -34,10 +36,10 @@ struct MessagesView: UIViewControllerRepresentable { } func updateUIViewController(_ uiViewController: MessagesViewController, context: Context) { - if !uiViewController.isFirstResponder { - uiViewController.becomeFirstResponder() - } uiViewController.messagesCollectionView.reloadData() + DispatchQueue.main.async { + uiViewController.messagesCollectionView.scrollToBottom(animated: true) + } } func makeCoordinator() -> Coordinator { @@ -75,22 +77,3 @@ extension MessagesView.Coordinator: MessagesLayoutDelegate, MessagesDisplayDeleg avatarView.set(avatar: avatar) } } - -@available(iOS 13.0.0, *) -struct MessageViewPreviewWrapper: View { - @State var messages = [MessageType]() - var body: some View { - MessagesView(messages: $messages).onAppear { - SampleData.shared.getMessages(count: 20) { messages in - self.messages.append(contentsOf: messages) - } - } - } -} - -@available(iOS 13.0.0, *) -struct MessagesView_Previews: PreviewProvider { - static var previews: some View { - MessageViewPreviewWrapper() - } -} diff --git a/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift b/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift new file mode 100644 index 00000000..595bab09 --- /dev/null +++ b/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift @@ -0,0 +1,35 @@ +// +// ChatView.swift +// ChatExample +// +// Created by Kino Roy on 2020-07-18. +// Copyright © 2020 MessageKit. All rights reserved. +// + +import SwiftUI +import MessageKit + +@available(iOS 13.0, *) +struct SwiftUIExampleView: View { + @State var messages = [MessageType]() + var body: some View { + MessagesView(messages: $messages).onAppear { + SampleData.shared.getMessages(count: 20) { messages in + self.messages.append(contentsOf: messages) + } + MockSocket.shared.connect(with: [SampleData.shared.nathan, SampleData.shared.wu]).onNewMessage { message in + self.messages.append(message) + } + }.onDisappear { + MockSocket.shared.disconnect() + } + .navigationBarTitle("SwiftUI Example", displayMode: .inline) + } +} + +@available(iOS 13.0.0, *) +struct SwiftUIExampleView_Previews: PreviewProvider { + static var previews: some View { + SwiftUIExampleView() + } +} From dbc7de1132689126a0770640dc49d46988d2c72d Mon Sep 17 00:00:00 2001 From: Kino Date: Sat, 18 Jul 2020 15:27:22 -0700 Subject: [PATCH 08/17] Initialize initial messages inline, add some helper methods --- .../Sources/Data Generation/SampleData.swift | 15 +++++++++ .../Views/SwiftUI/SwiftUIExampleView.swift | 32 ++++++++++++++----- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/Example/Sources/Data Generation/SampleData.swift b/Example/Sources/Data Generation/SampleData.swift index 9fa50d29..30f92311 100644 --- a/Example/Sources/Data Generation/SampleData.swift +++ b/Example/Sources/Data Generation/SampleData.swift @@ -214,6 +214,21 @@ final internal class SampleData { completion(messages) } + func getMessages(count: Int) -> [MockMessage] { + var messages: [MockMessage] = [] + // Disable Custom Messages + UserDefaults.standard.set(false, forKey: "Custom Messages") + for _ in 0.. Void) { var messages: [MockMessage] = [] // Enable Custom Messages diff --git a/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift b/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift index 595bab09..03228cdf 100644 --- a/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift +++ b/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift @@ -11,20 +11,36 @@ import MessageKit @available(iOS 13.0, *) struct SwiftUIExampleView: View { - @State var messages = [MessageType]() + + @State var messages: [MessageType] = SampleData.shared.getMessages(count: 20) + var body: some View { MessagesView(messages: $messages).onAppear { - SampleData.shared.getMessages(count: 20) { messages in - self.messages.append(contentsOf: messages) - } - MockSocket.shared.connect(with: [SampleData.shared.nathan, SampleData.shared.wu]).onNewMessage { message in - self.messages.append(message) - } + self.connectToMessageSocket() }.onDisappear { - MockSocket.shared.disconnect() + self.cleanupSocket() } .navigationBarTitle("SwiftUI Example", displayMode: .inline) } + + private func getInitialMessages() { + SampleData.shared.getMessages(count: 20) { messages in + DispatchQueue.main.async { + self.messages.append(contentsOf: messages) + } + } + } + + private func connectToMessageSocket() { + MockSocket.shared.connect(with: [SampleData.shared.nathan, SampleData.shared.wu]).onNewMessage { message in + self.messages.append(message) + } + } + + private func cleanupSocket() { + MockSocket.shared.disconnect() + } + } @available(iOS 13.0.0, *) From e9e524c4653ebf9f1c35095fa62543574f0aa2e4 Mon Sep 17 00:00:00 2001 From: Kino Date: Sat, 18 Jul 2020 15:27:56 -0700 Subject: [PATCH 09/17] Keep an initialized @State variable so we don't scrollToBottom animated the first time --- Example/Sources/Views/SwiftUI/MessagesView.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Example/Sources/Views/SwiftUI/MessagesView.swift b/Example/Sources/Views/SwiftUI/MessagesView.swift index 631c3f50..fa49e174 100644 --- a/Example/Sources/Views/SwiftUI/MessagesView.swift +++ b/Example/Sources/Views/SwiftUI/MessagesView.swift @@ -23,6 +23,7 @@ class MessageSwiftUIVC: MessagesViewController { @available(iOS 13.0.0, *) struct MessagesView: UIViewControllerRepresentable { + @State var initialized = false @Binding var messages: [MessageType] func makeUIViewController(context: Context) -> MessagesViewController { @@ -37,8 +38,14 @@ struct MessagesView: UIViewControllerRepresentable { func updateUIViewController(_ uiViewController: MessagesViewController, context: Context) { uiViewController.messagesCollectionView.reloadData() + scrollToBottom(uiViewController) + } + + private func scrollToBottom(_ uiViewController: MessagesViewController) { DispatchQueue.main.async { - uiViewController.messagesCollectionView.scrollToBottom(animated: true) + // The initialized state variable allows us to start at the bottom with the initial messages without seeing the inital scroll flash by + uiViewController.messagesCollectionView.scrollToBottom(animated: self.initialized) + self.initialized = true } } From 76ac0722c34b6a1cbf2df87ecf01286b180eaa76 Mon Sep 17 00:00:00 2001 From: Kino Date: Sat, 18 Jul 2020 15:32:48 -0700 Subject: [PATCH 10/17] add #if canImport for SwiftUI --- Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift b/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift index 03228cdf..3485b0e3 100644 --- a/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift +++ b/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift @@ -6,7 +6,9 @@ // Copyright © 2020 MessageKit. All rights reserved. // +#if canImport(SwiftUI) import SwiftUI +#endif import MessageKit @available(iOS 13.0, *) From 0f3e7cfe3b3913e3ce3ab614d702a1ae53541ddd Mon Sep 17 00:00:00 2001 From: Kino Date: Sat, 18 Jul 2020 15:49:22 -0700 Subject: [PATCH 11/17] Add message sending ability by conforming Coordinator to InputBarAccessoryViewDelegate --- Example/Sources/Views/SwiftUI/MessagesView.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Example/Sources/Views/SwiftUI/MessagesView.swift b/Example/Sources/Views/SwiftUI/MessagesView.swift index fa49e174..cc04a6f5 100644 --- a/Example/Sources/Views/SwiftUI/MessagesView.swift +++ b/Example/Sources/Views/SwiftUI/MessagesView.swift @@ -10,6 +10,7 @@ import SwiftUI #endif import MessageKit +import InputBarAccessoryView class MessageSwiftUIVC: MessagesViewController { override func viewDidAppear(_ animated: Bool) { @@ -32,6 +33,7 @@ struct MessagesView: UIViewControllerRepresentable { messagesVC.messagesCollectionView.messagesDisplayDelegate = context.coordinator messagesVC.messagesCollectionView.messagesLayoutDelegate = context.coordinator messagesVC.messagesCollectionView.messagesDataSource = context.coordinator + messagesVC.messageInputBar.delegate = context.coordinator return messagesVC } @@ -77,6 +79,15 @@ extension MessagesView.Coordinator: MessagesDataSource { } } +@available(iOS 13.0.0, *) +extension MessagesView.Coordinator: InputBarAccessoryViewDelegate { + func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String) { + let message = MockMessage(text: text, user: SampleData.shared.currentSender, messageId: UUID().uuidString, date: Date()) + messages.wrappedValue.append(message) + inputBar.inputTextView.text = "" + } +} + @available(iOS 13.0.0, *) extension MessagesView.Coordinator: MessagesLayoutDelegate, MessagesDisplayDelegate { func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) { From 6ff4bd7bc0df57c3bc401ef7d03e07bb923c2f1b Mon Sep 17 00:00:00 2001 From: Kino Date: Sat, 18 Jul 2020 15:57:21 -0700 Subject: [PATCH 12/17] Scroll to bottom on keyboard begins editing --- Example/Sources/Views/SwiftUI/MessagesView.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Example/Sources/Views/SwiftUI/MessagesView.swift b/Example/Sources/Views/SwiftUI/MessagesView.swift index cc04a6f5..efd7843d 100644 --- a/Example/Sources/Views/SwiftUI/MessagesView.swift +++ b/Example/Sources/Views/SwiftUI/MessagesView.swift @@ -34,6 +34,8 @@ struct MessagesView: UIViewControllerRepresentable { messagesVC.messagesCollectionView.messagesLayoutDelegate = context.coordinator messagesVC.messagesCollectionView.messagesDataSource = context.coordinator messagesVC.messageInputBar.delegate = context.coordinator + messagesVC.scrollsToBottomOnKeyboardBeginsEditing = true // default false + messagesVC.maintainPositionOnKeyboardFrameChanged = true // default false return messagesVC } From a9a17956cbbc37319e119f1a61294c311935ad70 Mon Sep 17 00:00:00 2001 From: Kino Date: Sat, 18 Jul 2020 15:57:40 -0700 Subject: [PATCH 13/17] Add message top and bottom labels for name and time --- .../Sources/Views/SwiftUI/MessagesView.swift | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Example/Sources/Views/SwiftUI/MessagesView.swift b/Example/Sources/Views/SwiftUI/MessagesView.swift index efd7843d..cb82ed92 100644 --- a/Example/Sources/Views/SwiftUI/MessagesView.swift +++ b/Example/Sources/Views/SwiftUI/MessagesView.swift @@ -58,10 +58,18 @@ struct MessagesView: UIViewControllerRepresentable { } final class Coordinator { + + let formatter: DateFormatter = { + let formatter = DateFormatter() + formatter.dateStyle = .medium + return formatter + }() + var messages: Binding<[MessageType]> init(messages: Binding<[MessageType]>) { self.messages = messages } + } } @@ -79,6 +87,16 @@ extension MessagesView.Coordinator: MessagesDataSource { func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int { return messages.wrappedValue.count } + + func messageTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? { + let name = message.sender.displayName + return NSAttributedString(string: name, attributes: [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .caption1)]) + } + + func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? { + let dateString = formatter.string(from: message.sentDate) + return NSAttributedString(string: dateString, attributes: [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .caption2)]) + } } @available(iOS 13.0.0, *) @@ -96,4 +114,11 @@ extension MessagesView.Coordinator: MessagesLayoutDelegate, MessagesDisplayDeleg let avatar = SampleData.shared.getAvatarFor(sender: message.sender) avatarView.set(avatar: avatar) } + func messageTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat { + return 20 + } + + func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat { + return 16 + } } From 93036d49d2eab7c356d591ca6afbbdac2f23e22d Mon Sep 17 00:00:00 2001 From: Kino Date: Sat, 18 Jul 2020 16:36:58 -0700 Subject: [PATCH 14/17] Remove unused getInitialMessages method --- Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift b/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift index 3485b0e3..434e0dea 100644 --- a/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift +++ b/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift @@ -25,14 +25,6 @@ struct SwiftUIExampleView: View { .navigationBarTitle("SwiftUI Example", displayMode: .inline) } - private func getInitialMessages() { - SampleData.shared.getMessages(count: 20) { messages in - DispatchQueue.main.async { - self.messages.append(contentsOf: messages) - } - } - } - private func connectToMessageSocket() { MockSocket.shared.connect(with: [SampleData.shared.nathan, SampleData.shared.wu]).onNewMessage { message in self.messages.append(message) From 8b848dfefe893623a62e61ea9372c774f4e5199c Mon Sep 17 00:00:00 2001 From: Kino Date: Sat, 18 Jul 2020 21:56:58 -0700 Subject: [PATCH 15/17] Don't attempt to build with 32 bit architectures SwiftUI doesn't include symbols for 32-bit archs so xcodebuild fails, and there is no reason to build the example app for 32 bit archs --- Example/Podfile.lock | 2 +- Example/Sources/View Controllers/LaunchViewController.swift | 2 -- Example/Sources/Views/SwiftUI/MessagesView.swift | 2 -- Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift | 2 -- GitHubActions/build.sh | 2 +- 5 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 0d697a90..8bd75481 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -22,4 +22,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 90bd12ca685503630d7fe716609f4974660ed5ee -COCOAPODS: 1.9.3 +COCOAPODS: 1.9.1 diff --git a/Example/Sources/View Controllers/LaunchViewController.swift b/Example/Sources/View Controllers/LaunchViewController.swift index 17a57e88..d5990063 100644 --- a/Example/Sources/View Controllers/LaunchViewController.swift +++ b/Example/Sources/View Controllers/LaunchViewController.swift @@ -25,9 +25,7 @@ import UIKit import MessageKit import SafariServices -#if canImport(SwiftUI) import SwiftUI -#endif final internal class LaunchViewController: UITableViewController { diff --git a/Example/Sources/Views/SwiftUI/MessagesView.swift b/Example/Sources/Views/SwiftUI/MessagesView.swift index cb82ed92..1cf94f79 100644 --- a/Example/Sources/Views/SwiftUI/MessagesView.swift +++ b/Example/Sources/Views/SwiftUI/MessagesView.swift @@ -6,9 +6,7 @@ // Copyright © 2020 MessageKit. All rights reserved. // -#if canImport(SwiftUI) import SwiftUI -#endif import MessageKit import InputBarAccessoryView diff --git a/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift b/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift index 434e0dea..b117430d 100644 --- a/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift +++ b/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift @@ -6,9 +6,7 @@ // Copyright © 2020 MessageKit. All rights reserved. // -#if canImport(SwiftUI) import SwiftUI -#endif import MessageKit @available(iOS 13.0, *) diff --git a/GitHubActions/build.sh b/GitHubActions/build.sh index 3f998f9a..7bcd40ea 100755 --- a/GitHubActions/build.sh +++ b/GitHubActions/build.sh @@ -53,7 +53,7 @@ if [ "$MODE" = "example" -o "$MODE" = "all" ]; then gem install bundler bundle check || bundle install bundle exec pod install - set -o pipefail && xcodebuild build analyze -workspace ChatExample.xcworkspace -scheme ChatExample -destination "platform=iOS Simulator,name=iPhone 11 Pro" ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO | xcpretty -c + set -o pipefail && xcodebuild build analyze -workspace ChatExample.xcworkspace -scheme ChatExample -destination "platform=iOS Simulator,name=iPhone 11 Pro" CODE_SIGNING_REQUIRED=NO | xcpretty -c success="1" fi From e4405580d223d53b67898df85b80555d2efb905b Mon Sep 17 00:00:00 2001 From: Kino Date: Fri, 24 Jul 2020 12:27:33 -0700 Subject: [PATCH 16/17] Address code review --- Example/Sources/Views/SwiftUI/MessagesView.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Example/Sources/Views/SwiftUI/MessagesView.swift b/Example/Sources/Views/SwiftUI/MessagesView.swift index 1cf94f79..4247ce2f 100644 --- a/Example/Sources/Views/SwiftUI/MessagesView.swift +++ b/Example/Sources/Views/SwiftUI/MessagesView.swift @@ -10,7 +10,7 @@ import SwiftUI import MessageKit import InputBarAccessoryView -class MessageSwiftUIVC: MessagesViewController { +final class MessageSwiftUIVC: MessagesViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // Because SwiftUI wont automatically make our controller the first responder, we need to do it on viewDidAppear @@ -19,7 +19,7 @@ class MessageSwiftUIVC: MessagesViewController { } } -@available(iOS 13.0.0, *) +@available(iOS 13.0, *) struct MessagesView: UIViewControllerRepresentable { @State var initialized = false @@ -72,7 +72,7 @@ struct MessagesView: UIViewControllerRepresentable { } -@available(iOS 13.0.0, *) +@available(iOS 13.0, *) extension MessagesView.Coordinator: MessagesDataSource { func currentSender() -> SenderType { return SampleData.shared.currentSender @@ -97,7 +97,7 @@ extension MessagesView.Coordinator: MessagesDataSource { } } -@available(iOS 13.0.0, *) +@available(iOS 13.0, *) extension MessagesView.Coordinator: InputBarAccessoryViewDelegate { func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String) { let message = MockMessage(text: text, user: SampleData.shared.currentSender, messageId: UUID().uuidString, date: Date()) @@ -106,7 +106,7 @@ extension MessagesView.Coordinator: InputBarAccessoryViewDelegate { } } -@available(iOS 13.0.0, *) +@available(iOS 13.0, *) extension MessagesView.Coordinator: MessagesLayoutDelegate, MessagesDisplayDelegate { func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) { let avatar = SampleData.shared.getAvatarFor(sender: message.sender) From c2e41ae804d3656dab5bd0eeac6d4650629be04d Mon Sep 17 00:00:00 2001 From: Kino Date: Fri, 24 Jul 2020 12:29:31 -0700 Subject: [PATCH 17/17] Address code review --- Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift b/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift index b117430d..41d3b0f2 100644 --- a/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift +++ b/Example/Sources/Views/SwiftUI/SwiftUIExampleView.swift @@ -35,7 +35,7 @@ struct SwiftUIExampleView: View { } -@available(iOS 13.0.0, *) +@available(iOS 13.0, *) struct SwiftUIExampleView_Previews: PreviewProvider { static var previews: some View { SwiftUIExampleView()