mirror of
https://github.com/MessageKit/MessageKit.git
synced 2026-02-06 19:03:19 +00:00
bff35fda61
* build: Swiftlint plugin * build: Swiftformat plugin * build: Swiftformat plugin * build: Swiftformat bash command * style: Swiftformat rules * style: Swiftformat applied to codebase * style: Ignore Tests for Swiftlint * Update bundler * Update changelog and migration guide * style: Ignore Example for Swiftlint * chore: Changelog * Update Xcode version for ci_pr_tests.yml * Update ci_pr_framework.yml * Update ci_pr_example.yml * chore: Changelog Co-authored-by: Jakub Kaspar <kaspikk@gmail.com>
164 lines
6.0 KiB
Swift
164 lines
6.0 KiB
Swift
// MIT License
|
|
//
|
|
// Copyright (c) 2017-2020 MessageKit
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
// copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
|
|
import InputBarAccessoryView
|
|
import MessageKit
|
|
import SwiftUI
|
|
|
|
// MARK: - MessageSwiftUIVC
|
|
|
|
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
|
|
becomeFirstResponder()
|
|
messagesCollectionView.scrollToLastItem(animated: true)
|
|
}
|
|
}
|
|
|
|
// MARK: - MessagesView
|
|
|
|
struct MessagesView: UIViewControllerRepresentable {
|
|
// MARK: Internal
|
|
|
|
final class Coordinator {
|
|
// MARK: Lifecycle
|
|
|
|
init(messages: Binding<[MessageType]>) {
|
|
self.messages = messages
|
|
}
|
|
|
|
// MARK: Internal
|
|
|
|
let formatter: DateFormatter = {
|
|
let formatter = DateFormatter()
|
|
formatter.dateStyle = .medium
|
|
return formatter
|
|
}()
|
|
|
|
var messages: Binding<[MessageType]>
|
|
}
|
|
|
|
@State var initialized = false
|
|
@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
|
|
messagesVC.messageInputBar.delegate = context.coordinator
|
|
messagesVC.scrollsToLastItemOnKeyboardBeginsEditing = true // default false
|
|
messagesVC.maintainPositionOnInputBarHeightChanged = true // default false
|
|
messagesVC.showMessageTimestampOnSwipeLeft = true // default false
|
|
|
|
return messagesVC
|
|
}
|
|
|
|
func updateUIViewController(_ uiViewController: MessagesViewController, context _: Context) {
|
|
uiViewController.messagesCollectionView.reloadData()
|
|
scrollToBottom(uiViewController)
|
|
}
|
|
|
|
func makeCoordinator() -> Coordinator {
|
|
Coordinator(messages: $messages)
|
|
}
|
|
|
|
// MARK: Private
|
|
|
|
private func scrollToBottom(_ uiViewController: MessagesViewController) {
|
|
DispatchQueue.main.async {
|
|
// The initialized state variable allows us to start at the bottom with the initial messages without seeing the initial scroll flash by
|
|
uiViewController.messagesCollectionView.scrollToLastItem(animated: self.initialized)
|
|
self.initialized = true
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - MessagesView.Coordinator + MessagesDataSource
|
|
|
|
extension MessagesView.Coordinator: MessagesDataSource {
|
|
var currentSender: SenderType {
|
|
SampleData.shared.currentSender
|
|
}
|
|
|
|
func messageForItem(at indexPath: IndexPath, in _: MessagesCollectionView) -> MessageType {
|
|
messages.wrappedValue[indexPath.section]
|
|
}
|
|
|
|
func numberOfSections(in _: MessagesCollectionView) -> Int {
|
|
messages.wrappedValue.count
|
|
}
|
|
|
|
func messageTopLabelAttributedText(for message: MessageType, at _: 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) -> NSAttributedString? {
|
|
let dateString = formatter.string(from: message.sentDate)
|
|
return NSAttributedString(
|
|
string: dateString,
|
|
attributes: [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .caption2)])
|
|
}
|
|
|
|
func messageTimestampLabelAttributedText(for message: MessageType, at _: IndexPath) -> NSAttributedString? {
|
|
let sentDate = message.sentDate
|
|
let sentDateString = MessageKitDateFormatter.shared.string(from: sentDate)
|
|
let timeLabelFont: UIFont = .boldSystemFont(ofSize: 10)
|
|
let timeLabelColor: UIColor = .systemGray
|
|
return NSAttributedString(
|
|
string: sentDateString,
|
|
attributes: [NSAttributedString.Key.font: timeLabelFont, NSAttributedString.Key.foregroundColor: timeLabelColor])
|
|
}
|
|
}
|
|
|
|
// MARK: - MessagesView.Coordinator + InputBarAccessoryViewDelegate
|
|
|
|
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 = ""
|
|
}
|
|
}
|
|
|
|
// MARK: - MessagesView.Coordinator + MessagesLayoutDelegate, MessagesDisplayDelegate
|
|
|
|
extension MessagesView.Coordinator: MessagesLayoutDelegate, MessagesDisplayDelegate {
|
|
func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at _: IndexPath, in _: MessagesCollectionView) {
|
|
let avatar = SampleData.shared.getAvatarFor(sender: message.sender)
|
|
avatarView.set(avatar: avatar)
|
|
}
|
|
|
|
func messageTopLabelHeight(for _: MessageType, at _: IndexPath, in _: MessagesCollectionView) -> CGFloat {
|
|
20
|
|
}
|
|
|
|
func messageBottomLabelHeight(for _: MessageType, at _: IndexPath, in _: MessagesCollectionView) -> CGFloat {
|
|
16
|
|
}
|
|
}
|