Extract AddParticipantsViewModel from the ScheduleMeetingViewModel to be used for other future views

This commit is contained in:
QuentinArguillere 2024-04-29 17:34:53 +02:00
parent 1f0c3fa5f7
commit 19da4e0d64
5 changed files with 71 additions and 41 deletions

View file

@ -13,6 +13,7 @@
6613A0B02BAEB7F4008923A4 /* MeetingsListFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6613A0AF2BAEB7F4008923A4 /* MeetingsListFragment.swift */; };
6613A0B42BAEBE3F008923A4 /* MeetingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6613A0B32BAEBE3F008923A4 /* MeetingViewModel.swift */; };
6613A0B62BAEBE5C008923A4 /* ScheduleMeetingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6613A0B52BAEBE5C008923A4 /* ScheduleMeetingViewModel.swift */; };
66162A202BDFC2F900DCE913 /* AddParticipantsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66162A1F2BDFC2F900DCE913 /* AddParticipantsViewModel.swift */; };
662B69D92B25DE18007118BF /* TelecomManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 662B69D82B25DE18007118BF /* TelecomManager.swift */; };
662B69DB2B25DE25007118BF /* ProviderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 662B69DA2B25DE25007118BF /* ProviderDelegate.swift */; };
6646A7A32BB2E224006B842A /* ScheduleMeetingFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6646A7A22BB2E224006B842A /* ScheduleMeetingFragment.swift */; };
@ -167,6 +168,7 @@
6613A0AF2BAEB7F4008923A4 /* MeetingsListFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingsListFragment.swift; sourceTree = "<group>"; };
6613A0B32BAEBE3F008923A4 /* MeetingViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingViewModel.swift; sourceTree = "<group>"; };
6613A0B52BAEBE5C008923A4 /* ScheduleMeetingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleMeetingViewModel.swift; sourceTree = "<group>"; };
66162A1F2BDFC2F900DCE913 /* AddParticipantsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddParticipantsViewModel.swift; sourceTree = "<group>"; };
662B69D82B25DE18007118BF /* TelecomManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelecomManager.swift; sourceTree = "<group>"; };
662B69DA2B25DE25007118BF /* ProviderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderDelegate.swift; sourceTree = "<group>"; };
6646A7A22BB2E224006B842A /* ScheduleMeetingFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleMeetingFragment.swift; sourceTree = "<group>"; };
@ -658,6 +660,7 @@
D7A2EDD42AC180FE005D90FC /* Viewmodel */ = {
isa = PBXGroup;
children = (
66162A1F2BDFC2F900DCE913 /* AddParticipantsViewModel.swift */,
D7A2EDD52AC18115005D90FC /* SharedMainViewModel.swift */,
D796F1FF2B0BB61A0041115F /* ToastViewModel.swift */,
);
@ -980,6 +983,7 @@
D734499B2BC694C900778C56 /* MeetingWaitingRoomViewModel.swift in Sources */,
D719ABB72ABC67BF00B41C10 /* LinphoneApp.swift in Sources */,
66E50A4B2BD12B7800AD61CA /* MeetingsFragment.swift in Sources */,
66162A202BDFC2F900DCE913 /* AddParticipantsViewModel.swift in Sources */,
D732A91B2B061BD900DB42BA /* HistoryListBottomSheet.swift in Sources */,
D72250632ADE9615008FB426 /* HistoryViewModel.swift in Sources */,
66E56BC92BA4A6D7006CE56F /* MeetingsListViewModel.swift in Sources */,
@ -1252,7 +1256,7 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_ENTITLEMENTS = Linphone/Linphone.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 4;
CURRENT_PROJECT_VERSION = 10;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "\"Linphone/Preview Content\"";

View file

@ -18,7 +18,8 @@ struct AddParticipantsFragment: View {
@ObservedObject var contactsManager = ContactsManager.shared
@ObservedObject var magicSearch = MagicSearchSingleton.shared
@ObservedObject var scheduleMeetingViewModel: ScheduleMeetingViewModel
@ObservedObject var addParticipantsViewModel: AddParticipantsViewModel
var confirmAddParticipantsFunc: ([SelectedAddressModel]) -> Void
@State private var delayedColor = Color.white
@FocusState var isSearchFieldFocused: Bool
@ -50,7 +51,7 @@ struct AddParticipantsFragment: View {
.padding(.top, 2)
.padding(.leading, -10)
.onTapGesture {
scheduleMeetingViewModel.participantsToAdd = []
addParticipantsViewModel.reset()
dismiss()
}
@ -59,7 +60,7 @@ struct AddParticipantsFragment: View {
.multilineTextAlignment(.leading)
.default_text_style_orange_800(styleSize: 16)
.padding(.top, 20)
Text("\($scheduleMeetingViewModel.participants.count) selected participants")
Text("\($addParticipantsViewModel.participantsToAdd.count) selected participants")
.default_text_style_300(styleSize: 12)
}
Spacer()
@ -72,12 +73,12 @@ struct AddParticipantsFragment: View {
ScrollView(.horizontal) {
HStack {
ForEach(0..<scheduleMeetingViewModel.participantsToAdd.count, id: \.self) { index in
ForEach(0..<addParticipantsViewModel.participantsToAdd.count, id: \.self) { index in
ZStack(alignment: .topTrailing) {
VStack {
Avatar(contactAvatarModel: scheduleMeetingViewModel.participantsToAdd[index].avatarModel, avatarSize: 50)
Avatar(contactAvatarModel: addParticipantsViewModel.participantsToAdd[index].avatarModel, avatarSize: 50)
Text(scheduleMeetingViewModel.participantsToAdd[index].avatarModel.name)
Text(addParticipantsViewModel.participantsToAdd[index].avatarModel.name)
.default_text_style(styleSize: 12)
.frame(minWidth: 60, maxWidth:80)
}
@ -87,7 +88,7 @@ struct AddParticipantsFragment: View {
.foregroundStyle(Color.grayMain2c500)
.frame(width: 25, height: 25)
.onTapGesture {
scheduleMeetingViewModel.participantsToAdd.remove(at: index)
addParticipantsViewModel.participantsToAdd.remove(at: index)
}
}
}
@ -96,12 +97,12 @@ struct AddParticipantsFragment: View {
.padding(.leading, 16)
ZStack(alignment: .trailing) {
TextField("Search contact", text: $scheduleMeetingViewModel.searchField)
TextField("Search contact", text: $addParticipantsViewModel.searchField)
.default_text_style(styleSize: 15)
.frame(height: 25)
.focused($isSearchFieldFocused)
.padding(.horizontal, 30)
.onChange(of: scheduleMeetingViewModel.searchField) { newValue in
.onChange(of: addParticipantsViewModel.searchField) { newValue in
magicSearch.currentFilterSuggestions = newValue
magicSearch.searchForSuggestions()
}.onAppear {
@ -120,9 +121,9 @@ struct AddParticipantsFragment: View {
Spacer()
if !scheduleMeetingViewModel.searchField.isEmpty {
if !addParticipantsViewModel.searchField.isEmpty {
Button(action: {
scheduleMeetingViewModel.searchField = ""
addParticipantsViewModel.searchField = ""
magicSearch.currentFilterSuggestions = ""
magicSearch.searchForSuggestions()
isSearchFieldFocused = false
@ -199,7 +200,7 @@ struct AddParticipantsFragment: View {
.background(.white)
.onTapGesture {
if let addr = contactsManager.lastSearch[index].address {
scheduleMeetingViewModel.selectParticipant(addr: addr)
addParticipantsViewModel.selectParticipant(addr: addr)
}
}
.buttonStyle(.borderless)
@ -220,7 +221,7 @@ struct AddParticipantsFragment: View {
}
Button {
withAnimation {
scheduleMeetingViewModel.addParticipants()
confirmAddParticipantsFunc(addParticipantsViewModel.participantsToAdd)
dismiss()
}
} label: {
@ -248,7 +249,7 @@ struct AddParticipantsFragment: View {
ForEach(0..<contactsManager.lastSearchSuggestions.count, id: \.self) { index in
Button {
if let addr = contactsManager.lastSearchSuggestions[index].address {
scheduleMeetingViewModel.selectParticipant(addr: addr)
addParticipantsViewModel.selectParticipant(addr: addr)
}
} label: {
HStack {
@ -288,5 +289,5 @@ struct AddParticipantsFragment: View {
}
#Preview {
AddParticipantsFragment(scheduleMeetingViewModel: ScheduleMeetingViewModel())
AddParticipantsFragment(addParticipantsViewModel: AddParticipantsViewModel(), confirmAddParticipantsFunc: {_ in } )
}

View file

@ -42,6 +42,8 @@ struct ScheduleMeetingFragment: View {
@State var selectedHours: Int = 0
@State var selectedMinutes: Int = 0
@State var addParticipantsViewModel = AddParticipantsViewModel()
var body: some View {
NavigationView {
ZStack(alignment: .bottomTrailing) {
@ -284,7 +286,10 @@ struct ScheduleMeetingFragment: View {
VStack {
NavigationLink(destination: {
AddParticipantsFragment(scheduleMeetingViewModel: scheduleMeetingViewModel)
AddParticipantsFragment(addParticipantsViewModel: addParticipantsViewModel, confirmAddParticipantsFunc: scheduleMeetingViewModel.addParticipants)
.onAppear {
addParticipantsViewModel.participantsToAdd = scheduleMeetingViewModel.participants
}
}, label: {
HStack(alignment: .center, spacing: 8) {
Image("users")
@ -300,6 +305,7 @@ struct ScheduleMeetingFragment: View {
Spacer()
}
})
if !scheduleMeetingViewModel.participants.isEmpty {
ScrollView {
ForEach(0..<scheduleMeetingViewModel.participants.count, id: \.self) { index in

View file

@ -21,16 +21,6 @@ import Foundation
import linphonesw
import Combine
class SelectedAddressModel: ObservableObject {
var address: Address
var avatarModel: ContactAvatarModel
init (addr: Address, avModel: ContactAvatarModel) {
address = addr
avatarModel = avModel
}
}
class ScheduleMeetingViewModel: ObservableObject {
static let TAG = "[ScheduleMeetingViewModel]"
@ -45,13 +35,10 @@ class ScheduleMeetingViewModel: ObservableObject {
@Published var toTime: String = ""
@Published var timezone: String = ""
@Published var sendInvitations: Bool = true
@Published var participantsToAdd: [SelectedAddressModel] = []
@Published var participants: [SelectedAddressModel] = []
@Published var operationInProgress: Bool = false
@Published var conferenceCreatedEvent: Bool = false
@Published var searchField: String = ""
var conferenceScheduler: ConferenceScheduler?
private var mSchedulerSubscriptions = Set<AnyCancellable?>()
var conferenceInfoToEdit: ConferenceInfo?
@ -75,11 +62,9 @@ class ScheduleMeetingViewModel: ObservableObject {
allDayMeeting = false
timezone = ""
sendInvitations = true
participantsToAdd = []
participants = []
operationInProgress = false
conferenceCreatedEvent = false
searchField = ""
fromDate = Calendar.current.date(byAdding: .hour, value: 1, to: Date.now)!
toDate = Calendar.current.date(byAdding: .hour, value: 2, to: Date.now)!
@ -113,14 +98,7 @@ class ScheduleMeetingViewModel: ObservableObject {
// TODO
}
func selectParticipant(addr: Address) {
if let idx = participantsToAdd.firstIndex(where: {$0.address.weakEqual(address2: addr)}) {
participantsToAdd.remove(at: idx)
} else {
participantsToAdd.append(SelectedAddressModel(addr: addr, avModel: ContactAvatarModel.getAvatarModelFromAddress(address: addr)))
}
}
func addParticipants() {
func addParticipants(participantsToAdd: [SelectedAddressModel]) {
var list = participants
for selectedAddr in participantsToAdd {
if let found = list.first(where: { $0.address.weakEqual(address2: selectedAddr.address) }) {
@ -134,7 +112,6 @@ class ScheduleMeetingViewModel: ObservableObject {
Log.info("\(ScheduleMeetingViewModel.TAG) [\(list.count - participants.count) participants added, now there are \(list.count) participants in list")
participants = list
participantsToAdd = []
}
private func fillConferenceInfo(confInfo: ConferenceInfo) {

View file

@ -0,0 +1,42 @@
//
// AddParticipantsViewModel.swift
// Linphone
//
// Created by QuentinArguillere on 29/04/2024.
//
import Foundation
import linphonesw
import Combine
class SelectedAddressModel: ObservableObject {
var address: Address
var avatarModel: ContactAvatarModel
init (addr: Address, avModel: ContactAvatarModel) {
address = addr
avatarModel = avModel
}
}
class AddParticipantsViewModel: ObservableObject {
static let TAG = "[AddParticipantsViewModel]"
@Published var participantsToAdd: [SelectedAddressModel] = []
@Published var searchField: String = ""
func selectParticipant(addr: Address) {
if let idx = participantsToAdd.firstIndex(where: {$0.address.weakEqual(address2: addr)}) {
Log.info("[\(AddParticipantsViewModel.TAG)] Removing participant \(addr.asStringUriOnly()) from selection")
participantsToAdd.remove(at: idx)
} else {
Log.info("[\(AddParticipantsViewModel.TAG)] Adding participant \(addr.asStringUriOnly()) to selection")
participantsToAdd.append(SelectedAddressModel(addr: addr, avModel: ContactAvatarModel.getAvatarModelFromAddress(address: addr)))
}
}
func reset() {
participantsToAdd = []
searchField = ""
}
}