Ephemeral message

This commit is contained in:
Benoit Martins 2024-10-08 09:12:16 +02:00
parent 2eee40a7ae
commit 2b80c5b78b
4 changed files with 156 additions and 11 deletions

View file

@ -34,6 +34,9 @@ struct ChatBubbleView: View {
@State private var isPressed: Bool = false
@State private var timePassed: TimeInterval?
@State private var timer: Timer?
@State private var ephemeralLifetime: String = ""
var body: some View {
HStack {
if eventLogMessage.eventModel.eventLogType == .ConferenceChatMessage {
@ -165,6 +168,28 @@ struct ChatBubbleView: View {
}
HStack(alignment: .center) {
if eventLogMessage.message.isEphemeral && eventLogMessage.message.isOutgoing {
Text(ephemeralLifetime)
.foregroundStyle(Color.grayMain2c500)
.default_text_style_300(styleSize: 14)
.padding(.top, 1)
.onAppear {
updateEphemeralTimer()
}
.onChange(of: eventLogMessage.message.ephemeralExpireTime) { ephemeralExpireTimeTmp in
if ephemeralExpireTimeTmp > 0 {
updateEphemeralTimer()
}
}
Image("clock-countdown")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c500)
.frame(width: 15, height: 15)
.padding(.top, 1)
}
Text(conversationViewModel.getMessageTime(startDate: eventLogMessage.message.dateReceived))
.foregroundStyle(Color.grayMain2c500)
.default_text_style_300(styleSize: 14)
@ -187,6 +212,29 @@ struct ChatBubbleView: View {
.padding(.top, 1)
}
}
if eventLogMessage.message.isEphemeral && !eventLogMessage.message.isOutgoing {
Image("clock-countdown")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c500)
.frame(width: 15, height: 15)
.padding(.top, 1)
.padding(.trailing, -4)
Text(ephemeralLifetime)
.foregroundStyle(Color.grayMain2c500)
.default_text_style_300(styleSize: 14)
.padding(.top, 1)
.onAppear {
updateEphemeralTimer()
}
.onChange(of: eventLogMessage.message.ephemeralExpireTime) { ephemeralExpireTimeTmp in
if ephemeralExpireTimeTmp > 0 {
updateEphemeralTimer()
}
}
}
}
.onTapGesture {
conversationViewModel.selectedMessageToDisplayDetails = eventLogMessage
@ -551,6 +599,30 @@ struct ChatBubbleView: View {
return "file"
}
}
private func updateEphemeralTimer() {
if eventLogMessage.message.isEphemeral {
if eventLogMessage.message.ephemeralExpireTime == 0 {
// Message hasn't been read by all participants yet
self.ephemeralLifetime = eventLogMessage.message.ephemeralLifetime.convertDurationToString()
} else {
let remaining = eventLogMessage.message.ephemeralExpireTime - Int(Date().timeIntervalSince1970)
self.ephemeralLifetime = remaining.convertDurationToString()
if timer == nil {
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
let updatedRemaining = eventLogMessage.message.ephemeralExpireTime - Int(Date().timeIntervalSince1970)
if updatedRemaining <= 0 {
timer?.invalidate()
timer = nil
} else {
self.ephemeralLifetime = updatedRemaining.convertDurationToString()
}
}
}
}
}
}
}
enum URLType {

View file

@ -233,7 +233,7 @@ struct UIList: UIViewRepresentable {
tableView.insertSections([section], with: .top)
case .delete(let section, let row):
tableView.deleteRows(at: [IndexPath(row: row, section: section)], with: .top)
tableView.deleteRows(at: [IndexPath(row: row, section: section)], with: .left)
case .insert(let section, let row):
tableView.insertRows(at: [IndexPath(row: row, section: section)], with: .top)
case .edit(let section, let row):

View file

@ -80,6 +80,10 @@ public struct Message: Identifiable, Hashable {
public var isForward: Bool
public var ownReaction: String
public var reactions: [String]
public var isEphemeral: Bool
public var ephemeralExpireTime: Int
public var ephemeralLifetime: Int
public init(
id: String,
@ -97,7 +101,10 @@ public struct Message: Identifiable, Hashable {
replyMessage: ReplyMessage? = nil,
isForward: Bool = false,
ownReaction: String = "",
reactions: [String] = []
reactions: [String] = [],
isEphemeral: Bool = false,
ephemeralExpireTime: Int = 0,
ephemeralLifetime: Int = 0
) {
self.id = id
self.appData = appData
@ -115,6 +122,9 @@ public struct Message: Identifiable, Hashable {
self.isForward = isForward
self.ownReaction = ownReaction
self.reactions = reactions
self.isEphemeral = isEphemeral
self.ephemeralExpireTime = ephemeralExpireTime
self.ephemeralLifetime = ephemeralLifetime
}
public static func makeMessage(
@ -167,7 +177,7 @@ extension Message {
extension Message: Equatable {
public static func == (lhs: Message, rhs: Message) -> Bool {
lhs.id == rhs.id && lhs.status == rhs.status && lhs.isFirstMessage == rhs.isFirstMessage && lhs.ownReaction == rhs.ownReaction && lhs.reactions == rhs.reactions
lhs.id == rhs.id && lhs.status == rhs.status && lhs.isFirstMessage == rhs.isFirstMessage && lhs.ownReaction == rhs.ownReaction && lhs.reactions == rhs.reactions && lhs.ephemeralExpireTime == rhs.ephemeralExpireTime
}
}

View file

@ -114,6 +114,8 @@ class ConversationViewModel: ObservableObject {
self.getNewMessages(eventLogs: eventLogs)
}, onChatMessageSending: { (_: ChatRoom, eventLog: EventLog) in
self.getNewMessages(eventLogs: [eventLog])
}, onEphemeralMessageDeleted: {(_: ChatRoom, eventLog: EventLog) in
self.removeMessage(eventLog)
})
self.chatRoomDelegateHolder = ChatRoomDelegateHolder(chatroom: chatroom, delegate: chatRoomDelegate)
}
@ -139,12 +141,22 @@ class ConversationViewModel: ObservableObject {
statusTmp = .sending
}
let ephemeralExpireTimeTmp = message.ephemeralExpireTime
if !self.conversationMessagesSection.isEmpty && !self.conversationMessagesSection[0].rows.isEmpty {
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLog.chatMessage?.messageId == message.messageId}) {
if indexMessage < self.conversationMessagesSection[0].rows.count && self.conversationMessagesSection[0].rows[indexMessage].message.status != statusTmp {
DispatchQueue.main.async {
//self.objectWillChange.send()
self.conversationMessagesSection[0].rows[indexMessage].message.status = statusTmp ?? .error
if indexMessage < self.conversationMessagesSection[0].rows.count {
if self.conversationMessagesSection[0].rows[indexMessage].message.status != statusTmp {
DispatchQueue.main.async {
//self.objectWillChange.send()
self.conversationMessagesSection[0].rows[indexMessage].message.status = statusTmp ?? .error
self.conversationMessagesSection[0].rows[indexMessage].message.ephemeralExpireTime = ephemeralExpireTimeTmp
}
} else {
DispatchQueue.main.async {
//self.objectWillChange.send()
self.conversationMessagesSection[0].rows[indexMessage].message.ephemeralExpireTime = ephemeralExpireTimeTmp
}
}
}
}
@ -201,7 +213,18 @@ class ConversationViewModel: ObservableObject {
self.conversationMessagesSection[0].rows[indexMessage!].message.reactions = reactionsTmp
}
}
}, onEphemeralMessageTimerStarted: { (message: ChatMessage) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLog.chatMessage?.messageId == message.messageId})
let ephemeralExpireTimeTmp = message.ephemeralExpireTime
DispatchQueue.main.async {
if indexMessage != nil {
self.objectWillChange.send()
self.conversationMessagesSection[0].rows[indexMessage!].message.ephemeralExpireTime = ephemeralExpireTimeTmp
}
}
})
self.chatMessageDelegateHolders.append(ChatMessageDelegateHolder(message: message, delegate: chatMessageDelegate))
}
}
@ -480,7 +503,10 @@ class ConversationViewModel: ObservableObject {
replyMessage: replyMessageTmp,
isForward: eventLog.chatMessage?.isForward ?? false,
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
reactions: reactionsTmp
reactions: reactionsTmp,
isEphemeral: eventLog.chatMessage?.isEphemeral ?? false,
ephemeralExpireTime: eventLog.chatMessage?.ephemeralExpireTime ?? 0,
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0
)
)
)
@ -700,7 +726,10 @@ class ConversationViewModel: ObservableObject {
replyMessage: replyMessageTmp,
isForward: eventLog.chatMessage?.isForward ?? false,
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
reactions: reactionsTmp
reactions: reactionsTmp,
isEphemeral: eventLog.chatMessage?.isEphemeral ?? false,
ephemeralExpireTime: eventLog.chatMessage?.ephemeralExpireTime ?? 0,
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0
)
), at: 0
)
@ -932,7 +961,10 @@ class ConversationViewModel: ObservableObject {
replyMessage: replyMessageTmp,
isForward: eventLog.chatMessage?.isForward ?? false,
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
reactions: reactionsTmp
reactions: reactionsTmp,
isEphemeral: eventLog.chatMessage?.isEphemeral ?? false,
ephemeralExpireTime: eventLog.chatMessage?.ephemeralExpireTime ?? 0,
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0
)
)
@ -1210,7 +1242,10 @@ class ConversationViewModel: ObservableObject {
replyMessage: replyMessageTmp,
isForward: eventLog.chatMessage?.isForward ?? false,
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
reactions: reactionsTmp
reactions: reactionsTmp,
isEphemeral: eventLog.chatMessage?.isEphemeral ?? false,
ephemeralExpireTime: eventLog.chatMessage?.ephemeralExpireTime ?? 0,
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0
)
), at: 0
)
@ -1257,6 +1292,34 @@ class ConversationViewModel: ObservableObject {
}
}
func removeMessage(_ eventLog: EventLog) {
/*
if let found = self.conversationMessagesSection[0].rows.first(where: { $0.message.id == eventLog.chatMessage?.messageId }) {
var updatedList = self.conversationMessagesSection[0].rows
print("Removing message from conversation events list")
if let index = updatedList.firstIndex(where: { $0.message.id == found.message.id }) {
updatedList.remove(at: index)
}
DispatchQueue.main.async {
self.conversationMessagesSection[0].rows = updatedList
}
} else {
print("Failed to find matching message in conversation events list")
}
*/
if let index = self.conversationMessagesSection[0].rows.firstIndex(where: { $0.message.id == eventLog.chatMessage?.messageId }) {
DispatchQueue.main.async {
if index > 0 && self.conversationMessagesSection[0].rows[index - 1].message.address == self.conversationMessagesSection[0].rows[index].message.address {
self.conversationMessagesSection[0].rows[index - 1].message.isFirstMessage = self.conversationMessagesSection[0].rows[index].message.isFirstMessage
}
self.conversationMessagesSection[0].rows.remove(at: index)
}
}
}
func sendMessage(audioRecorder: AudioRecorder? = nil) {
coreContext.doOnCoreQueue { _ in
do {