mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
wip
This commit is contained in:
@@ -563,6 +563,10 @@ final class ChatModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func getGroupMember(_ groupMemberId: Int64) -> GroupMember? {
|
||||
groupMembers.first(where: { $0.groupMemberId == groupMemberId })
|
||||
}
|
||||
|
||||
func upsertGroupMember(_ groupInfo: GroupInfo, _ member: GroupMember) -> Bool {
|
||||
// user member was updated
|
||||
if groupInfo.membership.groupMemberId == member.groupMemberId {
|
||||
|
||||
@@ -318,33 +318,15 @@ func apiGetChatItemInfo(type: ChatType, id: Int64, itemId: Int64) async throws -
|
||||
func apiSendMessage(sendRef: SendRef, file: CryptoFile?, quotedItemId: Int64?, msg: MsgContent, live: Bool = false, ttl: Int? = nil) async -> ChatItem? {
|
||||
let chatModel = ChatModel.shared
|
||||
let cmd: ChatCommand = .apiSendMessage(sendRef: sendRef, file: file, quotedItemId: quotedItemId, msg: msg, live: live, ttl: ttl)
|
||||
let r: ChatResponse
|
||||
switch sendRef {
|
||||
// TODO group-direct: re-use direct logic for directMember
|
||||
case .direct:
|
||||
var cItem: ChatItem? = nil
|
||||
let endTask = beginBGTask({
|
||||
if let cItem = cItem {
|
||||
DispatchQueue.main.async {
|
||||
chatModel.messageDelivery.removeValue(forKey: cItem.id)
|
||||
}
|
||||
}
|
||||
})
|
||||
r = await chatSendCmd(cmd, bgTask: false)
|
||||
if case let .newChatItem(_, aChatItem) = r {
|
||||
cItem = aChatItem.chatItem
|
||||
chatModel.messageDelivery[aChatItem.chatItem.id] = endTask
|
||||
return cItem
|
||||
}
|
||||
if let networkErrorAlert = networkErrorAlert(r) {
|
||||
AlertManager.shared.showAlert(networkErrorAlert)
|
||||
} else {
|
||||
sendMessageErrorAlert(r)
|
||||
}
|
||||
endTask()
|
||||
return nil
|
||||
default:
|
||||
r = await chatSendCmd(cmd, bgDelay: msgDelay)
|
||||
let cItem = await sendMessageDirect(cmd)
|
||||
return cItem
|
||||
case .group(_, .some(_)):
|
||||
let cItem = await sendMessageDirect(cmd)
|
||||
return cItem
|
||||
case .group(_, .none):
|
||||
let r = await chatSendCmd(cmd, bgDelay: msgDelay)
|
||||
if case let .newChatItem(_, aChatItem) = r {
|
||||
return aChatItem.chatItem
|
||||
}
|
||||
@@ -353,6 +335,31 @@ func apiSendMessage(sendRef: SendRef, file: CryptoFile?, quotedItemId: Int64?, m
|
||||
}
|
||||
}
|
||||
|
||||
private func sendMessageDirect(_ cmd: ChatCommand) async -> ChatItem? {
|
||||
let chatModel = ChatModel.shared
|
||||
var cItem: ChatItem? = nil
|
||||
let endTask = beginBGTask({
|
||||
if let cItem = cItem {
|
||||
DispatchQueue.main.async {
|
||||
chatModel.messageDelivery.removeValue(forKey: cItem.id)
|
||||
}
|
||||
}
|
||||
})
|
||||
let r = await chatSendCmd(cmd, bgTask: false)
|
||||
if case let .newChatItem(_, aChatItem) = r {
|
||||
cItem = aChatItem.chatItem
|
||||
chatModel.messageDelivery[aChatItem.chatItem.id] = endTask
|
||||
return cItem
|
||||
}
|
||||
if let networkErrorAlert = networkErrorAlert(r) {
|
||||
AlertManager.shared.showAlert(networkErrorAlert)
|
||||
} else {
|
||||
sendMessageErrorAlert(r)
|
||||
}
|
||||
endTask()
|
||||
return nil
|
||||
}
|
||||
|
||||
private func sendMessageErrorAlert(_ r: ChatResponse) {
|
||||
logger.error("apiSendMessage error: \(String(describing: r))")
|
||||
AlertManager.shared.showAlertMsg(
|
||||
|
||||
@@ -290,7 +290,7 @@ struct ChatItemInfoView: View {
|
||||
|
||||
private func membersStatuses(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> [(GroupMember, CIStatus)] {
|
||||
memberDeliveryStatuses.compactMap({ mds in
|
||||
if let mem = ChatModel.shared.groupMembers.first(where: { $0.groupMemberId == mds.groupMemberId }) {
|
||||
if let mem = ChatModel.shared.getGroupMember(mds.groupMemberId) {
|
||||
return (mem, mds.memberDeliveryStatus)
|
||||
} else {
|
||||
return nil
|
||||
|
||||
@@ -207,6 +207,13 @@ struct ChatView: View {
|
||||
logger.error("apiContactInfo error: \(responseError(error))")
|
||||
}
|
||||
}
|
||||
} else if case let .group(groupInfo) = cInfo {
|
||||
Task {
|
||||
let groupMembers = await apiListMembers(groupInfo.groupId)
|
||||
await MainActor.run {
|
||||
ChatModel.shared.groupMembers = groupMembers
|
||||
}
|
||||
}
|
||||
}
|
||||
if chatModel.draftChatId == cInfo.id, let draft = chatModel.draft {
|
||||
composeState = draft
|
||||
@@ -428,22 +435,27 @@ struct ChatView: View {
|
||||
}
|
||||
|
||||
@ViewBuilder private func chatItemView(_ ci: ChatItem, _ maxWidth: CGFloat) -> some View {
|
||||
// TODO group-direct: display message as sent/received privately
|
||||
if case let .groupRcv(member, _) = ci.chatDir,
|
||||
if case let .groupRcv(member, msgScope) = ci.chatDir,
|
||||
case let .group(groupInfo) = chat.chatInfo {
|
||||
let (prevItem, nextItem) = chatModel.getChatItemNeighbors(ci)
|
||||
if ci.memberConnected != nil && nextItem?.memberConnected != nil {
|
||||
// memberConnected events are aggregated at the last chat item in a row of such events, see ChatItemView
|
||||
ZStack {} // scroll doesn't work if it's EmptyView()
|
||||
} else {
|
||||
if prevItem == nil || showMemberImage(member, prevItem) {
|
||||
if prevItem == nil || showMemberImage(member, msgScope, prevItem) {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
if ci.content.showMemberName {
|
||||
Text(member.displayName)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.leading, memberImageSize + 14)
|
||||
.padding(.top, 7)
|
||||
Group {
|
||||
if msgScope == .msPrivate {
|
||||
Text("\(member.displayName) **privately**")
|
||||
} else {
|
||||
Text(member.displayName)
|
||||
}
|
||||
}
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.leading, memberImageSize + 14)
|
||||
.padding(.top, 7)
|
||||
}
|
||||
HStack(alignment: .top, spacing: 8) {
|
||||
ProfileImage(imageStr: member.memberProfile.image)
|
||||
@@ -465,6 +477,38 @@ struct ChatView: View {
|
||||
.padding(.leading, memberImageSize + 8 + 12)
|
||||
}
|
||||
}
|
||||
} else if case let .groupSnd(directMember) = ci.chatDir,
|
||||
case let .group(groupInfo) = chat.chatInfo {
|
||||
let (prevItem, _) = chatModel.getChatItemNeighbors(ci)
|
||||
if prevItem == nil || showSndScope(directMember, prevItem) {
|
||||
VStack(alignment: .trailing, spacing: 4) {
|
||||
if ci.content.showMemberName {
|
||||
HStack {
|
||||
if let directMember = directMember {
|
||||
ProfileImage(imageStr: directMember.image)
|
||||
.frame(width: 30, height: 30)
|
||||
.onTapGesture { selectedMember = directMember }
|
||||
.appSheet(item: $selectedMember) { member in
|
||||
GroupMemberInfoView(groupInfo: groupInfo, member: directMember, navigation: true)
|
||||
}
|
||||
Text("**privately** to \(directMember.displayName)")
|
||||
} else {
|
||||
Text("to group")
|
||||
}
|
||||
}
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.top, 7)
|
||||
}
|
||||
chatItemWithMenu(ci, maxWidth)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.top, 5)
|
||||
} else {
|
||||
chatItemWithMenu(ci, maxWidth)
|
||||
.padding(.horizontal)
|
||||
.padding(.top, 5)
|
||||
}
|
||||
} else {
|
||||
chatItemWithMenu(ci, maxWidth)
|
||||
.padding(.horizontal)
|
||||
@@ -875,11 +919,24 @@ struct ChatView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO group-direct: show image if scope changes from group to private or vice versa
|
||||
private func showMemberImage(_ member: GroupMember, _ prevItem: ChatItem?) -> Bool {
|
||||
private func showMemberImage(_ member: GroupMember, _ msgScope: MessageScope, _ prevItem: ChatItem?) -> Bool {
|
||||
switch (prevItem?.chatDir) {
|
||||
case .groupSnd: return true
|
||||
case let .groupRcv(prevMember, _): return prevMember.groupMemberId != member.groupMemberId
|
||||
case let .groupRcv(prevMember, prevMsgScope): return prevMember.groupMemberId != member.groupMemberId || prevMsgScope != msgScope
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
||||
private func showSndScope(_ directMember: GroupMember?, _ prevItem: ChatItem?) -> Bool {
|
||||
switch (prevItem?.chatDir) {
|
||||
case .groupRcv: return true
|
||||
case let .groupSnd(prevDirectMember):
|
||||
switch (prevDirectMember, directMember) {
|
||||
case (.none, .some(_)): return true
|
||||
case (.some(_), .none): return true
|
||||
case let (.some(prevDM), .some(dm)): return prevDM.groupMemberId != dm.groupMemberId
|
||||
default: return false
|
||||
}
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,12 @@ import SimpleXChat
|
||||
import SwiftyGif
|
||||
import PhotosUI
|
||||
|
||||
enum ComposeDirectMember {
|
||||
case noDirectMember
|
||||
case directMember(groupMember: GroupMember)
|
||||
case directMemberCancelled
|
||||
}
|
||||
|
||||
enum ComposePreview {
|
||||
case noPreview
|
||||
case linkPreview(linkPreview: LinkPreview?)
|
||||
@@ -40,6 +46,7 @@ struct LiveMessage {
|
||||
struct ComposeState {
|
||||
var message: String
|
||||
var liveMessage: LiveMessage? = nil
|
||||
var directMember: ComposeDirectMember
|
||||
var preview: ComposePreview
|
||||
var contextItem: ComposeContextItem
|
||||
var voiceMessageRecordingState: VoiceMessageRecordingState
|
||||
@@ -49,12 +56,14 @@ struct ComposeState {
|
||||
init(
|
||||
message: String = "",
|
||||
liveMessage: LiveMessage? = nil,
|
||||
directMember: ComposeDirectMember = .noDirectMember,
|
||||
preview: ComposePreview = .noPreview,
|
||||
contextItem: ComposeContextItem = .noContextItem,
|
||||
voiceMessageRecordingState: VoiceMessageRecordingState = .noRecording
|
||||
) {
|
||||
self.message = message
|
||||
self.liveMessage = liveMessage
|
||||
self.directMember = directMember
|
||||
self.preview = preview
|
||||
self.contextItem = contextItem
|
||||
self.voiceMessageRecordingState = voiceMessageRecordingState
|
||||
@@ -62,6 +71,11 @@ struct ComposeState {
|
||||
|
||||
init(editingItem: ChatItem) {
|
||||
self.message = editingItem.content.text
|
||||
if let directMember = editingItem.directMember {
|
||||
self.directMember = .directMember(groupMember: directMember)
|
||||
} else {
|
||||
self.directMember = .noDirectMember
|
||||
}
|
||||
self.preview = chatItemPreview(chatItem: editingItem)
|
||||
self.contextItem = .editingItem(chatItem: editingItem)
|
||||
if let emc = editingItem.content.msgContent,
|
||||
@@ -75,6 +89,7 @@ struct ComposeState {
|
||||
func copy(
|
||||
message: String? = nil,
|
||||
liveMessage: LiveMessage? = nil,
|
||||
directMember: ComposeDirectMember? = nil,
|
||||
preview: ComposePreview? = nil,
|
||||
contextItem: ComposeContextItem? = nil,
|
||||
voiceMessageRecordingState: VoiceMessageRecordingState? = nil
|
||||
@@ -82,6 +97,7 @@ struct ComposeState {
|
||||
ComposeState(
|
||||
message: message ?? self.message,
|
||||
liveMessage: liveMessage ?? self.liveMessage,
|
||||
directMember: directMember ?? self.directMember,
|
||||
preview: preview ?? self.preview,
|
||||
contextItem: contextItem ?? self.contextItem,
|
||||
voiceMessageRecordingState: voiceMessageRecordingState ?? self.voiceMessageRecordingState
|
||||
@@ -582,6 +598,23 @@ struct ComposeView: View {
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder private func contextDirectMemberView() -> some View {
|
||||
switch composeState.directMember {
|
||||
case .noDirectMember:
|
||||
EmptyView()
|
||||
case let .directMember(groupMember):
|
||||
ContextDirectMemberView(
|
||||
directMember: groupMember,
|
||||
cancelDirectMemberContext: { composeState = composeState.copy(directMember: .directMemberCancelled) }
|
||||
)
|
||||
case .directMemberCancelled:
|
||||
ContextDirectMemberView(
|
||||
directMember: nil,
|
||||
cancelDirectMemberContext: { composeState = composeState.copy(directMember: .noDirectMember) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder private func contextItemView() -> some View {
|
||||
switch composeState.contextItem {
|
||||
case .noContextItem:
|
||||
@@ -747,12 +780,18 @@ struct ComposeView: View {
|
||||
}
|
||||
|
||||
func send(_ mc: MsgContent, quoted: Int64?, file: CryptoFile? = nil, live: Bool = false, ttl: Int?) async -> ChatItem? {
|
||||
// TODO group-direct: directMember in compose state
|
||||
var sendRef: SendRef?
|
||||
let chatId = chat.chatInfo.apiId
|
||||
switch chat.chatInfo.chatType {
|
||||
case .direct: sendRef = .direct(contactId: chatId)
|
||||
case .group: sendRef = .group(groupId: chatId, directMemberId: nil)
|
||||
case .direct:
|
||||
sendRef = .direct(contactId: chatId)
|
||||
case .group:
|
||||
switch composeState.directMember {
|
||||
case let .directMember(groupMember):
|
||||
sendRef = .group(groupId: chatId, directMemberId: groupMember.groupMemberId)
|
||||
default:
|
||||
sendRef = .group(groupId: chatId, directMemberId: nil)
|
||||
}
|
||||
default: sendRef = nil
|
||||
}
|
||||
if let sendRef = sendRef {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// ContextDirectMemberView.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by spaced4ndy on 11.09.2023.
|
||||
// Copyright © 2023 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
struct ContextDirectMemberView: View {
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
let directMember: GroupMember?
|
||||
let cancelDirectMemberContext: () -> Void
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
if let directMember = directMember {
|
||||
ProfileImage(imageStr: directMember.image)
|
||||
.frame(width: 30, height: 30)
|
||||
.padding(.trailing, 2)
|
||||
Text("Message will be sent privately to \(directMember.chatViewName)")
|
||||
.lineLimit(1)
|
||||
} else {
|
||||
Text("Message will be sent to all members")
|
||||
}
|
||||
Spacer()
|
||||
Button {
|
||||
withAnimation {
|
||||
cancelDirectMemberContext()
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "multiply")
|
||||
}
|
||||
}
|
||||
.padding(12)
|
||||
.frame(minHeight: 50)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(colorScheme == .light ? sentColorLight : sentColorDark)
|
||||
.padding(.top, 8)
|
||||
}
|
||||
}
|
||||
|
||||
struct ContextDirectMemberView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ContextDirectMemberView(directMember: GroupMember.sampleData, cancelDirectMemberContext: {})
|
||||
}
|
||||
}
|
||||
@@ -172,6 +172,7 @@
|
||||
648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; };
|
||||
649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; };
|
||||
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; };
|
||||
64A2723E2AAF16CD00BE1136 /* ContextDirectMemberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A2723D2AAF16CD00BE1136 /* ContextDirectMemberView.swift */; };
|
||||
64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; };
|
||||
64AA1C6C27F3537400AC7277 /* DeletedItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */; };
|
||||
64C06EB52A0A4A7C00792D4D /* ChatItemInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */; };
|
||||
@@ -449,6 +450,7 @@
|
||||
6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = "<group>"; };
|
||||
649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = "<group>"; };
|
||||
64A2723D2AAF16CD00BE1136 /* ContextDirectMemberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextDirectMemberView.swift; sourceTree = "<group>"; };
|
||||
64AA1C6827EE10C800AC7277 /* ContextItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextItemView.swift; sourceTree = "<group>"; };
|
||||
64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedItemView.swift; sourceTree = "<group>"; };
|
||||
64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemInfoView.swift; sourceTree = "<group>"; };
|
||||
@@ -837,6 +839,7 @@
|
||||
3CDBCF4127FAE51000354CDD /* ComposeLinkView.swift */,
|
||||
644EFFDD292BCD9D00525D5B /* ComposeVoiceView.swift */,
|
||||
D72A9087294BD7A70047C86D /* NativeTextEditor.swift */,
|
||||
64A2723D2AAF16CD00BE1136 /* ContextDirectMemberView.swift */,
|
||||
);
|
||||
path = ComposeMessage;
|
||||
sourceTree = "<group>";
|
||||
@@ -1119,6 +1122,7 @@
|
||||
64D0C2C629FAC1EC00B38D5F /* AddContactLearnMore.swift in Sources */,
|
||||
5C3A88D127DF57800060F1C2 /* FramedItemView.swift in Sources */,
|
||||
5C65F343297D45E100B67AF3 /* VersionView.swift in Sources */,
|
||||
64A2723E2AAF16CD00BE1136 /* ContextDirectMemberView.swift in Sources */,
|
||||
64F1CC3B28B39D8600CD1FB1 /* IncognitoHelp.swift in Sources */,
|
||||
5CB0BA90282713D900B3292C /* SimpleXInfo.swift in Sources */,
|
||||
5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */,
|
||||
|
||||
@@ -2133,10 +2133,17 @@ public struct ChatItem: Identifiable, Decodable {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO group-direct: prohibit moderation if directMember is present
|
||||
public var directMember: GroupMember? {
|
||||
switch chatDir {
|
||||
case let .groupSnd(directMember): return directMember
|
||||
case let .groupRcv(groupMember, .msPrivate): return groupMember
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
|
||||
public func memberToModerate(_ chatInfo: ChatInfo) -> (GroupInfo, GroupMember)? {
|
||||
switch (chatInfo, chatDir) {
|
||||
case let (.group(groupInfo), .groupRcv(groupMember, _)):
|
||||
case let (.group(groupInfo), .groupRcv(groupMember, .msGroup)):
|
||||
let m = groupInfo.membership
|
||||
return m.memberRole >= .admin && m.memberRole >= groupMember.memberRole && meta.itemDeleted == nil
|
||||
? (groupInfo, groupMember)
|
||||
@@ -2588,12 +2595,17 @@ public enum CIContent: Decodable, ItemContent {
|
||||
public var showMemberName: Bool {
|
||||
switch self {
|
||||
case .rcvMsgContent: return true
|
||||
case .sndMsgContent: return true
|
||||
case .rcvDeleted: return true
|
||||
case .sndDeleted: return true
|
||||
case .rcvCall: return true
|
||||
case .sndCall: return true
|
||||
case .rcvIntegrityError: return true
|
||||
case .rcvDecryptionError: return true
|
||||
case .rcvGroupInvitation: return true
|
||||
case .sndGroupInvitation: return true
|
||||
case .rcvModerated: return true
|
||||
case .sndModerated: return true
|
||||
case .invalidJSON: return true
|
||||
default: return false
|
||||
}
|
||||
@@ -2631,13 +2643,28 @@ public struct CIQuote: Decodable, ItemContent {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO group-direct: "<sender> privately" possibly here?
|
||||
public func getSender(_ membership: GroupMember?) -> String? {
|
||||
switch (chatDir) {
|
||||
case .directSnd: return "you"
|
||||
case .directRcv: return nil
|
||||
case .groupSnd: return membership?.displayName ?? "you"
|
||||
case let .groupRcv(member, _): return member.displayName
|
||||
switch chatDir {
|
||||
case .directSnd:
|
||||
return NSLocalizedString("you", comment: "quote sender")
|
||||
case .directRcv:
|
||||
return nil
|
||||
case .groupSnd(.msGroup):
|
||||
if let membershipName = membership?.displayName {
|
||||
return membershipName
|
||||
} else {
|
||||
return NSLocalizedString("you", comment: "quote sender")
|
||||
}
|
||||
case .groupSnd(.msPrivate):
|
||||
if let membershipName = membership?.displayName {
|
||||
return String.localizedStringWithFormat(NSLocalizedString("%@, privately", comment: "quote sender"), membershipName)
|
||||
} else {
|
||||
return NSLocalizedString("you, privately", comment: "quote sender")
|
||||
}
|
||||
case let .groupRcv(member, .msGroup):
|
||||
return member.displayName
|
||||
case let .groupRcv(member, .msPrivate):
|
||||
return String.localizedStringWithFormat(NSLocalizedString("%@, privately", comment: "quote sender"), member.displayName)
|
||||
case nil: return nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user