conversation view: add default emoji palette
Gitlab: #326
Change-Id: I08cdc114445f8ce2abbc5f16f942d9e9c986986f
diff --git a/Ring/Ring/Extensions/String+Helpers.swift b/Ring/Ring/Extensions/String+Helpers.swift
index e5058d9..b79bdf5 100644
--- a/Ring/Ring/Extensions/String+Helpers.swift
+++ b/Ring/Ring/Extensions/String+Helpers.swift
@@ -167,7 +167,7 @@
.replacingOccurrences(of: ")", with: "")
}
- func containsCaseInsentative(string: String) -> Bool {
+ func containsCaseInsensitive(string: String) -> Bool {
return self.range(of: string, options: .caseInsensitive) != nil
}
}
diff --git a/Ring/Ring/Features/Conversations/Conversation/ConversationViewController.swift b/Ring/Ring/Features/Conversations/Conversation/ConversationViewController.swift
index f5092e0..228e2fa 100644
--- a/Ring/Ring/Features/Conversations/Conversation/ConversationViewController.swift
+++ b/Ring/Ring/Features/Conversations/Conversation/ConversationViewController.swift
@@ -173,7 +173,7 @@
can receive taps. The tap gesture should be re-added
once the contact picker is dismissed.
*/
- self.view.removeGestureRecognizer(self.screenTapRecognizer)
+ self.view.removeGestureRecognizer(self.screenTapRecognizer)
self.viewModel.slectContactsToShareMessage(message: message)
case .share(let items):
self.presentActivityControllerWithItems(items: items)
diff --git a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/ContextMenuVM.swift b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/ContextMenuVM.swift
index a04255a..6ebfa09 100644
--- a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/ContextMenuVM.swift
+++ b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/ContextMenuVM.swift
@@ -20,8 +20,10 @@
import Foundation
import SwiftUI
+import RxRelay
class ContextMenuVM {
+ var sendEmojiUpdate = BehaviorRelay(value: [String: String]())
@Published var menuItems = [ContextualMenuItem]()
var presentingMessage: MessageBubbleView! {
didSet {
@@ -29,6 +31,7 @@
actionsAnchor = presentingMessage.model.message.incoming ? .topLeading : .topTrailing
messsageAnchor = presentingMessage.model.message.incoming ? .bottomLeading : .bottomTrailing
updateContextMenuSize()
+ isOurMsg = !presentingMessage.model.message.incoming
}
}
var messageFrame: CGRect = CGRect.zero {
@@ -49,17 +52,32 @@
let menuItemFont = Font.callout
let screenPadding: CGFloat = 100
let menuCornerRadius: CGFloat = 3
+ let defaultVerticalPadding: CGFloat = 6
+ let maxScaleFactor: CGFloat = 1.1
var bottomOffset: CGFloat = 0 // move message up
var menuOffsetX: CGFloat = 0
var menuOffsetY: CGFloat = 0
var scaleMessageUp = true
var actionsAnchor: UnitPoint = .center
var messsageAnchor: UnitPoint = .center
- var messageHeight: CGFloat = 0
+ var messageHeight: CGFloat = 0 {
+ didSet {
+ isShortMsg = messageHeight < screenHeight / 4.0
+ }
+ }
+ var emojiVerticalPadding: CGFloat = 6
+
+ var emojiBarHeight: CGFloat = 68
+ var isShortMsg: Bool = true
+ var incomingMessageMarginSize: CGFloat = 58
+ var isOurMsg: Bool?
+
var shadowColor: UIColor {
return UITraitCollection.current.userInterfaceStyle == .light ? UIColor.tertiaryLabel : UIColor.black.withAlphaComponent(0.8)
}
+ var currentJamiAccountId: String?
+
func updateContextMenuSize() {
let height: CGFloat = CGFloat(menuItems.count) * itemHeight + menuPadding * 2
let fontAttributes = [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .callout)]
@@ -93,5 +111,49 @@
}
let difff = messageFrame.height + navBarHeight + menuSize.height - screenHeight
scaleMessageUp = difff <= 0
+ if scaleMessageUp {
+ let heightDiff = messageHeight * maxScaleFactor - messageHeight
+ /*
+ Because the messageAnchor for the scale is at the bottom,
+ the message will expand upwards. Therefore, it is necessary
+ to add scaled space.
+ */
+ emojiVerticalPadding = defaultVerticalPadding + heightDiff
+ }
+ // set the left margin for incoming messages when reactions are opened
+ incomingMessageMarginSize = messageFrame.minX
+ }
+
+ func sendReaction(value: String) {
+ if let msg = self.presentingMessage {
+ self.sendEmojiUpdate.accept(["messageId": msg.messageModel.id, "author": msg.messageModel.message.authorId, "data": value, "action": ReactionCommand.apply.toString()])
+ }
+ }
+
+ func revokeReaction(value: String, reactionId: String) {
+ if let msg = self.presentingMessage {
+ self.sendEmojiUpdate.accept(["reactionId": reactionId, "author": msg.messageModel.message.authorId, "data": value, "action": ReactionCommand.revoke.toString()])
+ }
+ }
+
+ func localUserAuthoredReaction(emoji: String) -> Bool {
+ if let sender = self.currentJamiAccountId {
+ return self.presentingMessage.messageModel.message.reactions.first(where: { item in item.author == sender && item.content == emoji }) != nil
+ }
+ return false
+ }
+}
+
+enum ReactionCommand {
+ case apply
+ case revoke
+
+ func toString() -> String {
+ switch self {
+ case .apply:
+ return "apply"
+ case .revoke:
+ return "revoke"
+ }
}
}
diff --git a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageContainerModel.swift b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageContainerModel.swift
index dd5bd28..6823558 100644
--- a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageContainerModel.swift
+++ b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageContainerModel.swift
@@ -136,7 +136,7 @@
DispatchQueue.main.async { [weak self, weak image] in
guard let self = self, let image = image else { return }
if self.messageRow.shouldDisplayAavatar && self.message.incoming {
- self.messageRow.avatarImage = image
+ self.messageRow.updateImage(image: image, jamiId: jamiId)
}
if self.message.type == .contact && self.message.incoming {
self.contactViewModel.avatarImage = image
diff --git a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageContentVM.swift b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageContentVM.swift
index c1fdbd9..d0f76ac 100644
--- a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageContentVM.swift
+++ b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageContentVM.swift
@@ -443,9 +443,6 @@
}
func swarmColorUpdated(color: UIColor) {
- if self.message.incoming || self.content.containsOnlyEmoji {
- return
- }
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
self.preferencesColor = color
diff --git a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageRowVM.swift b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageRowVM.swift
index 84d5598..d4222dc 100644
--- a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageRowVM.swift
+++ b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageRowVM.swift
@@ -57,6 +57,13 @@
}
}
+ func updateImage(image: UIImage, jamiId: String) {
+ let localId = message.uri.isEmpty ? message.authorId : message.uri
+ if jamiId == localId {
+ self.avatarImage = image
+ }
+ }
+
var sequencing: MessageSequencing = .unknown {
didSet {
topSpace = (sequencing == .singleMessage || sequencing == .firstOfSequence) ? 2 : 0
diff --git a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessagesListVM.swift b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessagesListVM.swift
index 155a124..45c6df9 100644
--- a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessagesListVM.swift
+++ b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessagesListVM.swift
@@ -88,6 +88,7 @@
class MessagesListVM: ObservableObject {
// view properties
+ var contextMenuModel = ContextMenuVM()
@Published var messagesModels = [MessageContainerModel]()
@Published var scrollToId: String?
@Published var scrollToReplyTarget: String? // message id of a reply target that we should scroll
@@ -342,6 +343,25 @@
self.reactionsUpdated(messageId: messageId)
})
.disposed(by: self.disposeBag)
+ contextMenuModel.currentJamiAccountId = self.accountService.currentAccount?.jamiId
+ // setup subscription for emoji picker
+ self.contextMenuModel.sendEmojiUpdate
+ .subscribe(onNext: { [weak self] event in
+ if let self = self, !event.isEmpty {
+ switch event["action"] {
+ case ReactionCommand.apply.toString():
+ if let dat = event["data"], let mId = event["messageId"] {
+ self.conversationService.sendEmojiReactionMessage(conversationId: self.conversation.id, accountId: self.conversation.accountId, message: dat, parentId: mId)
+ }
+ case ReactionCommand.revoke.toString():
+ if let rId = event["reactionId"] {
+ self.conversationService.editSwarmMessage(conversationId: self.conversation.id, accountId: self.conversation.accountId, message: "", parentId: rId)
+ }
+ default: break
+ }
+ }
+ })
+ .disposed(by: self.disposeBag)
}
func subscribeMessageUpdates() {
diff --git a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/Views/ContextMenuView.swift b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/Views/ContextMenuView.swift
index e59a6b5..a10357a 100644
--- a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/Views/ContextMenuView.swift
+++ b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/Views/ContextMenuView.swift
@@ -56,48 +56,92 @@
@SwiftUI.State private var messageOffsetDiff: CGFloat = 0
@SwiftUI.State private var cornerRadius: CGFloat = 0
@SwiftUI.State private var scrollViewHeight: CGFloat = 0
+ @SwiftUI.GestureState private var isLongPressingEmojiBar = false
var body: some View {
ZStack {
GeometryReader { _ in
VStack(alignment: .leading) {
- // message
- ScrollView {
- model.presentingMessage
- .frame(
- width: model.messageFrame.width,
- height: model.messageFrame.height
- )
- }
- .cornerRadius(cornerRadius)
- .scaleEffect(messageScale, anchor: model.messsageAnchor)
- .shadow(color: Color(model.shadowColor), radius: messageShadow)
- .frame(
- width: model.messageFrame.width,
- height: scrollViewHeight
- )
Spacer()
- .frame(height: 10)
- // actions
- makeActions()
- .frame(width: model.menuSize.width)
- .opacity(actionsOpacity)
- .scaleEffect(actionsScale, anchor: model.actionsAnchor)
- .offset(
- x: model.menuOffsetX,
- y: model.menuOffsetY
- )
+ .frame(height: model.defaultVerticalPadding)
+ // emoji picker
+ if model.isShortMsg {
+ HStack {
+ if !model.isOurMsg! {
+ Spacer()
+ .frame(width: model.incomingMessageMarginSize)
+ }
+ makeEmojiBar()
+ if model.isOurMsg! {
+ Spacer()
+ .frame(width: 10)
+ }
+ }
+ .frame(width: screenWidth, alignment: model.isOurMsg! ? .trailing : .leading)
+ Spacer()
+ .frame(height: model.emojiVerticalPadding)
+ }
+ // message body in scrollable view
+ // message + tappable area
+ HStack {
+ if !model.isOurMsg! {
+ Spacer()
+ .frame(width: model.incomingMessageMarginSize)
+ }
+ tappableMessageBody()
+ if model.isOurMsg! {
+ Spacer()
+ .frame(width: 10)
+ }
+ }
+ .frame(width: screenWidth, alignment: model.isOurMsg! ? .trailing : .leading)
+ // extra check for long messages to move emojis closer to the touch center
+ if !model.isShortMsg {
+ HStack {
+ if !model.isOurMsg! {
+ Spacer()
+ .frame(width: model.incomingMessageMarginSize)
+ }
+ makeEmojiBar()
+ if model.isOurMsg! {
+ Spacer()
+ .frame(width: 10)
+ }
+ }
+ .frame(width: screenWidth, alignment: model.isOurMsg! ? .trailing : .leading)
+ } else {
+ Spacer()
+ .frame(height: model.defaultVerticalPadding)
+ }
+ // actions (reply, fwd, etc.)
+ HStack {
+ if !model.isOurMsg! {
+ Spacer()
+ .frame(width: model.incomingMessageMarginSize)
+ }
+ makeActions()
+ .opacity(actionsOpacity)
+ .scaleEffect(actionsScale, anchor: model.actionsAnchor)
+ .frame(width: model.menuSize.width)
+ if model.isOurMsg! {
+ Spacer()
+ .frame(width: 10)
+ }
+ }
+ .frame(width: screenWidth, alignment: model.isOurMsg! ? .trailing : .leading)
}
- .offset(
- x: model.messageFrame.origin.x,
- y: model.messageFrame.origin.y + messageOffsetDiff
- )
+ .padding(.trailing, 4)
}
- .background(makeBackground())
+ .offset( // offset vstack
+ x: 0,
+ y: max(0, model.messageFrame.origin.y + messageOffsetDiff - (model.isShortMsg ? model.emojiBarHeight : 0))
+ )
+
}
+ .background(makeBackground())
.onTapGesture {
presentingState = .willDismissWithoutAction
- withAnimation(Animation.easeOut(duration: 0.3)) {
+ withAnimation(Animation.easeOut(duration: 0.1)) {
scrollViewHeight = model.messageFrame.height
blurAmount = 0
backgroundScale = 1.00
@@ -109,17 +153,17 @@
messageOffsetDiff = 0
cornerRadius = 0
}
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.42) {
presentingState = .dismissed
}
}
.onAppear(perform: {
scrollViewHeight = model.messageFrame.height
- withAnimation(.easeOut(duration: 0.4)) {
- messageScale = model.scaleMessageUp ? 1.1 : 1.0
+ withAnimation(.easeOut(duration: 0.3)) {
+ messageScale = model.scaleMessageUp ? model.maxScaleFactor : 1.0
messageShadow = 4
}
- withAnimation(.easeIn(duration: 0.2).delay(0.3)) {
+ withAnimation(.easeIn(duration: 0.2).delay(0.15)) {
let impactMed = UIImpactFeedbackGenerator(style: .medium)
impactMed.impactOccurred()
blurAmount = 10
@@ -130,13 +174,61 @@
messageOffsetDiff = model.bottomOffset
cornerRadius = model.menuCornerRadius
}
- withAnimation(.spring(response: 0.2, dampingFraction: 0.6, blendDuration: 0.2).delay(0.3)) {
+ withAnimation(.spring(response: 0.2, dampingFraction: 0.6, blendDuration: 0.2).delay(0.15)) {
actionsScale = 1
}
})
.edgesIgnoringSafeArea(.all)
}
+ func tappableMessageBody() -> some View {
+ ZStack {
+ ScrollView {
+ model.presentingMessage
+ .frame(
+ width: model.messageFrame.width,
+ height: model.messageFrame.height
+ )
+
+ }
+ .cornerRadius(cornerRadius)
+ .scaleEffect(messageScale, anchor: model.messsageAnchor)
+ .shadow(color: Color(model.shadowColor), radius: messageShadow)
+ .frame(
+ width: model.messageFrame.width,
+ height: scrollViewHeight
+ )
+ // invisible tap area for accessibility
+ Rectangle()
+ .cornerRadius(cornerRadius)
+ .scaleEffect(messageScale, anchor: model.messsageAnchor)
+ .frame(
+ width: model.messageFrame.width,
+ height: scrollViewHeight
+ )
+ .onTapGesture {
+ presentingState = .willDismissWithoutAction
+ withAnimation(Animation.easeOut(duration: 0.1)) {
+ scrollViewHeight = model.messageFrame.height
+ blurAmount = 0
+ backgroundScale = 1.00
+ messageScale = 1
+ actionsScale = 0.00
+ actionsOpacity = 0
+ messageShadow = 0
+ backgroundOpacity = 0
+ messageOffsetDiff = 0
+ cornerRadius = 0
+ }
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
+ presentingState = .dismissed
+ }
+ }
+ .foregroundColor(Color.clear) // Make the Rectangle transparent
+ .contentShape(Rectangle())
+ }
+ }
+
func makeBackground() -> some View {
ZStack {
Color(UIColor.systemBackground)
@@ -151,6 +243,32 @@
.edgesIgnoringSafeArea(.all)
}
+ func makeEmojiBar() -> some View {
+ HStack {
+ let defaultReactionEmojis: [String] = [
+ 0x1F44D, 0x1F44E, 0x1F606, 0x1F923, 0x1F615
+ ].map { String(UnicodeScalar($0)!) }
+
+ ForEach(defaultReactionEmojis.indices, id: \.self) { index in
+ EmojiBarView(
+ model: model,
+ emoji: defaultReactionEmojis[index],
+ presentingState: $presentingState,
+ elementOpacity: 0.0 as CGFloat,
+ delayIn: 0.03 * Double(index),
+ elementRotation: Angle(degrees: 10.0 * Double(defaultReactionEmojis.count))
+ )
+ }
+
+ }
+ .opacity(actionsOpacity)
+ .padding(.vertical, 3)
+ .padding(.horizontal, 8)
+ .background(Color(UIColor.secondarySystemBackground))
+ .cornerRadius(radius: 32, corners: .allCorners)
+ .shadow(color: Color(model.shadowColor), radius: messageShadow)
+ }
+
func makeActions() -> some View {
VStack(spacing: 0) {
ForEach(model.menuItems) { item in
@@ -193,3 +311,69 @@
.cornerRadius(radius: model.menuCornerRadius, corners: .allCorners)
}
}
+
+struct EmojiBarView: View {
+ var model: ContextMenuVM
+ var emoji: String
+ @Binding var presentingState: ContextMenuPresentingState
+ @SwiftUI.State var elementOpacity: CGFloat
+ @SwiftUI.State var delayIn: Double
+ @SwiftUI.State var elementRotation: Angle
+ @SwiftUI.State private var enabledNotifierLength: CGFloat = 0
+ @SwiftUI.State private var hightligthColor: UIColor = UIColor.defaultSwarmColor
+
+ var body: some View {
+ let emojiActive = model.localUserAuthoredReaction(emoji: emoji)
+ VStack {
+ Text(verbatim: emoji)
+ .font(.title2)
+ .opacity(elementOpacity)
+ .rotationEffect(elementRotation)
+ .padding(8)
+ .overlay(
+ Rectangle()
+ .fill(Color(hightligthColor))
+ .opacity(emojiActive ? elementOpacity : 0)
+ .frame(width: enabledNotifierLength, height: 3, alignment: .center)
+ .cornerRadius(8)
+ .offset(y: 20)
+ .onAppear(perform: {
+ hightligthColor = model.presentingMessage.model.preferencesColor
+ withAnimation(.spring(response: 0.4, dampingFraction: 0.3, blendDuration: 0.9).delay(delayIn + 0.5)) {
+ enabledNotifierLength = 20
+ }
+ })
+ )
+ }
+ .simultaneousGesture(
+ // handles adding or removing the default reactions from a message
+ TapGesture().onEnded({ _ in
+ DispatchQueue.main.async {
+ switch emojiActive {
+ case false:
+ model.sendReaction(value: emoji)
+ case true:
+ let reactionMsgId: String =
+ model.presentingMessage.model.message.reactions.first(where: {
+ item in item.author == model.currentJamiAccountId && item.content == emoji
+ })!.id
+ model.revokeReaction(value: emoji, reactionId: reactionMsgId)
+ }
+ presentingState = .dismissed
+ }
+ }))
+ .padding(4)
+ .onAppear {
+ withAnimation(.spring(response: 0.2, dampingFraction: 0.6, blendDuration: 0.2).delay(delayIn)) {
+ elementOpacity = 1
+ }
+ withAnimation(.spring(response: 0.2, dampingFraction: 0.6, blendDuration: 0.3).delay(delayIn)) {
+ elementRotation = Angle(degrees: elementRotation.degrees / -2)
+ }
+ withAnimation(.spring(response: 0.2, dampingFraction: 0.3, blendDuration: 0.5).delay(delayIn + 0.3)) {
+ elementRotation = Angle(degrees: 0)
+ }
+ }
+ }
+
+}
diff --git a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/Views/MessagesListView.swift b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/Views/MessagesListView.swift
index baac773..4916154 100644
--- a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/Views/MessagesListView.swift
+++ b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/Views/MessagesListView.swift
@@ -57,7 +57,6 @@
@SwiftUI.State private var currentSnapshot: UIImage?
@SwiftUI.State private var presentingMessage: MessageBubbleView?
@SwiftUI.State private var messageFrame: CGRect?
- var contextMenuModel = ContextMenuVM()
@SwiftUI.State private var screenHeight: CGFloat = 0
@SwiftUI.State private var messageContainerHeight: CGFloat = 0
@SwiftUI.State private var shouldHideActiveKeyboard = false
@@ -89,7 +88,7 @@
return dimensions[VerticalAlignment.center]
}
}
- .overlay(contextMenuPresentingState == .shouldPresent && contextMenuModel.presentingMessage != nil ? makeOverlay() : nil)
+ .overlay(contextMenuPresentingState == .shouldPresent && model.contextMenuModel.presentingMessage != nil ? makeOverlay() : nil)
// hide navigation bar when presenting context menu
.onChange(of: contextMenuPresentingState) { newValue in
let shouldHide = newValue == .shouldPresent
@@ -147,7 +146,7 @@
}
func makeOverlay() -> some View {
- return ContextMenuView(model: contextMenuModel, presentingState: $contextMenuPresentingState)
+ return ContextMenuView(model: model.contextMenuModel, presentingState: $contextMenuPresentingState)
}
private func createMessagesStackView() -> some View {
@@ -213,8 +212,8 @@
return
}
model.hideNavigationBar.accept(true)
- contextMenuModel.presentingMessage = message
- contextMenuModel.messageFrame = frame
+ model.contextMenuModel.presentingMessage = message
+ model.contextMenuModel.messageFrame = frame
/*
If the keyboard is open, it should be closed.
Once the context menu is removed, the keyboard
diff --git a/Ring/Ring/Features/Conversations/views/JamiSearchView/JamiSearchViewModel.swift b/Ring/Ring/Features/Conversations/views/JamiSearchView/JamiSearchViewModel.swift
index 6954690..c68b83c 100644
--- a/Ring/Ring/Features/Conversations/views/JamiSearchView/JamiSearchViewModel.swift
+++ b/Ring/Ring/Features/Conversations/views/JamiSearchView/JamiSearchViewModel.swift
@@ -163,13 +163,13 @@
} else {
var displayNameContainsText = false
if let displayName = conversation.displayName.value {
- displayNameContainsText = displayName.containsCaseInsentative(string: searchQuery)
+ displayNameContainsText = displayName.containsCaseInsensitive(string: searchQuery)
}
var participantHashContainsText = false
if let hash = conversation.model().getParticipants().first?.jamiId {
- participantHashContainsText = hash.containsCaseInsentative(string: searchQuery)
+ participantHashContainsText = hash.containsCaseInsensitive(string: searchQuery)
}
- return conversation.userName.value.containsCaseInsentative(string: searchQuery) ||
+ return conversation.userName.value.containsCaseInsensitive(string: searchQuery) ||
displayNameContainsText || participantHashContainsText
}
}
diff --git a/Ring/Ring/Services/ConversationsService.swift b/Ring/Ring/Services/ConversationsService.swift
index 2bcec60..875ceba 100644
--- a/Ring/Ring/Services/ConversationsService.swift
+++ b/Ring/Ring/Services/ConversationsService.swift
@@ -277,14 +277,18 @@
self.conversationsAdapter.loadConversationMessages(accountId, conversationId: conversationId, from: id, size: 1)
}
- func sendSwarmMessage(conversationId: String, accountId: String, message: String, parentId: String) {
- self.conversationsAdapter.sendSwarmMessage(accountId, conversationId: conversationId, message: message, parentId: parentId, flag: 0)
- }
-
func editSwarmMessage(conversationId: String, accountId: String, message: String, parentId: String) {
self.conversationsAdapter.sendSwarmMessage(accountId, conversationId: conversationId, message: message, parentId: parentId, flag: 1)
}
+ func sendEmojiReactionMessage(conversationId: String, accountId: String, message: String, parentId: String) {
+ self.conversationsAdapter.sendSwarmMessage(accountId, conversationId: conversationId, message: message, parentId: parentId, flag: 2)
+ }
+
+ func sendSwarmMessage(conversationId: String, accountId: String, message: String, parentId: String) {
+ self.conversationsAdapter.sendSwarmMessage(accountId, conversationId: conversationId, message: message, parentId: parentId, flag: 0)
+ }
+
func insertReplies(messages: [MessageModel], accountId: String, conversationId: String, fromLoaded: Bool) -> Bool {
if self.isTargetReply(messages: messages) {
self.processReplyTargetMessage(with: messages.first)
diff --git a/Ring/Ring/SwarmInfo.swift b/Ring/Ring/SwarmInfo.swift
index fe0ba6d..fe42c07 100644
--- a/Ring/Ring/SwarmInfo.swift
+++ b/Ring/Ring/SwarmInfo.swift
@@ -228,10 +228,10 @@
}
func contains(searchQuery: String) -> Bool {
- if self.title.value.containsCaseInsentative(string: searchQuery) { return true }
+ if self.title.value.containsCaseInsensitive(string: searchQuery) { return true }
return !self.participants.value.filter { participant in
- participant.registeredName.value.containsCaseInsentative(string: searchQuery) ||
- participant.profileName.value.containsCaseInsentative(string: searchQuery) || participant.jamiId.containsCaseInsentative(string: searchQuery)
+ participant.registeredName.value.containsCaseInsensitive(string: searchQuery) ||
+ participant.profileName.value.containsCaseInsensitive(string: searchQuery) || participant.jamiId.containsCaseInsensitive(string: searchQuery)
}.isEmpty
}