Skip to content

Commit

Permalink
Merge branch 'develop' into change/add-additional-space-when-mentioni…
Browse files Browse the repository at this point in the history
…ng-user
  • Loading branch information
nuno-vieira authored Dec 8, 2023
2 parents 65f436c + 1922666 commit 2e8a37c
Show file tree
Hide file tree
Showing 12 changed files with 162 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix date separator decoration view showing in the last message of the current page [#2899](https://github.com/GetStream/stream-chat-swift/pull/2899)
- Fix `JumpToUnreadMessagesButton` not localizable [#2917](https://github.com/GetStream/stream-chat-swift/pull/2917)
- Fix CocoaPods minimum iOS target not in sync with the Xcode project [#2924](https://github.com/GetStream/stream-chat-swift/pull/2924)
- Fix quoting message without bubble view when text is only emojis [#2925](https://github.com/GetStream/stream-chat-swift/pull/2925)
- Fix user mention not tappable when contains "@" character [#2928](https://github.com/GetStream/stream-chat-swift/pull/2928)
- Fix user mention not tappable if user does not have a name [#2928](https://github.com/GetStream/stream-chat-swift/pull/2928)
- Fix edit action possible in giphy messages [#2926](https://github.com/GetStream/stream-chat-swift/pull/2926)
- Fix not adding a space in the message input when mentioning a user [#2927](https://github.com/GetStream/stream-chat-swift/pull/2927)

# [4.44.0](https://github.com/GetStream/stream-chat-swift/releases/tag/4.44.0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@ open class ChatMessageLayoutOptionsResolver {
return [.text, .centered]
}

// Do not show bubble if the message is to be rendered as large emoji
if !message.shouldRenderAsJumbomoji {
// Do not show bubble if the message is to be rendered as large emoji.
// Unless we are quoting a message, in this case the bubble should still be rendered.
if !message.shouldRenderAsJumbomoji || message.quotedMessage != nil {
options.insert(.bubble)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ open class ChatMessageActionsVC: _ViewController, ThemeProvider {
actions.append(copyActionItem())
}

if canUpdateAnyMessage {
if canUpdateAnyMessage && message.giphyAttachments.isEmpty {
actions.append(editActionItem())
} else if canUpdateOwnMessage && message.isSentByCurrentUser {
} else if canUpdateOwnMessage && message.isSentByCurrentUser && message.giphyAttachments.isEmpty {
actions.append(editActionItem())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ class TextViewMentionedUsersHandler {
else {
return nil
}
let name = String(text[range].replacingOccurrences(of: "@", with: ""))
return mentionedUsers.first(where: { $0.name == name })

let mention = String(text[range])
return mentionedUsers.first(where: {
let name = $0.name ?? $0.id
return mention.contains(name)
})
}
}
4 changes: 4 additions & 0 deletions StreamChat.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,7 @@
ADA8EBE928CFD52F00DB9B03 /* TextViewUserMentionsHandler_Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADA8EBE828CFD52F00DB9B03 /* TextViewUserMentionsHandler_Mock.swift */; };
ADA8EBEB28CFD82C00DB9B03 /* ChatMessageContentViewDelegate_Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADA8EBEA28CFD82C00DB9B03 /* ChatMessageContentViewDelegate_Mock.swift */; };
ADAA377125E43C3700C31528 /* ChatSuggestionsVC_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADD5A9E725DE8AF6006DC88A /* ChatSuggestionsVC_Tests.swift */; };
ADAA9F412B2240300078C3D4 /* TextViewMentionedUsersHandler_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADAA9F402B2240300078C3D4 /* TextViewMentionedUsersHandler_Tests.swift */; };
ADAC47AA275A7C960027B672 /* ChatMessageContentView_Documentation_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADAC47A9275A7C960027B672 /* ChatMessageContentView_Documentation_Tests.swift */; };
ADB22F7C25F1626200853C92 /* OnlineIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADB22F7A25F1626200853C92 /* OnlineIndicatorView.swift */; };
ADB22F7D25F1626200853C92 /* ChatPresenceAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADB22F7B25F1626200853C92 /* ChatPresenceAvatarView.swift */; };
Expand Down Expand Up @@ -3823,6 +3824,7 @@
ADA5A0F7276790C100E1C465 /* ChatMessageListDateSeparatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatMessageListDateSeparatorView.swift; sourceTree = "<group>"; };
ADA8EBE828CFD52F00DB9B03 /* TextViewUserMentionsHandler_Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewUserMentionsHandler_Mock.swift; sourceTree = "<group>"; };
ADA8EBEA28CFD82C00DB9B03 /* ChatMessageContentViewDelegate_Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatMessageContentViewDelegate_Mock.swift; sourceTree = "<group>"; };
ADAA9F402B2240300078C3D4 /* TextViewMentionedUsersHandler_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewMentionedUsersHandler_Tests.swift; sourceTree = "<group>"; };
ADAC47A9275A7C960027B672 /* ChatMessageContentView_Documentation_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatMessageContentView_Documentation_Tests.swift; sourceTree = "<group>"; };
ADB22F7A25F1626200853C92 /* OnlineIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnlineIndicatorView.swift; sourceTree = "<group>"; };
ADB22F7B25F1626200853C92 /* ChatPresenceAvatarView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatPresenceAvatarView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -7193,6 +7195,7 @@
A3960E0427DA5512003AB2B0 /* Utils */ = {
isa = PBXGroup;
children = (
ADAA9F402B2240300078C3D4 /* TextViewMentionedUsersHandler_Tests.swift */,
AD4C15552A55874700A32955 /* ImageLoading_Tests.swift */,
BDDD1EAB2632E32000BA007B /* AppearanceProvider_Tests.swift */,
C1320E07276B2E0800A06B35 /* Array+SafeSubscript_Tests.swift */,
Expand Down Expand Up @@ -10041,6 +10044,7 @@
401105462A12735900F877C7 /* WaveformView_Tests.swift in Sources */,
ADEE651E29BF715600186129 /* ChatMessageListVCDelegate_Mock.swift in Sources */,
AD050BA8265D600B006649A5 /* QuotedChatMessageView+SwiftUI_Tests.swift in Sources */,
ADAA9F412B2240300078C3D4 /* TextViewMentionedUsersHandler_Tests.swift in Sources */,
40824D2F2A1271D7003B61FD /* RecordButton_Tests.swift in Sources */,
A3D9D69627EDE87900725066 /* Components_Mock.swift in Sources */,
AD25070D272C0C8D00BC14C4 /* ChatMessageReactionAuthorsVC_Tests.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,31 @@ final class ChatChannelVC_Tests: XCTestCase {
)
}

func test_onlyEmojiMessageAppearance_whenQuotingMessage() {
let quotedMessage = ChatMessage.mock(text: "Hello")
channelControllerMock.simulateInitial(
channel: .mock(cid: .unique),
messages: [
.mock(id: .unique, cid: .unique, text: "👍🏻💯", author: .mock(id: .unique), quotedMessage: quotedMessage),
.mock(id: .unique, cid: .unique, text: "Simple text", author: .mock(id: .unique), isSentByCurrentUser: true),
.mock(
id: .unique,
cid: .unique,
text: "🚀",
author: .mock(id: .unique),
quotedMessage: quotedMessage,
isSentByCurrentUser: true
),
quotedMessage
],
state: .localDataFetched
)
AssertSnapshot(
vc,
isEmbeddedInNavigationController: true
)
}

func test_whenShouldMessagesStartAtTheTopIsTrue() {
var components = Components.mock
components.shouldMessagesStartAtTheTop = true
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,18 @@ final class ChatMessageActionsVC_Tests: XCTestCase {
XCTAssertFalse(vc.messageActions.contains(where: { $0 is EditActionItem }))
}

func test_messageActions_whenUpdateOwnMessage_whenGiphy_thenDoesNotContainEditAction() {
chatMessageController.simulateInitial(
message: ChatMessage.mock(attachments: [makeGiphyAttachmentPayload()], isSentByCurrentUser: true),
replies: [],
state: .remoteDataFetched
)

vc.channel = .mock(cid: .unique, ownCapabilities: [.updateOwnMessage])

XCTAssertFalse(vc.messageActions.contains(where: { $0 is EditActionItem }))
}

func test_messageActions_whenUpdateAnyMessage_messageIsSentByCurrentUser_thenContainsEditAction() {
chatMessageController.simulateInitial(
message: ChatMessage.mock(isSentByCurrentUser: true),
Expand All @@ -219,6 +231,18 @@ final class ChatMessageActionsVC_Tests: XCTestCase {
XCTAssertTrue(vc.messageActions.contains(where: { $0 is EditActionItem }))
}

func test_messageActions_whenUpdateAnyMessage_whenGiphy_thenDoesNotContainEditAction() {
chatMessageController.simulateInitial(
message: ChatMessage.mock(attachments: [makeGiphyAttachmentPayload()], isSentByCurrentUser: true),
replies: [],
state: .remoteDataFetched
)

vc.channel = .mock(cid: .unique, ownCapabilities: [.updateAnyMessage])

XCTAssertFalse(vc.messageActions.contains(where: { $0 is EditActionItem }))
}

func test_messageActions_whenUpdateAnyMessage_messageIsSentByAnotherUser_thenContainsEditAction() {
chatMessageController.simulateInitial(
message: ChatMessage.mock(isSentByCurrentUser: false),
Expand Down Expand Up @@ -385,6 +409,20 @@ final class ChatMessageActionsVC_Tests: XCTestCase {
}
}

// MARK: - Helpers

private extension ChatMessageActionsVC_Tests {
func makeGiphyAttachmentPayload() -> AnyChatMessageAttachment {
.dummy(
type: .giphy,
payload: try! JSONEncoder.stream.encode(GiphyAttachmentPayload(
title: nil,
previewURL: URL.localYodaImage
))
)
}
}

private extension UIViewController {
/// `ChatMessageActionsVC` is not used as a root view controller, so we embed it to snapshot its more realistic size.
func embedded() -> UIViewController {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//
// Copyright © 2023 Stream.io Inc. All rights reserved.
//

@testable import StreamChat
@testable import StreamChatUI
import XCTest

final class TextViewMentionedUsersHandler_Tests: XCTestCase {
func test_mentionedUserTapped_whenRangeIncludesMention() {
let textView = UITextView()
textView.text = "@Leia Hello!"

let sut = TextViewMentionedUsersHandler()
let user = sut.mentionedUserTapped(
on: textView,
in: .init(location: 0, length: 5),
with: [.mock(id: "leia", name: "Leia")]
)

XCTAssertEqual(user?.name, "Leia")
}

func test_mentionedUserTapped_whenRangeDoesNotIncludeMention() {
let textView = UITextView()
textView.text = "@Leia Hello!"

let sut = TextViewMentionedUsersHandler()
let user = sut.mentionedUserTapped(
on: textView,
in: .init(location: 3, length: 7),
with: [.mock(id: "leia", name: "Leia")]
)

XCTAssertEqual(user?.name, nil)
}

func test_mentionedUserTapped_whenIncludesSpecialCharacter() {
let textView = UITextView()
textView.text = "@Lei@ Hello!"

let sut = TextViewMentionedUsersHandler()
let user = sut.mentionedUserTapped(
on: textView,
in: .init(location: 0, length: 5),
with: [.mock(id: "leia", name: "Lei@")]
)

XCTAssertEqual(user?.name, "Lei@")
}

// Customers can customise how mentions are presented, and so they can chose not to show it.
func test_mentionedUserTapped_whenAtSignIsNotPresent() {
let textView = UITextView()
textView.text = "Lei@ Hello!"

let sut = TextViewMentionedUsersHandler()
let user = sut.mentionedUserTapped(
on: textView,
in: .init(location: 0, length: 5),
with: [.mock(id: "leia", name: "Lei@")]
)

XCTAssertEqual(user?.name, "Lei@")
}

func test_mentionedUserTapped_whenUserDoesNotHaveName() {
let textView = UITextView()
textView.text = "leia Hello!"

let sut = TextViewMentionedUsersHandler()
let user = sut.mentionedUserTapped(
on: textView,
in: .init(location: 0, length: 5),
with: [.mock(id: "leia", name: nil)]
)

XCTAssertEqual(user?.id, "leia")
}
}

0 comments on commit 2e8a37c

Please sign in to comment.