This commit is contained in:
spaced4ndy
2023-09-11 21:04:00 +04:00
parent 8efa023327
commit 3cdba73109
5 changed files with 100 additions and 12 deletions
+51 -3
View File
@@ -486,7 +486,7 @@ struct ChatView: View {
HStack {
if let directMember = directMember {
ProfileImage(imageStr: directMember.image)
.frame(width: 30, height: 30)
.frame(width: 20, height: 20)
.onTapGesture { selectedMember = directMember }
.appSheet(item: $selectedMember) { member in
GroupMemberInfoView(groupInfo: groupInfo, member: directMember, navigation: true)
@@ -550,6 +550,8 @@ struct ChatView: View {
@State private var playbackState: VoiceMessagePlaybackState = .noPlayback
@State private var playbackTime: TimeInterval?
@State private var allowMemberMenu: Bool = true
var body: some View {
let alignment: Alignment = ci.chatDir.sent ? .trailing : .leading
let uiMenu: Binding<UIMenu> = Binding(
@@ -642,7 +644,15 @@ struct ChatView: View {
menu.append(rm)
}
if ci.meta.itemDeleted == nil && !ci.isLiveDummy && !live {
menu.append(replyUIAction())
if ci.directMember == nil {
menu.append(replyUIAction())
}
if case let .group(groupInfo) = chat.chatInfo,
let toDirectMember = ci.memberToReplyDirectlyTo,
let toDirectMemberWithConn = ChatModel.shared.getGroupMember(toDirectMember.groupMemberId),
toDirectMemberWithConn.allowedToSendDirectlyTo(groupInfo: groupInfo) {
menu.append(replyDirectlyUIAction(toDirectMemberWithConn, groupInfo))
}
}
menu.append(shareUIAction())
menu.append(copyUIAction())
@@ -697,7 +707,45 @@ struct ChatView: View {
if composeState.editing {
composeState = ComposeState(contextItem: .quotedItem(chatItem: ci))
} else {
composeState = composeState.copy(contextItem: .quotedItem(chatItem: ci))
composeState = composeState.copy(
directMember: .noDirectMember,
contextItem: .quotedItem(chatItem: ci)
)
}
}
}
}
private func replyDirectlyUIAction(_ toDirectMember: GroupMember, _ groupInfo: GroupInfo) -> UIAction {
UIAction(
title: NSLocalizedString("Reply directly", comment: "chat item action"),
image: UIImage(systemName: "arrowshape.turn.up.left")
) { _ in
let canSend = toDirectMember.canSendDirectlyTo(groupInfo: groupInfo)
switch canSend {
case .notConnected:
AlertManager.shared.showAlert(Alert(
title: Text("Can't send directly!"),
message: Text("Member is not connected.")
))
case .notSupported:
AlertManager.shared.showAlert(Alert(
title: Text("Can't send directly!"),
message: Text("Member doesn't support this feature, ask them to update.")
))
case .canSend:
withAnimation {
if composeState.editing {
composeState = ComposeState(
directMember: .directMember(groupMember: toDirectMember),
contextItem: .quotedItem(chatItem: ci)
)
} else {
composeState = composeState.copy(
directMember: .directMember(groupMember: toDirectMember),
contextItem: .quotedItem(chatItem: ci)
)
}
}
}
}
@@ -273,6 +273,7 @@ struct ComposeView: View {
var body: some View {
VStack(spacing: 0) {
contextDirectMemberView()
contextItemView()
switch (composeState.editing, composeState.preview) {
case (true, .filePreview): EmptyView()
@@ -605,7 +606,10 @@ struct ComposeView: View {
case let .directMember(groupMember):
ContextDirectMemberView(
directMember: groupMember,
cancelDirectMemberContext: { composeState = composeState.copy(directMember: .directMemberCancelled) }
cancelDirectMemberContext: { composeState = composeState.copy(
directMember: .directMemberCancelled,
contextItem: .noContextItem
)}
)
case .directMemberCancelled:
ContextDirectMemberView(
@@ -17,9 +17,11 @@ struct ContextDirectMemberView: View {
var body: some View {
HStack {
if let directMember = directMember {
ProfileImage(imageStr: directMember.image)
.frame(width: 30, height: 30)
.padding(.trailing, 2)
if let image = directMember.image {
ProfileImage(imageStr: directMember.image)
.frame(width: 30, height: 30)
.padding(.trailing, 2)
}
Text("Directly to \(directMember.chatViewName)")
.lineLimit(1)
} else {
+38 -4
View File
@@ -1807,6 +1807,30 @@ public struct GroupMember: Identifiable, Decodable {
return GroupMemberRole.allCases.filter { $0 <= userRole }
}
public func allowedToSendDirectlyTo(groupInfo: GroupInfo) -> Bool {
let userRole = groupInfo.membership.memberRole
return (
(groupInfo.fullGroupPreferences.directMessages.on && userRole >= .author)
|| userRole >= .admin
|| memberRole >= .admin
)
}
public enum CanSendDirectlyTo {
case canSend
case notConnected
case notSupported
}
public func canSendDirectlyTo(groupInfo: GroupInfo) -> CanSendDirectlyTo {
// TODO group-direct: check version
if let activeConn = activeConn {
return .canSend
} else {
return .notConnected
}
}
public var memberIncognito: Bool {
memberProfile.profileId != memberContactProfileId
}
@@ -1834,6 +1858,7 @@ public struct GroupMemberRef: Decodable {
public enum GroupMemberRole: String, Identifiable, CaseIterable, Comparable, Decodable {
case observer = "observer"
case author = "author"
case member = "member"
case admin = "admin"
case owner = "owner"
@@ -1843,6 +1868,7 @@ public enum GroupMemberRole: String, Identifiable, CaseIterable, Comparable, Dec
public var text: String {
switch self {
case .observer: return NSLocalizedString("observer", comment: "member role")
case .author: return NSLocalizedString("author", comment: "member role")
case .member: return NSLocalizedString("member", comment: "member role")
case .admin: return NSLocalizedString("admin", comment: "member role")
case .owner: return NSLocalizedString("owner", comment: "member role")
@@ -1852,9 +1878,10 @@ public enum GroupMemberRole: String, Identifiable, CaseIterable, Comparable, Dec
private var comparisonValue: Int {
switch self {
case .observer: return 0
case .member: return 1
case .admin: return 2
case .owner: return 3
case .author: return 1
case .member: return 2
case .admin: return 3
case .owner: return 4
}
}
@@ -2141,6 +2168,14 @@ public struct ChatItem: Identifiable, Decodable {
}
}
public var memberToReplyDirectlyTo: GroupMember? {
switch chatDir {
case let .groupSnd(directMember): return directMember
case let .groupRcv(groupMember, _): return groupMember
default: return nil
}
}
public func memberToModerate(_ chatInfo: ChatInfo) -> (GroupInfo, GroupMember)? {
switch (chatInfo, chatDir) {
case let (.group(groupInfo), .groupRcv(groupMember, .msGroup)):
@@ -2254,7 +2289,6 @@ public struct ChatItem: Identifiable, Decodable {
)
}
// TODO group-direct: possibly this has to take sendRef as parameter instead (for directMember)
public static func liveDummy(_ chatType: ChatType) -> ChatItem {
var item = ChatItem(
chatDir: chatType == ChatType.direct ? CIDirection.directSnd : CIDirection.groupSnd(directMember: nil),
@@ -1633,7 +1633,7 @@ data class ChatItem (
@Serializable
enum class MessageScope(val messageScope: String) {
@SerialName("group") MSGroup("group"),
@SerialName("private") MSDirect("direct");
@SerialName("direct") MSDirect("direct");
}
@Serializable