forked from mirrors/linphone-iphone
Implement meetings bottom sheet and meeting details delete action
This commit is contained in:
parent
5b5a5d88fa
commit
5b3f412bb7
9 changed files with 236 additions and 15 deletions
|
|
@ -7,6 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
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 */; };
|
||||
|
|
@ -29,6 +30,7 @@
|
|||
66E56BC92BA4A6D7006CE56F /* MeetingsListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66E56BC82BA4A6D7006CE56F /* MeetingsListViewModel.swift */; };
|
||||
66E56BCC2BA9A1E0006CE56F /* MeetingsListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66E56BCB2BA9A1E0006CE56F /* MeetingsListItemModel.swift */; };
|
||||
66E56BCE2BA9A1F8006CE56F /* MeetingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66E56BCD2BA9A1F8006CE56F /* MeetingModel.swift */; };
|
||||
66F08C892C2AFEF700D9AE2F /* MeetingsListBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66F08C882C2AFEF700D9AE2F /* MeetingsListBottomSheet.swift */; };
|
||||
66F626B22BCEBB86003E2DEC /* AddParticipantsFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66F626B12BCEBB86003E2DEC /* AddParticipantsFragment.swift */; };
|
||||
66FBFC482B83B8CC00BC6AB1 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C492002B24DB6900CEA16D /* Log.swift */; };
|
||||
66FBFC492B83BD2400BC6AB1 /* ConfigExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491F82B24D25A00CEA16D /* ConfigExtension.swift */; };
|
||||
|
|
@ -207,6 +209,7 @@
|
|||
66E56BC82BA4A6D7006CE56F /* MeetingsListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingsListViewModel.swift; sourceTree = "<group>"; };
|
||||
66E56BCB2BA9A1E0006CE56F /* MeetingsListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingsListItemModel.swift; sourceTree = "<group>"; };
|
||||
66E56BCD2BA9A1F8006CE56F /* MeetingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingModel.swift; sourceTree = "<group>"; };
|
||||
66F08C882C2AFEF700D9AE2F /* MeetingsListBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingsListBottomSheet.swift; sourceTree = "<group>"; };
|
||||
66F626B12BCEBB86003E2DEC /* AddParticipantsFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddParticipantsFragment.swift; sourceTree = "<group>"; };
|
||||
C60E8F182C0F649200A06DB8 /* UIApplicationExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationExtension.swift; sourceTree = "<group>"; };
|
||||
C62817272C1B389700DBA646 /* SideMenuAccountRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuAccountRow.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -349,6 +352,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4ED1F0A881A9ACB5977A8987 /* BuildFile in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -410,6 +414,7 @@
|
|||
66E50A4A2BD12B7800AD61CA /* MeetingsFragment.swift */,
|
||||
6613A0AD2BAEB7DF008923A4 /* MeetingFragment.swift */,
|
||||
6613A0AF2BAEB7F4008923A4 /* MeetingsListFragment.swift */,
|
||||
66F08C882C2AFEF700D9AE2F /* MeetingsListBottomSheet.swift */,
|
||||
6646A7A22BB2E224006B842A /* ScheduleMeetingFragment.swift */,
|
||||
66F626B12BCEBB86003E2DEC /* AddParticipantsFragment.swift */,
|
||||
);
|
||||
|
|
@ -1126,6 +1131,7 @@
|
|||
D7B99E9B2B29F7C300BE7BF2 /* ActivityIndicator.swift in Sources */,
|
||||
66F626B22BCEBB86003E2DEC /* AddParticipantsFragment.swift in Sources */,
|
||||
D72343302ACEFEF8009AA24E /* QrCodeScannerFragment.swift in Sources */,
|
||||
66F08C892C2AFEF700D9AE2F /* MeetingsListBottomSheet.swift in Sources */,
|
||||
D726E43F2B19E56F0083C415 /* StartCallViewModel.swift in Sources */,
|
||||
D70A26EE2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift in Sources */,
|
||||
D7D1698C2AE66FA500109A5C /* MagicSearchSingleton.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ struct ContentView: View {
|
|||
@State var isShowEditContactFragment = false
|
||||
@State var isShowStartCallFragment = false
|
||||
@State var isShowDismissPopup = false
|
||||
@State var isShowSendCancelMeetingNotificationPopup = false
|
||||
|
||||
@State var fullscreenVideo = false
|
||||
|
||||
|
|
@ -530,7 +531,8 @@ struct ContentView: View {
|
|||
MeetingsView(
|
||||
meetingsListViewModel: meetingsListViewModel,
|
||||
meetingViewModel: meetingViewModel,
|
||||
isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment
|
||||
isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment,
|
||||
isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -762,7 +764,7 @@ struct ContentView: View {
|
|||
.background(Color.gray100)
|
||||
.ignoresSafeArea(.keyboard)
|
||||
} else if self.index == 3 {
|
||||
MeetingFragment(meetingViewModel: meetingViewModel, meetingsListViewModel: meetingsListViewModel, isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment)
|
||||
MeetingFragment(meetingViewModel: meetingViewModel, meetingsListViewModel: meetingsListViewModel, isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment, isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.gray100)
|
||||
.ignoresSafeArea(.keyboard)
|
||||
|
|
@ -980,6 +982,28 @@ struct ContentView: View {
|
|||
.onAppear {
|
||||
}
|
||||
}
|
||||
|
||||
if isShowSendCancelMeetingNotificationPopup {
|
||||
PopupView(isShowPopup: $isShowSendCancelMeetingNotificationPopup,
|
||||
title: Text("The meeting has been cancelled"),
|
||||
content: Text("Send notification to participants ?"),
|
||||
titleFirstButton: Text("Cancel"),
|
||||
actionFirstButton: { self.isShowSendCancelMeetingNotificationPopup.toggle() },
|
||||
titleSecondButton: Text("Ok"),
|
||||
actionSecondButton: {
|
||||
if let meetingToDelete = self.meetingsListViewModel.selectedMeetingToDelete {
|
||||
// We're in the meeting list view
|
||||
self.meetingViewModel.sendMeetingCancelledNotifications(meeting: meetingToDelete)
|
||||
self.isShowSendCancelMeetingNotificationPopup.toggle()
|
||||
}
|
||||
})
|
||||
.background(.black.opacity(0.65))
|
||||
.zIndex(3)
|
||||
.onTapGesture {
|
||||
self.isShowSendCancelMeetingNotificationPopup.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
if telecomManager.meetingWaitingRoomDisplayed {
|
||||
MeetingWaitingRoomFragment(meetingWaitingRoomViewModel: meetingWaitingRoomViewModel)
|
||||
.zIndex(3)
|
||||
|
|
|
|||
|
|
@ -130,6 +130,13 @@ struct ToastView: View {
|
|||
.default_text_style(styleSize: 15)
|
||||
.padding(8)
|
||||
|
||||
case "Success_toast_meeting_deleted":
|
||||
Text("Successfully removed meeting")
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundStyle(Color.greenSuccess500)
|
||||
.default_text_style(styleSize: 15)
|
||||
.padding(8)
|
||||
|
||||
case "Failed_toast_call_transfer_failed":
|
||||
Text("Call transfer failed!")
|
||||
.multilineTextAlignment(.center)
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ struct MeetingFragment: View {
|
|||
|
||||
@State var addParticipantsViewModel = AddParticipantsViewModel()
|
||||
@Binding var isShowScheduleMeetingFragment: Bool
|
||||
@Binding var isShowSendCancelMeetingNotificationPopup: Bool
|
||||
|
||||
@ViewBuilder
|
||||
func getParticipantLine(participant: SelectedAddressModel) -> some View {
|
||||
|
|
@ -105,13 +106,34 @@ struct MeetingFragment: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
Image("dots-three-vertical")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orangeMain500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.onTapGesture {
|
||||
|
||||
Menu {
|
||||
Button(role: .destructive) {
|
||||
withAnimation {
|
||||
meetingsListViewModel.selectedMeetingToDelete = meetingViewModel.displayedMeeting
|
||||
meetingViewModel.displayedMeeting = nil
|
||||
meetingsListViewModel.deleteSelectedMeeting()
|
||||
isShowSendCancelMeetingNotificationPopup.toggle()
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Image("trash-simple")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
Text("Delete this meeting")
|
||||
.foregroundStyle(Color.redDanger500)
|
||||
.default_text_style(styleSize: 16)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
Image("dots-three-vertical")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orangeMain500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 50)
|
||||
|
|
@ -279,7 +301,8 @@ struct MeetingFragment: View {
|
|||
model.description = "description du meeting ça va être la bringue wesh wesh gros bien ou bien ça roule"
|
||||
return MeetingFragment(meetingViewModel: model
|
||||
, meetingsListViewModel: MeetingsListViewModel()
|
||||
, isShowScheduleMeetingFragment: .constant(true))
|
||||
, isShowScheduleMeetingFragment: .constant(true)
|
||||
, isShowSendCancelMeetingNotificationPopup: .constant(false))
|
||||
}
|
||||
|
||||
// swiftlint:enable line_length
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@ struct MeetingsFragment: View {
|
|||
|
||||
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
|
||||
|
||||
@State var showingSheet: Bool = false
|
||||
@State var reader : ScrollViewProxy?
|
||||
@Binding var showingSheet: Bool
|
||||
|
||||
@ViewBuilder
|
||||
func createMonthLine(model: MeetingsListItemModel) -> some View {
|
||||
|
|
@ -84,6 +83,10 @@ struct MeetingsFragment: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.onLongPressGesture(minimumDuration: 0.2) {
|
||||
meetingViewModel.displayedMeeting = model.model
|
||||
showingSheet.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
|
|
@ -173,5 +176,7 @@ struct MeetingsFragment: View {
|
|||
}
|
||||
|
||||
#Preview {
|
||||
MeetingsFragment(meetingsListViewModel: MeetingsListViewModel(), meetingViewModel: MeetingViewModel())
|
||||
MeetingsFragment(meetingsListViewModel: MeetingsListViewModel(),
|
||||
meetingViewModel: MeetingViewModel(),
|
||||
showingSheet: .constant(false))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* 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 SwiftUI
|
||||
import linphonesw
|
||||
import Contacts
|
||||
|
||||
struct MeetingsListBottomSheet: View {
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
|
||||
@State private var orientation = UIDevice.current.orientation
|
||||
|
||||
@ObservedObject var meetingsListViewModel: MeetingsListViewModel
|
||||
@Binding var showingSheet: Bool
|
||||
@Binding var isShowSendCancelMeetingNotificationPopup: Bool
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
if idiom != .pad && (orientation == .landscapeLeft
|
||||
|| orientation == .landscapeRight
|
||||
|| UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) {
|
||||
Spacer()
|
||||
HStack {
|
||||
Spacer()
|
||||
Button("Close") {
|
||||
if #available(iOS 16.0, *) {
|
||||
showingSheet.toggle()
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.trailing)
|
||||
}
|
||||
|
||||
Button {
|
||||
meetingsListViewModel.deleteSelectedMeeting()
|
||||
CoreContext.shared.doOnCoreQueue { core in
|
||||
if let organizerUri = self.meetingsListViewModel.selectedMeetingToDelete?.confInfo.organizer {
|
||||
if core.defaultAccount?.contactAddress?.weakEqual(address2: organizerUri) ?? false {
|
||||
DispatchQueue.main.async {
|
||||
// If we are the organizer, display popup for sending
|
||||
self.isShowSendCancelMeetingNotificationPopup = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if #available(iOS 16.0, *) {
|
||||
if idiom != .pad {
|
||||
showingSheet.toggle()
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Image("trash-simple")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.redDanger500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
Text("Delete this meeting")
|
||||
.foregroundStyle(Color.redDanger500)
|
||||
.default_text_style(styleSize: 16)
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxHeight: .infinity)
|
||||
}
|
||||
.padding(.horizontal, 30)
|
||||
.background(Color.gray100)
|
||||
|
||||
}
|
||||
.background(Color.gray100)
|
||||
.frame(maxWidth: .infinity)
|
||||
.onRotate { newOrientation in
|
||||
orientation = newOrientation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,16 +20,40 @@
|
|||
import SwiftUI
|
||||
|
||||
struct MeetingsView: View {
|
||||
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
|
||||
|
||||
@ObservedObject var meetingsListViewModel: MeetingsListViewModel
|
||||
@ObservedObject var meetingViewModel: MeetingViewModel
|
||||
|
||||
@Binding var isShowScheduleMeetingFragment: Bool
|
||||
@Binding var isShowSendCancelMeetingNotificationPopup: Bool
|
||||
|
||||
@State private var showingSheet = false
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
MeetingsFragment(meetingsListViewModel: meetingsListViewModel, meetingViewModel: meetingViewModel)
|
||||
|
||||
if #available(iOS 16.0, *), idiom != .pad {
|
||||
MeetingsFragment(meetingsListViewModel: meetingsListViewModel, meetingViewModel: meetingViewModel, showingSheet: $showingSheet)
|
||||
.sheet(isPresented: $showingSheet) {
|
||||
MeetingsListBottomSheet(
|
||||
meetingsListViewModel: meetingsListViewModel,
|
||||
showingSheet: $showingSheet,
|
||||
isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup
|
||||
)
|
||||
.presentationDetents([.fraction(0.1)])
|
||||
}
|
||||
} else {
|
||||
MeetingsFragment(meetingsListViewModel: meetingsListViewModel, meetingViewModel: meetingViewModel, showingSheet: $showingSheet)
|
||||
.halfSheet(showSheet: $showingSheet) {
|
||||
MeetingsListBottomSheet(
|
||||
meetingsListViewModel: meetingsListViewModel,
|
||||
showingSheet: $showingSheet,
|
||||
isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup
|
||||
)
|
||||
} onDismiss: {}
|
||||
}
|
||||
|
||||
Button {
|
||||
withAnimation {
|
||||
|
|
@ -57,6 +81,7 @@ struct MeetingsView: View {
|
|||
MeetingsView(
|
||||
meetingsListViewModel: MeetingsListViewModel(),
|
||||
meetingViewModel: MeetingViewModel(),
|
||||
isShowScheduleMeetingFragment: .constant(false)
|
||||
isShowScheduleMeetingFragment: .constant(false),
|
||||
isShowSendCancelMeetingNotificationPopup: .constant(false)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -348,4 +348,11 @@ class MeetingViewModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
func sendMeetingCancelledNotifications(meeting: MeetingModel) {
|
||||
Log.error("\(MeetingViewModel.TAG) - sendMeetingCancelledNotifications TODO")
|
||||
//CoreContext.shared.doOnCoreQueue { core in
|
||||
// self.resetConferenceSchedulerAndListeners(core: core)
|
||||
// self.conferenceScheduler?.cancelConference(conferenceInfo: meeting.confInfo)
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class MeetingsListViewModel: ObservableObject {
|
|||
|
||||
private var coreContext = CoreContext.shared
|
||||
private var mCoreSuscriptions = Set<AnyCancellable?>()
|
||||
var selectedMeeting: ConversationModel?
|
||||
var selectedMeetingToDelete: MeetingModel?
|
||||
|
||||
@Published var meetingsList: [MeetingsListItemModel] = []
|
||||
@Published var currentFilter = ""
|
||||
|
|
@ -112,4 +112,25 @@ class MeetingsListViewModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
func deleteSelectedMeeting() {
|
||||
guard let meetingToDelete = selectedMeetingToDelete else {
|
||||
Log.error("\(MeetingsListViewModel.TAG) Could not delete meeting because none was selected")
|
||||
return
|
||||
}
|
||||
|
||||
coreContext.doOnCoreQueue { core in
|
||||
core.deleteConferenceInformation(conferenceInfo: meetingToDelete.confInfo)
|
||||
DispatchQueue.main.async {
|
||||
if let index = self.meetingsList.firstIndex(where: { $0.model?.address == meetingToDelete.address }) {
|
||||
if self.todayIdx > index {
|
||||
// bump todayIdx one place up
|
||||
self.todayIdx -= 1
|
||||
}
|
||||
self.meetingsList.remove(at: index)
|
||||
ToastViewModel.shared.toastMessage = "Success_toast_meeting_deleted"
|
||||
ToastViewModel.shared.displayToast = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue