Add conference message bubble

This commit is contained in:
Benoit Martins 2024-10-10 09:48:02 +02:00
parent a13f44e189
commit a8f7756241
6 changed files with 140 additions and 7 deletions

View file

@ -7,7 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
4ED1F0A881A9ACB5977A8987 /* (null) in Frameworks */ = {isa = PBXBuildFile; };
4ED1F0A881A9ACB5977A8987 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
660AAF7F2B839272004C0FA6 /* msgNotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
660D8A712B517D260092694D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 660D8A702B517D260092694D /* GoogleService-Info.plist */; };
6613A0AE2BAEB7DF008923A4 /* MeetingFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6613A0AD2BAEB7DF008923A4 /* MeetingFragment.swift */; };
@ -118,6 +118,7 @@
D76005F62B0798B00054B79A /* IntExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76005F52B0798B00054B79A /* IntExtension.swift */; };
D7702EF22AC7205000557C00 /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7702EF12AC7205000557C00 /* WelcomeView.swift */; };
D777DBB32AE12C5900565A99 /* ContactsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D777DBB22AE12C5900565A99 /* ContactsManager.swift */; };
D77A080E2CB6BCAF0095D589 /* MessageConferenceInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77A080D2CB6BCA10095D589 /* MessageConferenceInfo.swift */; };
D78290B82ADD3910004AA85C /* ContactsFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78290B72ADD3910004AA85C /* ContactsFragment.swift */; };
D78290BB2ADD40B2004AA85C /* ContactViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78290BA2ADD40B2004AA85C /* ContactViewModel.swift */; };
D783C77C2B1089B200622CC2 /* assistant_linphone_default_values in Resources */ = {isa = PBXBuildFile; fileRef = D783C77A2B1089B200622CC2 /* assistant_linphone_default_values */; };
@ -305,6 +306,7 @@
D76005F52B0798B00054B79A /* IntExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntExtension.swift; sourceTree = "<group>"; };
D7702EF12AC7205000557C00 /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = "<group>"; };
D777DBB22AE12C5900565A99 /* ContactsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsManager.swift; sourceTree = "<group>"; };
D77A080D2CB6BCA10095D589 /* MessageConferenceInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageConferenceInfo.swift; sourceTree = "<group>"; };
D78290B72ADD3910004AA85C /* ContactsFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsFragment.swift; sourceTree = "<group>"; };
D78290BA2ADD40B2004AA85C /* ContactViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactViewModel.swift; sourceTree = "<group>"; };
D783C77A2B1089B200622CC2 /* assistant_linphone_default_values */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = assistant_linphone_default_values; sourceTree = "<group>"; };
@ -373,7 +375,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4ED1F0A881A9ACB5977A8987 /* (null) in Frameworks */,
4ED1F0A881A9ACB5977A8987 /* BuildFile in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -482,6 +484,7 @@
D70959EF2B8DF33B0014AC0B /* Model */ = {
isa = PBXGroup;
children = (
D77A080D2CB6BCA10095D589 /* MessageConferenceInfo.swift */,
D70959F02B8DF3EC0014AC0B /* ConversationModel.swift */,
D7E6ADF22B9875C20009A2BC /* Message.swift */,
D7C2DA1C2CA44DE400A2441B /* EventModel.swift */,
@ -1215,6 +1218,7 @@
D7DA67642ACCB31700E95002 /* ProfileModeFragment.swift in Sources */,
D7CEE03D2B7A23B200FD79B7 /* ConversationsListFragment.swift in Sources */,
D74C9CFC2ACACF370021626A /* WelcomePage3Fragment.swift in Sources */,
D77A080E2CB6BCAF0095D589 /* MessageConferenceInfo.swift in Sources */,
C6A5A9412C10B5D50070FEA4 /* EncodableExtension.swift in Sources */,
D719ABCC2ABC769C00B41C10 /* AssistantView.swift in Sources */,
C62817342C1C7C7400DBA646 /* HelpView.swift in Sources */,

View file

@ -1817,6 +1817,9 @@
},
"Meeting added to iPhone calendar" : {
},
"Meeting invite !!" : {
},
"Meetings" : {

View file

@ -302,6 +302,10 @@ struct ChatBubbleView: View {
})
.padding(.leading, eventLogMessage.message.isOutgoing ? 40 : 0)
.padding(.trailing, !eventLogMessage.message.isOutgoing ? 40 : 0)
} else if eventLogMessage.message.isIcalendar {
Text("Meeting invite !!")
.foregroundStyle(Color.grayMain2c500)
.default_text_style(styleSize: 12)
}
}
.onTapGesture {}

View file

@ -84,6 +84,8 @@ public struct Message: Identifiable, Hashable {
public var isEphemeral: Bool
public var ephemeralExpireTime: Int
public var ephemeralLifetime: Int
public var isIcalendar: Bool
public init(
id: String,
@ -104,7 +106,8 @@ public struct Message: Identifiable, Hashable {
reactions: [String] = [],
isEphemeral: Bool = false,
ephemeralExpireTime: Int = 0,
ephemeralLifetime: Int = 0
ephemeralLifetime: Int = 0,
isIcalendar: Bool = false
) {
self.id = id
self.appData = appData
@ -125,6 +128,7 @@ public struct Message: Identifiable, Hashable {
self.isEphemeral = isEphemeral
self.ephemeralExpireTime = ephemeralExpireTime
self.ephemeralLifetime = ephemeralLifetime
self.isIcalendar = isIcalendar
}
public static func makeMessage(

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2010-2023 Belledonne Communications SARL.
*
* This file is part of linphone-iphone
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import Foundation
public enum MessageConferenceState {
case updated
case cancelled
}
public struct MessageConferenceInfo {
public let id: String
var uri: URL
var subject: String
var description: String
var state: MessageConferenceState
var dateTime: String
//var duration: time_t
//var participantInfos: [ParticipantInfo]
public init(id: String, uri: URL, subject: String, description: String, state: MessageConferenceState, dateTime: String) {
self.id = id
self.uri = uri
self.subject = subject
self.description = description
self.state = state
self.dateTime = dateTime
}
}

View file

@ -506,7 +506,8 @@ class ConversationViewModel: ObservableObject {
reactions: reactionsTmp,
isEphemeral: eventLog.chatMessage?.isEphemeral ?? false,
ephemeralExpireTime: eventLog.chatMessage?.ephemeralExpireTime ?? 0,
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0,
isIcalendar: eventLog.chatMessage?.contents.first?.isIcalendar ?? false
)
)
)
@ -729,7 +730,8 @@ class ConversationViewModel: ObservableObject {
reactions: reactionsTmp,
isEphemeral: eventLog.chatMessage?.isEphemeral ?? false,
ephemeralExpireTime: eventLog.chatMessage?.ephemeralExpireTime ?? 0,
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0,
isIcalendar: eventLog.chatMessage?.contents.first?.isIcalendar ?? false
)
), at: 0
)
@ -964,7 +966,8 @@ class ConversationViewModel: ObservableObject {
reactions: reactionsTmp,
isEphemeral: eventLog.chatMessage?.isEphemeral ?? false,
ephemeralExpireTime: eventLog.chatMessage?.ephemeralExpireTime ?? 0,
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0,
isIcalendar: eventLog.chatMessage?.contents.first?.isIcalendar ?? false
)
)
@ -1245,7 +1248,8 @@ class ConversationViewModel: ObservableObject {
reactions: reactionsTmp,
isEphemeral: eventLog.chatMessage?.isEphemeral ?? false,
ephemeralExpireTime: eventLog.chatMessage?.ephemeralExpireTime ?? 0,
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0,
isIcalendar: eventLog.chatMessage?.contents.first?.isIcalendar ?? false
)
), at: 0
)
@ -1888,6 +1892,75 @@ class ConversationViewModel: ObservableObject {
}
}
}
func parseConferenceInvite(content: Content) -> MessageConferenceInfo? {
var meetingConferenceUri: URL?
var meetingSubject: String = ""
var meetingDescription: String = ""
var meetingUpdated: Bool = false
var meetingCancelled: Bool = false
var meetingDate: String = ""
var meetingTime: String = ""
var meetingDay: String = ""
var meetingDayNumber: String = ""
var meetingParticipants: String = ""
var meetingFound: Bool = false
if let conferenceInfo = try? Factory.Instance.createConferenceInfoFromIcalendarContent(content: content) {
if let conferenceAddress = conferenceInfo.uri {
let conferenceUri = conferenceAddress.asStringUriOnly()
Log.info("Found conference info with URI [\(conferenceUri)] and subject [\(conferenceInfo.subject)]")
meetingConferenceUri = URL(string: conferenceAddress.asStringUriOnly())
meetingSubject = conferenceInfo.subject ?? ""
meetingDescription = conferenceInfo.description ?? ""
meetingUpdated = (conferenceInfo.state == .Updated)
meetingCancelled = (conferenceInfo.state == .Cancelled)
let timestamp = conferenceInfo.dateTime
let duration = conferenceInfo.duration
let timeInterval = TimeInterval(timestamp)
let dateTmp = Date(timeIntervalSince1970: timeInterval)
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .full
dateFormatter.timeStyle = .none
let date = dateFormatter.string(from: dateTmp)
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = Locale.current.identifier == "fr_FR" ? "HH:mm" : "h:mm a"
let timeTmp = timeFormatter.string(from: dateTmp)
/*
let timeBisInterval = TimeInterval(timestamp + (Int(duration) * 60))
let timeBis = Date(timeIntervalSince1970: timeBisInterval)
let endTime = timeFormatter.string(from: timeBis)
let startTime = TimestampUtils.timeToString(timestamp)
let end = timestamp + (duration * 60)
let endTime = TimestampUtils.timeToString(end)
meetingDate = date
meetingTime = "\(startTime) - \(endTime)"
meetingDay = TimestampUtils.dayOfWeek(timestamp)
meetingDayNumber = TimestampUtils.dayOfMonth(timestamp)
let count = conferenceInfo.participantInfos.count
meetingParticipants = AppUtils.getStringWithPlural(R.plurals.conference_participants_list_title, count: count, countString: "\(count)")
meetingFound = true
*/
if meetingConferenceUri != nil {
return MessageConferenceInfo(id: UUID().uuidString, uri: meetingConferenceUri!, subject: meetingSubject, description: meetingDescription, state: .updated, dateTime: timeTmp)
}
}
}
return nil
}
}
// swiftlint:enable line_length
// swiftlint:enable type_body_length