diff --git a/Example/ChatExample.xcodeproj/project.pbxproj b/Example/ChatExample.xcodeproj/project.pbxproj index 1f646ec98..d1afcf27f 100644 --- a/Example/ChatExample.xcodeproj/project.pbxproj +++ b/Example/ChatExample.xcodeproj/project.pbxproj @@ -49,6 +49,7 @@ 9B49D53A263D9606008804B5 /* CustomLayoutSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B49D539263D9606008804B5 /* CustomLayoutSizeCalculator.swift */; }; 9B49D542263DA6F9008804B5 /* CustomMessageContentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B49D541263DA6F9008804B5 /* CustomMessageContentCell.swift */; }; 9B49D547263DAA29008804B5 /* CustomTextMessageContentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B49D546263DAA29008804B5 /* CustomTextMessageContentCell.swift */; }; + ABCBBB1428F57513008955E4 /* InputBarAccessoryView in Frameworks */ = {isa = PBXBuildFile; productRef = ABCBBB1328F57513008955E4 /* InputBarAccessoryView */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -124,6 +125,7 @@ buildActionMask = 2147483647; files = ( 13EFA5D927AC5634003002CC /* Kingfisher in Frameworks */, + ABCBBB1428F57513008955E4 /* InputBarAccessoryView in Frameworks */, 1C5433DF24C38DBF00A5383B /* SwiftUI.framework in Frameworks */, 13EFA5D727AC5631003002CC /* MessageKit in Frameworks */, ); @@ -349,6 +351,7 @@ packageProductDependencies = ( 13EFA5D627AC5631003002CC /* MessageKit */, 13EFA5D827AC5634003002CC /* Kingfisher */, + ABCBBB1328F57513008955E4 /* InputBarAccessoryView */, ); productName = ChatExample; productReference = 882B5E331CF7D4B900B6E160 /* ChatExample.app */; @@ -426,6 +429,7 @@ mainGroup = 882B5E2A1CF7D4B900B6E160; packageReferences = ( 13CCA06125793E24005C19BB /* XCRemoteSwiftPackageReference "Kingfisher" */, + ABCBBB1228F57513008955E4 /* XCRemoteSwiftPackageReference "InputBarAccessoryView" */, ); productRefGroup = 882B5E341CF7D4B900B6E160 /* Products */; projectDirPath = ""; @@ -820,6 +824,14 @@ minimumVersion = 5.15.8; }; }; + ABCBBB1228F57513008955E4 /* XCRemoteSwiftPackageReference "InputBarAccessoryView" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/deemaze/InputBarAccessoryView.git"; + requirement = { + branch = "custom-attachment-cell"; + kind = branch; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -841,6 +853,11 @@ package = 13CCA06125793E24005C19BB /* XCRemoteSwiftPackageReference "Kingfisher" */; productName = Kingfisher; }; + ABCBBB1328F57513008955E4 /* InputBarAccessoryView */ = { + isa = XCSwiftPackageProductDependency; + package = ABCBBB1228F57513008955E4 /* XCRemoteSwiftPackageReference "InputBarAccessoryView" */; + productName = InputBarAccessoryView; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 882B5E2B1CF7D4B900B6E160 /* Project object */; diff --git a/Example/ChatExample.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Example/ChatExample.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..f9b0d7c5e --- /dev/null +++ b/Example/ChatExample.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/Package.swift b/Package.swift index 0ed44c8fb..dda32cd55 100644 --- a/Package.swift +++ b/Package.swift @@ -31,7 +31,7 @@ let package = Package( .plugin(name: "SwiftFormatPlugin", targets: ["SwiftFormatPlugin"]), ], dependencies: [ - .package(url: "https://github.com/nathantannar4/InputBarAccessoryView", .upToNextMajor(from: "6.1.0")), + .package(url: "https://github.com/deemaze/InputBarAccessoryView", branch: "custom-attachment-cell") ], targets: [ // MARK: - MessageKit diff --git a/Sources/Layout/MessageSizeCalculator.swift b/Sources/Layout/MessageSizeCalculator.swift index 1d9065c9e..da74bfa1d 100644 --- a/Sources/Layout/MessageSizeCalculator.swift +++ b/Sources/Layout/MessageSizeCalculator.swift @@ -123,13 +123,27 @@ open class MessageSizeCalculator: CellSizeCalculator { open func avatarPosition(for message: MessageType) -> AvatarPosition { let dataSource = messagesLayout.messagesDataSource let isFromCurrentSender = dataSource.isFromCurrentSender(message: message) - var position = isFromCurrentSender ? outgoingAvatarPosition : incomingAvatarPosition + + // Check if RTL mode is active + let isRTL = messagesLayout.messagesCollectionView.rtlLanguageProvider?.isRTLLanguage ?? false + + // In RTL, swap incoming/outgoing positions + var position: AvatarPosition + if isRTL { + position = isFromCurrentSender ? incomingAvatarPosition : outgoingAvatarPosition + } else { + position = isFromCurrentSender ? outgoingAvatarPosition : incomingAvatarPosition + } switch position.horizontal { case .cellTrailing, .cellLeading: break case .natural: - position.horizontal = isFromCurrentSender ? .cellTrailing : .cellLeading + if isRTL { + position.horizontal = isFromCurrentSender ? .cellLeading : .cellTrailing + } else { + position.horizontal = isFromCurrentSender ? .cellTrailing : .cellLeading + } } return position } @@ -157,7 +171,16 @@ open class MessageSizeCalculator: CellSizeCalculator { open func cellTopLabelAlignment(for message: MessageType) -> LabelAlignment { let dataSource = messagesLayout.messagesDataSource let isFromCurrentSender = dataSource.isFromCurrentSender(message: message) - return isFromCurrentSender ? outgoingCellTopLabelAlignment : incomingCellTopLabelAlignment + + // Check if RTL mode is active + let isRTL = messagesLayout.messagesCollectionView.rtlLanguageProvider?.isRTLLanguage ?? false + + // In RTL, swap incoming/outgoing alignments + if isRTL { + return isFromCurrentSender ? incomingCellTopLabelAlignment : outgoingCellTopLabelAlignment + } else { + return isFromCurrentSender ? outgoingCellTopLabelAlignment : incomingCellTopLabelAlignment + } } // MARK: - Top message Label @@ -179,7 +202,16 @@ open class MessageSizeCalculator: CellSizeCalculator { let dataSource = messagesLayout.messagesDataSource let isFromCurrentSender = dataSource.isFromCurrentSender(message: message) - return isFromCurrentSender ? outgoingMessageTopLabelAlignment : incomingMessageTopLabelAlignment + + // Check if RTL mode is active + let isRTL = collectionView.rtlLanguageProvider?.isRTLLanguage ?? false + + // In RTL, swap incoming/outgoing alignments + if isRTL { + return isFromCurrentSender ? incomingMessageTopLabelAlignment : outgoingMessageTopLabelAlignment + } else { + return isFromCurrentSender ? outgoingMessageTopLabelAlignment : incomingMessageTopLabelAlignment + } } // MARK: - Message time label @@ -205,7 +237,16 @@ open class MessageSizeCalculator: CellSizeCalculator { open func cellBottomLabelAlignment(for message: MessageType) -> LabelAlignment { let dataSource = messagesLayout.messagesDataSource let isFromCurrentSender = dataSource.isFromCurrentSender(message: message) - return isFromCurrentSender ? outgoingCellBottomLabelAlignment : incomingCellBottomLabelAlignment + + // Check if RTL mode is active + let isRTL = messagesLayout.messagesCollectionView.rtlLanguageProvider?.isRTLLanguage ?? false + + // In RTL, swap incoming/outgoing alignments + if isRTL { + return isFromCurrentSender ? incomingCellBottomLabelAlignment : outgoingCellBottomLabelAlignment + } else { + return isFromCurrentSender ? outgoingCellBottomLabelAlignment : incomingCellBottomLabelAlignment + } } // MARK: - Bottom Message Label @@ -227,7 +268,16 @@ open class MessageSizeCalculator: CellSizeCalculator { let dataSource = messagesLayout.messagesDataSource let isFromCurrentSender = dataSource.isFromCurrentSender(message: message) - return isFromCurrentSender ? outgoingMessageBottomLabelAlignment : incomingMessageBottomLabelAlignment + + // Check if RTL mode is active + let isRTL = collectionView.rtlLanguageProvider?.isRTLLanguage ?? false + + // In RTL, swap incoming/outgoing alignments + if isRTL { + return isFromCurrentSender ? incomingMessageBottomLabelAlignment : outgoingMessageBottomLabelAlignment + } else { + return isFromCurrentSender ? outgoingMessageBottomLabelAlignment : incomingMessageBottomLabelAlignment + } } // MARK: - MessageContainer @@ -235,7 +285,16 @@ open class MessageSizeCalculator: CellSizeCalculator { open func messageContainerPadding(for message: MessageType) -> UIEdgeInsets { let dataSource = messagesLayout.messagesDataSource let isFromCurrentSender = dataSource.isFromCurrentSender(message: message) - return isFromCurrentSender ? outgoingMessagePadding : incomingMessagePadding + + // Check if RTL mode is active + let isRTL = messagesLayout.messagesCollectionView.rtlLanguageProvider?.isRTLLanguage ?? false + + // In RTL, swap incoming/outgoing paddings + if isRTL { + return isFromCurrentSender ? incomingMessagePadding : outgoingMessagePadding + } else { + return isFromCurrentSender ? outgoingMessagePadding : incomingMessagePadding + } } open func messageContainerSize(for _: MessageType, at _: IndexPath) -> CGSize { diff --git a/Sources/Views/Cells/MessageContentCell.swift b/Sources/Views/Cells/MessageContentCell.swift index 034180d5a..1a1c43d89 100644 --- a/Sources/Views/Cells/MessageContentCell.swift +++ b/Sources/Views/Cells/MessageContentCell.swift @@ -56,6 +56,7 @@ open class MessageContentCell: MessageCollectionViewCell { open var cellTopLabel: InsetLabel = { let label = InsetLabel() label.numberOfLines = 0 + label.adjustsFontForContentSizeCategory = true label.textAlignment = .center return label }() @@ -64,6 +65,7 @@ open class MessageContentCell: MessageCollectionViewCell { open var cellBottomLabel: InsetLabel = { let label = InsetLabel() label.numberOfLines = 0 + label.adjustsFontForContentSizeCategory = true label.textAlignment = .center return label }() @@ -72,6 +74,7 @@ open class MessageContentCell: MessageCollectionViewCell { open var messageTopLabel: InsetLabel = { let label = InsetLabel() label.numberOfLines = 0 + label.adjustsFontForContentSizeCategory = true return label }() @@ -79,6 +82,7 @@ open class MessageContentCell: MessageCollectionViewCell { open var messageBottomLabel: InsetLabel = { let label = InsetLabel() label.numberOfLines = 0 + label.adjustsFontForContentSizeCategory = true return label }() diff --git a/Sources/Views/MessagesCollectionView.swift b/Sources/Views/MessagesCollectionView.swift index a551ef2f9..afe2d1e2c 100644 --- a/Sources/Views/MessagesCollectionView.swift +++ b/Sources/Views/MessagesCollectionView.swift @@ -23,6 +23,12 @@ import Foundation import UIKit +/// Protocol to provide RTL (Right-to-Left) language support for MessageKit +public protocol RTLLanguageProvider: AnyObject { + /// Returns `true` if the current language is RTL (Right-to-Left) + var isRTLLanguage: Bool { get } +} + open class MessagesCollectionView: UICollectionView { // MARK: Lifecycle @@ -55,6 +61,8 @@ open class MessagesCollectionView: UICollectionView { open weak var messageCellDelegate: MessageCellDelegate? + open weak var rtlLanguageProvider: RTLLanguageProvider? + open var isTypingIndicatorHidden: Bool { messagesCollectionViewFlowLayout.isTypingIndicatorViewHidden }