mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-04-17 20:08:31 +00:00
Add contacts and suggestions to history and conversation views
This commit is contained in:
parent
9364e7f196
commit
6c5bf43062
10 changed files with 537 additions and 54 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public enum AppGitInfo {
|
public enum AppGitInfo {
|
||||||
public static let branch = "master"
|
public static let branch = "feature/contacts_and_suggestions_list"
|
||||||
public static let commit = "cdde88e32"
|
public static let commit = "c3f95fe23"
|
||||||
public static let tag = "6.1.0-alpha"
|
public static let tag = "6.1.0-alpha"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ struct ContentView: View {
|
||||||
@State private var searchIsActive = false
|
@State private var searchIsActive = false
|
||||||
@State private var text = ""
|
@State private var text = ""
|
||||||
@FocusState private var focusedField: Bool
|
@FocusState private var focusedField: Bool
|
||||||
|
|
||||||
@State private var showingDialer = false
|
@State private var showingDialer = false
|
||||||
@State var isMenuOpen = false
|
@State var isMenuOpen = false
|
||||||
@State var isShowDeleteContactPopup = false
|
@State var isShowDeleteContactPopup = false
|
||||||
|
|
@ -320,6 +321,8 @@ struct ContentView: View {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
|
resetFilter()
|
||||||
|
|
||||||
sharedMainViewModel.changeIndexView(indexViewInt: 0)
|
sharedMainViewModel.changeIndexView(indexViewInt: 0)
|
||||||
sharedMainViewModel.displayedCall = nil
|
sharedMainViewModel.displayedCall = nil
|
||||||
sharedMainViewModel.displayedConversation = nil
|
sharedMainViewModel.displayedConversation = nil
|
||||||
|
|
@ -341,7 +344,8 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.padding(.top)
|
.padding(.top)
|
||||||
.frame(height: geometry.size.height/4)
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
ZStack {
|
ZStack {
|
||||||
if SharedMainViewModel.shared.missedCallsCount > 0 {
|
if SharedMainViewModel.shared.missedCallsCount > 0 {
|
||||||
|
|
@ -365,6 +369,8 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
|
resetFilter()
|
||||||
|
|
||||||
sharedMainViewModel.changeIndexView(indexViewInt: 1)
|
sharedMainViewModel.changeIndexView(indexViewInt: 1)
|
||||||
sharedMainViewModel.displayedFriend = nil
|
sharedMainViewModel.displayedFriend = nil
|
||||||
sharedMainViewModel.displayedConversation = nil
|
sharedMainViewModel.displayedConversation = nil
|
||||||
|
|
@ -390,7 +396,8 @@ struct ContentView: View {
|
||||||
})
|
})
|
||||||
.padding(.top)
|
.padding(.top)
|
||||||
}
|
}
|
||||||
.frame(height: geometry.size.height/4)
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
if !sharedMainViewModel.disableChatFeature {
|
if !sharedMainViewModel.disableChatFeature {
|
||||||
ZStack {
|
ZStack {
|
||||||
|
|
@ -415,6 +422,8 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
|
resetFilter()
|
||||||
|
|
||||||
sharedMainViewModel.changeIndexView(indexViewInt: 2)
|
sharedMainViewModel.changeIndexView(indexViewInt: 2)
|
||||||
sharedMainViewModel.displayedFriend = nil
|
sharedMainViewModel.displayedFriend = nil
|
||||||
sharedMainViewModel.displayedCall = nil
|
sharedMainViewModel.displayedCall = nil
|
||||||
|
|
@ -438,11 +447,14 @@ struct ContentView: View {
|
||||||
})
|
})
|
||||||
.padding(.top)
|
.padding(.top)
|
||||||
}
|
}
|
||||||
.frame(height: geometry.size.height/4)
|
|
||||||
|
Spacer()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !sharedMainViewModel.disableMeetingFeature {
|
if !sharedMainViewModel.disableMeetingFeature {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
|
resetFilter()
|
||||||
|
|
||||||
sharedMainViewModel.changeIndexView(indexViewInt: 3)
|
sharedMainViewModel.changeIndexView(indexViewInt: 3)
|
||||||
sharedMainViewModel.displayedFriend = nil
|
sharedMainViewModel.displayedFriend = nil
|
||||||
sharedMainViewModel.displayedCall = nil
|
sharedMainViewModel.displayedCall = nil
|
||||||
|
|
@ -464,13 +476,13 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.padding(.top)
|
.padding(.top)
|
||||||
.frame(height: geometry.size.height/4)
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(width: 75, height: geometry.size.height)
|
.frame(width: 75, height: geometry.size.height)
|
||||||
|
.padding(.bottom, geometry.safeAreaInsets.bottom)
|
||||||
.padding(.leading,
|
.padding(.leading,
|
||||||
orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0
|
orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0
|
||||||
? -geometry.safeAreaInsets.leading
|
? -geometry.safeAreaInsets.leading
|
||||||
|
|
@ -690,10 +702,12 @@ struct ContentView: View {
|
||||||
|
|
||||||
text = ""
|
text = ""
|
||||||
|
|
||||||
if sharedMainViewModel.indexView == 0 {
|
if sharedMainViewModel.indexView != 3 {
|
||||||
magicSearch.currentFilter = ""
|
magicSearch.currentFilter = ""
|
||||||
magicSearch.searchForContacts()
|
magicSearch.searchForContacts()
|
||||||
} else if let historyListVM = historyListViewModel, sharedMainViewModel.indexView == 1 {
|
}
|
||||||
|
|
||||||
|
if let historyListVM = historyListViewModel, sharedMainViewModel.indexView == 1 {
|
||||||
historyListVM.resetFilterCallLogs()
|
historyListVM.resetFilterCallLogs()
|
||||||
} else if let conversationsListVM = conversationsListViewModel, sharedMainViewModel.indexView == 2 {
|
} else if let conversationsListVM = conversationsListViewModel, sharedMainViewModel.indexView == 2 {
|
||||||
conversationsListVM.resetFilterConversations()
|
conversationsListVM.resetFilterConversations()
|
||||||
|
|
@ -735,10 +749,12 @@ struct ContentView: View {
|
||||||
self.focusedField = true
|
self.focusedField = true
|
||||||
}
|
}
|
||||||
.onChange(of: text) { newValue in
|
.onChange(of: text) { newValue in
|
||||||
if sharedMainViewModel.indexView == 0 {
|
if sharedMainViewModel.indexView != 3 {
|
||||||
magicSearch.currentFilter = newValue
|
magicSearch.currentFilter = newValue
|
||||||
magicSearch.searchForContacts()
|
magicSearch.searchForContacts()
|
||||||
} else if let historyListVM = historyListViewModel, sharedMainViewModel.indexView == 1 {
|
}
|
||||||
|
|
||||||
|
if let historyListVM = historyListViewModel, sharedMainViewModel.indexView == 1 {
|
||||||
if text.isEmpty {
|
if text.isEmpty {
|
||||||
historyListVM.resetFilterCallLogs()
|
historyListVM.resetFilterCallLogs()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -755,6 +771,34 @@ struct ContentView: View {
|
||||||
meetingsListVM.computeMeetingsList()
|
meetingsListVM.computeMeetingsList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.onChange(of: isShowStartCallFragment) { isShowStartCallFragmentNewValue in
|
||||||
|
if isShowStartCallFragmentNewValue == false && !text.isEmpty {
|
||||||
|
if let historyListVM = historyListViewModel, sharedMainViewModel.indexView == 1 {
|
||||||
|
magicSearch.currentFilter = text
|
||||||
|
magicSearch.searchForContacts()
|
||||||
|
|
||||||
|
if text.isEmpty {
|
||||||
|
historyListVM.resetFilterCallLogs()
|
||||||
|
} else {
|
||||||
|
historyListVM.filterCallLogs(filter: text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onChange(of: isShowStartConversationFragment) { isShowStartConversationFragmentNewValue in
|
||||||
|
if isShowStartConversationFragmentNewValue == false && !text.isEmpty {
|
||||||
|
if let conversationsListVM = conversationsListViewModel, sharedMainViewModel.indexView == 2 {
|
||||||
|
magicSearch.currentFilter = text
|
||||||
|
magicSearch.searchForContacts()
|
||||||
|
|
||||||
|
if text.isEmpty {
|
||||||
|
conversationsListVM.resetFilterConversations()
|
||||||
|
} else {
|
||||||
|
conversationsListVM.filterConversations(filter: text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
TextEditor(text: Binding(
|
TextEditor(text: Binding(
|
||||||
get: {
|
get: {
|
||||||
|
|
@ -777,18 +821,56 @@ struct ContentView: View {
|
||||||
self.focusedField = true
|
self.focusedField = true
|
||||||
}
|
}
|
||||||
.onChange(of: text) { newValue in
|
.onChange(of: text) { newValue in
|
||||||
if sharedMainViewModel.indexView == 0 {
|
if sharedMainViewModel.indexView != 3 {
|
||||||
magicSearch.currentFilter = newValue
|
magicSearch.currentFilter = newValue
|
||||||
magicSearch.searchForContacts()
|
magicSearch.searchForContacts()
|
||||||
} else if let historyListVM = historyListViewModel, sharedMainViewModel.indexView == 1 {
|
}
|
||||||
historyListVM.filterCallLogs(filter: text)
|
|
||||||
|
if let historyListVM = historyListViewModel, sharedMainViewModel.indexView == 1 {
|
||||||
|
if text.isEmpty {
|
||||||
|
historyListVM.resetFilterCallLogs()
|
||||||
|
} else {
|
||||||
|
historyListVM.filterCallLogs(filter: text)
|
||||||
|
}
|
||||||
} else if let conversationsListVM = conversationsListViewModel, sharedMainViewModel.indexView == 2 {
|
} else if let conversationsListVM = conversationsListViewModel, sharedMainViewModel.indexView == 2 {
|
||||||
conversationsListVM.filterConversations(filter: text)
|
if text.isEmpty {
|
||||||
|
conversationsListVM.resetFilterConversations()
|
||||||
|
} else {
|
||||||
|
conversationsListVM.filterConversations(filter: text)
|
||||||
|
}
|
||||||
} else if let meetingsListVM = meetingsListViewModel, sharedMainViewModel.indexView == 3 {
|
} else if let meetingsListVM = meetingsListViewModel, sharedMainViewModel.indexView == 3 {
|
||||||
meetingsListVM.currentFilter = text
|
meetingsListVM.currentFilter = text
|
||||||
meetingsListVM.computeMeetingsList()
|
meetingsListVM.computeMeetingsList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.onChange(of: isShowStartCallFragment) { isShowStartCallFragmentNewValue in
|
||||||
|
if isShowStartCallFragmentNewValue == false && !text.isEmpty {
|
||||||
|
if let historyListVM = historyListViewModel, sharedMainViewModel.indexView == 1 {
|
||||||
|
magicSearch.currentFilter = text
|
||||||
|
magicSearch.searchForContacts()
|
||||||
|
|
||||||
|
if text.isEmpty {
|
||||||
|
historyListVM.resetFilterCallLogs()
|
||||||
|
} else {
|
||||||
|
historyListVM.filterCallLogs(filter: text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onChange(of: isShowStartConversationFragment) { isShowStartConversationFragmentNewValue in
|
||||||
|
if isShowStartConversationFragmentNewValue == false && !text.isEmpty {
|
||||||
|
if let conversationsListVM = conversationsListViewModel, sharedMainViewModel.indexView == 2 {
|
||||||
|
magicSearch.currentFilter = text
|
||||||
|
magicSearch.searchForContacts()
|
||||||
|
|
||||||
|
if text.isEmpty {
|
||||||
|
conversationsListVM.resetFilterConversations()
|
||||||
|
} else {
|
||||||
|
conversationsListVM.filterConversations(filter: text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
|
@ -874,6 +956,8 @@ struct ContentView: View {
|
||||||
Group {
|
Group {
|
||||||
Spacer()
|
Spacer()
|
||||||
Button(action: {
|
Button(action: {
|
||||||
|
resetFilter()
|
||||||
|
|
||||||
sharedMainViewModel.changeIndexView(indexViewInt: 0)
|
sharedMainViewModel.changeIndexView(indexViewInt: 0)
|
||||||
sharedMainViewModel.displayedCall = nil
|
sharedMainViewModel.displayedCall = nil
|
||||||
sharedMainViewModel.displayedConversation = nil
|
sharedMainViewModel.displayedConversation = nil
|
||||||
|
|
@ -921,6 +1005,8 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
|
resetFilter()
|
||||||
|
|
||||||
sharedMainViewModel.changeIndexView(indexViewInt: 1)
|
sharedMainViewModel.changeIndexView(indexViewInt: 1)
|
||||||
sharedMainViewModel.displayedFriend = nil
|
sharedMainViewModel.displayedFriend = nil
|
||||||
sharedMainViewModel.displayedConversation = nil
|
sharedMainViewModel.displayedConversation = nil
|
||||||
|
|
@ -973,6 +1059,8 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
|
resetFilter()
|
||||||
|
|
||||||
sharedMainViewModel.changeIndexView(indexViewInt: 2)
|
sharedMainViewModel.changeIndexView(indexViewInt: 2)
|
||||||
sharedMainViewModel.displayedFriend = nil
|
sharedMainViewModel.displayedFriend = nil
|
||||||
sharedMainViewModel.displayedCall = nil
|
sharedMainViewModel.displayedCall = nil
|
||||||
|
|
@ -1002,6 +1090,8 @@ struct ContentView: View {
|
||||||
if !sharedMainViewModel.disableMeetingFeature {
|
if !sharedMainViewModel.disableMeetingFeature {
|
||||||
Spacer()
|
Spacer()
|
||||||
Button(action: {
|
Button(action: {
|
||||||
|
resetFilter()
|
||||||
|
|
||||||
sharedMainViewModel.changeIndexView(indexViewInt: 3)
|
sharedMainViewModel.changeIndexView(indexViewInt: 3)
|
||||||
sharedMainViewModel.displayedFriend = nil
|
sharedMainViewModel.displayedFriend = nil
|
||||||
sharedMainViewModel.displayedCall = nil
|
sharedMainViewModel.displayedCall = nil
|
||||||
|
|
@ -1299,13 +1389,17 @@ struct ContentView: View {
|
||||||
|
|
||||||
if sharedMainViewModel.operationInProgress {
|
if sharedMainViewModel.operationInProgress {
|
||||||
PopupLoadingView()
|
PopupLoadingView()
|
||||||
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
|
.padding(.bottom, UIDevice.current.userInterfaceIdiom == .pad && (orientation == .landscapeLeft || orientation == .landscapeRight || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) ? geometry.safeAreaInsets.bottom : 0)
|
||||||
.background(.black.opacity(0.65))
|
.background(.black.opacity(0.65))
|
||||||
.zIndex(3)
|
.zIndex(3)
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
if let contactsListVM = contactsListViewModel, let displayedConversation = contactsListVM.displayedConversation {
|
if let contactsListVM = contactsListViewModel, let displayedConversation = contactsListVM.displayedConversation {
|
||||||
|
|
||||||
if !sharedMainViewModel.disableChatFeature {
|
if !sharedMainViewModel.disableChatFeature {
|
||||||
sharedMainViewModel.displayedFriend = nil
|
resetFilter()
|
||||||
|
|
||||||
|
sharedMainViewModel.displayedFriend = nil
|
||||||
sharedMainViewModel.displayedCall = nil
|
sharedMainViewModel.displayedCall = nil
|
||||||
sharedMainViewModel.changeIndexView(indexViewInt: 2)
|
sharedMainViewModel.changeIndexView(indexViewInt: 2)
|
||||||
|
|
||||||
|
|
@ -1330,6 +1424,8 @@ struct ContentView: View {
|
||||||
} else if let historyListVM = historyListViewModel, let displayedConversation = historyListVM.displayedConversation {
|
} else if let historyListVM = historyListViewModel, let displayedConversation = historyListVM.displayedConversation {
|
||||||
|
|
||||||
if !sharedMainViewModel.disableChatFeature {
|
if !sharedMainViewModel.disableChatFeature {
|
||||||
|
resetFilter()
|
||||||
|
|
||||||
sharedMainViewModel.displayedFriend = nil
|
sharedMainViewModel.displayedFriend = nil
|
||||||
sharedMainViewModel.displayedCall = nil
|
sharedMainViewModel.displayedCall = nil
|
||||||
sharedMainViewModel.changeIndexView(indexViewInt: 2)
|
sharedMainViewModel.changeIndexView(indexViewInt: 2)
|
||||||
|
|
@ -1352,6 +1448,15 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if let conversationsListVM = conversationsListViewModel {
|
||||||
|
conversationsListVM.currentFilter = ""
|
||||||
|
|
||||||
|
self.resetFilter()
|
||||||
|
|
||||||
|
if let displayedConversation = conversationsListVM.displayedConversation {
|
||||||
|
conversationsListVM.changeDisplayedChatRoom(conversationModel: displayedConversation)
|
||||||
|
conversationsListVM.displayedConversation = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1404,7 +1509,7 @@ struct ContentView: View {
|
||||||
.transition(.move(edge: .trailing))
|
.transition(.move(edge: .trailing))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let meetingsListVM = meetingsListViewModel, isShowSendCancelMeetingNotificationPopup {
|
if let meetingsListVM = meetingsListViewModel, isShowSendCancelMeetingNotificationPopup {
|
||||||
PopupView(
|
PopupView(
|
||||||
isShowPopup: $isShowSendCancelMeetingNotificationPopup,
|
isShowPopup: $isShowSendCancelMeetingNotificationPopup,
|
||||||
title: Text("meeting_schedule_cancel_dialog_title"),
|
title: Text("meeting_schedule_cancel_dialog_title"),
|
||||||
|
|
@ -1668,6 +1773,7 @@ struct ContentView: View {
|
||||||
.onChange(of: navigationManager.selectedCallId) { newCallId in
|
.onChange(of: navigationManager.selectedCallId) { newCallId in
|
||||||
if newCallId != nil {
|
if newCallId != nil {
|
||||||
if !sharedMainViewModel.disableChatFeature {
|
if !sharedMainViewModel.disableChatFeature {
|
||||||
|
resetFilter()
|
||||||
sharedMainViewModel.changeIndexView(indexViewInt: 2)
|
sharedMainViewModel.changeIndexView(indexViewInt: 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1760,6 +1866,17 @@ struct ContentView: View {
|
||||||
self.sideMenuIsOpen.toggle()
|
self.sideMenuIsOpen.toggle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resetFilter() {
|
||||||
|
self.text = ""
|
||||||
|
self.focusedField = false
|
||||||
|
self.searchIsActive = false
|
||||||
|
|
||||||
|
if !magicSearch.currentFilter.isEmpty {
|
||||||
|
magicSearch.currentFilter = ""
|
||||||
|
magicSearch.searchForContacts()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ContactsContainer: View {
|
struct ContactsContainer: View {
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ struct ConversationsView: View {
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
ConversationsListFragment(
|
ConversationsListFragment(
|
||||||
showingSheet: .constant(false),
|
text: .constant(""),
|
||||||
text: .constant("")
|
showingSheet: .constant(false)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,14 @@ struct ConversationsFragment: View {
|
||||||
|
|
||||||
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
|
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
|
||||||
|
|
||||||
@State var showingSheet: Bool = false
|
|
||||||
@Binding var text: String
|
@Binding var text: String
|
||||||
|
|
||||||
|
@State var showingSheet: Bool = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
if #available(iOS 16.0, *), idiom != .pad {
|
if #available(iOS 16.0, *), idiom != .pad {
|
||||||
ConversationsListFragment(showingSheet: $showingSheet, text: $text)
|
ConversationsListFragment(text: $text, showingSheet: $showingSheet)
|
||||||
.sheet(isPresented: $showingSheet) {
|
.sheet(isPresented: $showingSheet) {
|
||||||
ConversationsListBottomSheet(
|
ConversationsListBottomSheet(
|
||||||
showingSheet: $showingSheet
|
showingSheet: $showingSheet
|
||||||
|
|
@ -43,7 +44,7 @@ struct ConversationsFragment: View {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ConversationsListFragment(showingSheet: $showingSheet, text: $text)
|
ConversationsListFragment(text: $text, showingSheet: $showingSheet)
|
||||||
.halfSheet(showSheet: $showingSheet) {
|
.halfSheet(showSheet: $showingSheet) {
|
||||||
ConversationsListBottomSheet(
|
ConversationsListBottomSheet(
|
||||||
showingSheet: $showingSheet
|
showingSheet: $showingSheet
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,12 @@ struct ConversationsListFragment: View {
|
||||||
|
|
||||||
@EnvironmentObject var navigationManager: NavigationManager
|
@EnvironmentObject var navigationManager: NavigationManager
|
||||||
|
|
||||||
|
@ObservedObject var contactsManager = ContactsManager.shared
|
||||||
|
|
||||||
@EnvironmentObject var conversationsListViewModel: ConversationsListViewModel
|
@EnvironmentObject var conversationsListViewModel: ConversationsListViewModel
|
||||||
|
|
||||||
@Binding var showingSheet: Bool
|
|
||||||
@Binding var text: String
|
@Binding var text: String
|
||||||
|
@Binding var showingSheet: Bool
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
|
|
@ -42,6 +44,34 @@ struct ConversationsListFragment: View {
|
||||||
text: $text
|
text: $text
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !conversationsListViewModel.currentFilter.isEmpty {
|
||||||
|
if !contactsManager.lastSearch.isEmpty {
|
||||||
|
HStack(alignment: .center) {
|
||||||
|
Text("contacts_list_all_contacts_title")
|
||||||
|
.default_text_style_800(styleSize: 16)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContactsListFragment(showingSheet: .constant(false), startCallFunc: { addr in
|
||||||
|
withAnimation {
|
||||||
|
conversationsListViewModel.createOneToOneChatRoomWith(remote: addr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if !contactsManager.lastSearchSuggestions.isEmpty {
|
||||||
|
HStack(alignment: .center) {
|
||||||
|
Text("generic_address_picker_suggestions_list_title")
|
||||||
|
.default_text_style_800(styleSize: 16)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
suggestionsList
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.safeAreaInset(edge: .top, content: {
|
.safeAreaInset(edge: .top, content: {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
@ -50,7 +80,13 @@ struct ConversationsListFragment: View {
|
||||||
.listStyle(.plain)
|
.listStyle(.plain)
|
||||||
.overlay(
|
.overlay(
|
||||||
VStack {
|
VStack {
|
||||||
if conversationsListViewModel.conversationsList.isEmpty {
|
if conversationsListViewModel.conversationsList.isEmpty &&
|
||||||
|
(
|
||||||
|
conversationsListViewModel.currentFilter.isEmpty ||
|
||||||
|
(!conversationsListViewModel.currentFilter.isEmpty &&
|
||||||
|
contactsManager.lastSearch.isEmpty &&
|
||||||
|
contactsManager.lastSearchSuggestions.isEmpty)
|
||||||
|
) {
|
||||||
Spacer()
|
Spacer()
|
||||||
Image("illus-belledonne")
|
Image("illus-belledonne")
|
||||||
.resizable()
|
.resizable()
|
||||||
|
|
@ -65,6 +101,11 @@ struct ConversationsListFragment: View {
|
||||||
}
|
}
|
||||||
.padding(.all)
|
.padding(.all)
|
||||||
)
|
)
|
||||||
|
.onDisappear {
|
||||||
|
if !conversationsListViewModel.currentFilter.isEmpty {
|
||||||
|
conversationsListViewModel.resetFilterConversations()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle("")
|
.navigationTitle("")
|
||||||
.navigationBarHidden(true)
|
.navigationBarHidden(true)
|
||||||
|
|
@ -77,6 +118,69 @@ struct ConversationsListFragment: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var suggestionsList: some View {
|
||||||
|
ForEach(0..<contactsManager.lastSearchSuggestions.count, id: \.self) { index in
|
||||||
|
Button {
|
||||||
|
if let address = contactsManager.lastSearchSuggestions[index].address {
|
||||||
|
withAnimation {
|
||||||
|
conversationsListViewModel.createOneToOneChatRoomWith(remote: address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
HStack {
|
||||||
|
if index < contactsManager.lastSearchSuggestions.count
|
||||||
|
&& contactsManager.lastSearchSuggestions[index].address != nil {
|
||||||
|
if contactsManager.lastSearchSuggestions[index].address!.domain != AppServices.corePreferences.defaultDomain {
|
||||||
|
Image(uiImage: contactsManager.textToImage(
|
||||||
|
firstName: String(contactsManager.lastSearchSuggestions[index].address!.asStringUriOnly().dropFirst(4)),
|
||||||
|
lastName: ""))
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 45, height: 45)
|
||||||
|
.clipShape(Circle())
|
||||||
|
|
||||||
|
Text(String(contactsManager.lastSearchSuggestions[index].address!.asStringUriOnly().dropFirst(4)))
|
||||||
|
.default_text_style(styleSize: 16)
|
||||||
|
.lineLimit(1)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.foregroundStyle(Color.orangeMain500)
|
||||||
|
} else {
|
||||||
|
if let address = contactsManager.lastSearchSuggestions[index].address {
|
||||||
|
let nameTmp = address.displayName
|
||||||
|
?? address.username
|
||||||
|
?? String(address.asStringUriOnly().dropFirst(4))
|
||||||
|
|
||||||
|
Image(uiImage: contactsManager.textToImage(
|
||||||
|
firstName: nameTmp,
|
||||||
|
lastName: ""))
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 45, height: 45)
|
||||||
|
.clipShape(Circle())
|
||||||
|
|
||||||
|
Text(nameTmp)
|
||||||
|
.default_text_style(styleSize: 16)
|
||||||
|
.lineLimit(1)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.foregroundStyle(Color.orangeMain500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Image("profil-picture-default")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 45, height: 45)
|
||||||
|
.clipShape(Circle())
|
||||||
|
|
||||||
|
Text("username_error")
|
||||||
|
.default_text_style(styleSize: 16)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.foregroundStyle(Color.orangeMain500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.buttonStyle(.borderless)
|
||||||
|
.listRowSeparator(.hidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ConversationRow: View {
|
struct ConversationRow: View {
|
||||||
|
|
@ -244,7 +348,7 @@ struct ConversationRow: View {
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
ConversationsListFragment(
|
ConversationsListFragment(
|
||||||
showingSheet: .constant(false),
|
text: .constant(""),
|
||||||
text: .constant("")
|
showingSheet: .constant(false)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,13 @@ class ConversationsListViewModel: ObservableObject {
|
||||||
|
|
||||||
private var coreConversationDelegate: CoreDelegate?
|
private var coreConversationDelegate: CoreDelegate?
|
||||||
|
|
||||||
|
@Published var currentFilter: String = ""
|
||||||
|
@Published var displayedConversation: ConversationModel?
|
||||||
@Published var conversationsList: [ConversationModel] = []
|
@Published var conversationsList: [ConversationModel] = []
|
||||||
|
|
||||||
var selectedConversation: ConversationModel?
|
var selectedConversation: ConversationModel?
|
||||||
|
|
||||||
var currentFilter: String = ""
|
private var chatRoomDelegate: ChatRoomDelegate?
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
computeChatRoomsList()
|
computeChatRoomsList()
|
||||||
|
|
@ -428,6 +430,7 @@ class ConversationsListViewModel: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
func resetFilterConversations() {
|
func resetFilterConversations() {
|
||||||
|
currentFilter = ""
|
||||||
filterConversations(filter: "")
|
filterConversations(filter: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -479,5 +482,163 @@ class ConversationsListViewModel: ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createOneToOneChatRoomWith(remote: Address) {
|
||||||
|
CoreContext.shared.doOnCoreQueue { core in
|
||||||
|
let account = core.defaultAccount
|
||||||
|
if account == nil {
|
||||||
|
Log.error(
|
||||||
|
"\(ConversationsListViewModel.TAG) No default account found, can't create conversation with \(remote.asStringUriOnly())"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.sharedMainViewModel.operationInProgress = true
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
let params = try core.createConferenceParams(conference: nil)
|
||||||
|
params.chatEnabled = true
|
||||||
|
params.groupEnabled = false
|
||||||
|
params.subject = NSLocalizedString("conversation_one_to_one_hidden_subject", comment: "")
|
||||||
|
params.account = account
|
||||||
|
|
||||||
|
guard let chatParams = params.chatParams else { return }
|
||||||
|
chatParams.ephemeralLifetime = 0 // Make sure ephemeral is disabled by default
|
||||||
|
|
||||||
|
let sameDomain = remote.domain == AppServices.corePreferences.defaultDomain && remote.domain == account!.params?.domain
|
||||||
|
if account!.params != nil && (account!.params!.instantMessagingEncryptionMandatory && sameDomain) {
|
||||||
|
Log.info("\(ConversationsListViewModel.TAG) Account is in secure mode & domain matches, creating an E2E encrypted conversation")
|
||||||
|
chatParams.backend = ChatRoom.Backend.FlexisipChat
|
||||||
|
params.securityLevel = Conference.SecurityLevel.EndToEnd
|
||||||
|
} else if account!.params != nil && (!account!.params!.instantMessagingEncryptionMandatory) {
|
||||||
|
if LinphoneUtils.isEndToEndEncryptedChatAvailable(core: core) {
|
||||||
|
Log.info(
|
||||||
|
"\(ConversationsListViewModel.TAG) Account is in interop mode but LIME is available, creating an E2E encrypted conversation"
|
||||||
|
)
|
||||||
|
chatParams.backend = ChatRoom.Backend.FlexisipChat
|
||||||
|
params.securityLevel = Conference.SecurityLevel.EndToEnd
|
||||||
|
} else {
|
||||||
|
Log.info(
|
||||||
|
"\(ConversationsListViewModel.TAG) Account is in interop mode but LIME isn't available, creating a SIP simple conversation"
|
||||||
|
)
|
||||||
|
chatParams.backend = ChatRoom.Backend.Basic
|
||||||
|
params.securityLevel = Conference.SecurityLevel.None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.error(
|
||||||
|
"\(ConversationsListViewModel.TAG) Account is in secure mode, can't chat with SIP address of different domain \(remote.asStringUriOnly())"
|
||||||
|
)
|
||||||
|
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
|
self.sharedMainViewModel.operationInProgress = false
|
||||||
|
ToastViewModel.shared.show("Failed_to_create_conversation_error")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let participants = [remote]
|
||||||
|
let localAddress = account?.params?.identityAddress
|
||||||
|
let existingChatRoom = core.searchChatRoom(params: params, localAddr: localAddress, remoteAddr: nil, participants: participants)
|
||||||
|
if existingChatRoom == nil {
|
||||||
|
Log.info(
|
||||||
|
"\(ConversationsListViewModel.TAG) No existing 1-1 conversation between local account \(localAddress?.asStringUriOnly() ?? "") and remote \(remote.asStringUriOnly()) was found for given parameters, let's create it"
|
||||||
|
)
|
||||||
|
|
||||||
|
do {
|
||||||
|
let chatRoom = try core.createChatRoom(params: params, participants: participants)
|
||||||
|
if chatParams.backend == ChatRoom.Backend.FlexisipChat {
|
||||||
|
let state = chatRoom.state
|
||||||
|
if state == ChatRoom.State.Created {
|
||||||
|
let chatRoomId = LinphoneUtils.getConversationId(chatRoom: chatRoom)
|
||||||
|
Log.info("\(ConversationsListViewModel.TAG) 1-1 conversation \(chatRoomId) has been created")
|
||||||
|
|
||||||
|
let model = ConversationModel(chatRoom: chatRoom)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
|
self.displayedConversation = model
|
||||||
|
self.sharedMainViewModel.operationInProgress = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.info("\(ConversationsListViewModel.TAG) Conversation isn't in Created state yet (state is \(state)), wait for it")
|
||||||
|
self.chatRoomAddDelegate(core: core, chatRoom: chatRoom)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let chatRoomId = LinphoneUtils.getConversationId(chatRoom: chatRoom)
|
||||||
|
Log.info("\(ConversationsListViewModel.TAG) Conversation successfully created \(chatRoomId)")
|
||||||
|
|
||||||
|
let model = ConversationModel(chatRoom: chatRoom)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
|
self.displayedConversation = model
|
||||||
|
self.sharedMainViewModel.operationInProgress = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Log.error("\(ConversationsListViewModel.TAG) Failed to create 1-1 conversation with \(remote.asStringUriOnly())")
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
|
self.sharedMainViewModel.operationInProgress = false
|
||||||
|
ToastViewModel.shared.show("Failed_to_create_conversation_error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.warn(
|
||||||
|
"\(ConversationsListViewModel.TAG) A 1-1 conversation between local account \(localAddress?.asStringUriOnly() ?? "") and remote \(remote.asStringUriOnly()) for given parameters already exists!"
|
||||||
|
)
|
||||||
|
let model = ConversationModel(chatRoom: existingChatRoom!)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
|
self.displayedConversation = model
|
||||||
|
self.sharedMainViewModel.operationInProgress = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func chatRoomAddDelegate(core: Core, chatRoom: ChatRoom) {
|
||||||
|
self.chatRoomDelegate = ChatRoomDelegateStub(onStateChanged: { (chatRoom: ChatRoom, state: ChatRoom.State) in
|
||||||
|
let state = chatRoom.state
|
||||||
|
let chatRoomId = LinphoneUtils.getChatRoomId(room: chatRoom)
|
||||||
|
if state == ChatRoom.State.CreationFailed {
|
||||||
|
Log.error("\(StartConversationViewModel.TAG) Conversation \(chatRoomId) creation has failed!")
|
||||||
|
if let chatRoomDelegate = self.chatRoomDelegate {
|
||||||
|
chatRoom.removeDelegate(delegate: chatRoomDelegate)
|
||||||
|
}
|
||||||
|
self.chatRoomDelegate = nil
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.sharedMainViewModel.operationInProgress = false
|
||||||
|
ToastViewModel.shared.show("Failed_to_create_conversation_error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, onConferenceJoined: { (chatRoom: ChatRoom, _: EventLog) in
|
||||||
|
let state = chatRoom.state
|
||||||
|
let id = LinphoneUtils.getChatRoomId(room: chatRoom)
|
||||||
|
Log.info("\(StartConversationViewModel.TAG) Conversation \(id) \(chatRoom.subject ?? "") state changed: \(state)")
|
||||||
|
if state == ChatRoom.State.Created {
|
||||||
|
Log.info("\(StartConversationViewModel.TAG) Conversation \(id) successfully created")
|
||||||
|
if let chatRoomDelegate = self.chatRoomDelegate {
|
||||||
|
chatRoom.removeDelegate(delegate: chatRoomDelegate)
|
||||||
|
}
|
||||||
|
self.chatRoomDelegate = nil
|
||||||
|
|
||||||
|
let model = ConversationModel(chatRoom: chatRoom)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.displayedConversation = model
|
||||||
|
self.sharedMainViewModel.operationInProgress = false
|
||||||
|
}
|
||||||
|
} else if state == ChatRoom.State.CreationFailed {
|
||||||
|
Log.error("\(StartConversationViewModel.TAG) Conversation \(id) creation has failed!")
|
||||||
|
if let chatRoomDelegate = self.chatRoomDelegate {
|
||||||
|
chatRoom.removeDelegate(delegate: chatRoomDelegate)
|
||||||
|
}
|
||||||
|
self.chatRoomDelegate = nil
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.sharedMainViewModel.operationInProgress = false
|
||||||
|
ToastViewModel.shared.show("Failed_to_create_conversation_error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
chatRoom.addDelegate(delegate: self.chatRoomDelegate!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// swiftlint:enable line_length
|
// swiftlint:enable line_length
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,11 @@ class StartConversationViewModel: ObservableObject {
|
||||||
|
|
||||||
@Published var participants: [SelectedAddressModel] = []
|
@Published var participants: [SelectedAddressModel] = []
|
||||||
|
|
||||||
@Published var operationOneToOneInProgress: Bool = false
|
@Published var hideGroupChatButton: Bool = false
|
||||||
@Published var operationGroupInProgress: Bool = false
|
@Published var operationGroupInProgress: Bool = false
|
||||||
|
@Published var operationOneToOneInProgress: Bool = false
|
||||||
@Published var displayedConversation: ConversationModel?
|
@Published var displayedConversation: ConversationModel?
|
||||||
|
|
||||||
@Published var hideGroupChatButton: Bool = false
|
|
||||||
|
|
||||||
private var chatRoomDelegate: ChatRoomDelegate?
|
private var chatRoomDelegate: ChatRoomDelegate?
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,32 +22,26 @@ import SwiftUI
|
||||||
struct PopupLoadingView: View {
|
struct PopupLoadingView: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
GeometryReader { geometry in
|
VStack {
|
||||||
VStack(alignment: .leading) {
|
ProgressView()
|
||||||
|
.controlSize(.large)
|
||||||
ProgressView()
|
.progressViewStyle(CircularProgressViewStyle(tint: Color.orangeMain500))
|
||||||
.controlSize(.large)
|
.frame(maxWidth: .infinity)
|
||||||
.progressViewStyle(CircularProgressViewStyle(tint: Color.orangeMain500))
|
.padding(.top)
|
||||||
.frame(maxWidth: .infinity)
|
.padding(.bottom)
|
||||||
.padding(.top)
|
|
||||||
.padding(.bottom)
|
Text("operation_in_progress_overlay")
|
||||||
|
.tint(Color.grayMain2c600)
|
||||||
Text("operation_in_progress_overlay")
|
.default_text_style(styleSize: 15)
|
||||||
.tint(Color.grayMain2c600)
|
.frame(maxWidth: .infinity)
|
||||||
.default_text_style(styleSize: 15)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
}
|
|
||||||
.padding(.horizontal, 20)
|
|
||||||
.padding(.vertical, 20)
|
|
||||||
.background(.white)
|
|
||||||
.cornerRadius(20)
|
|
||||||
.padding(.horizontal)
|
|
||||||
.frame(maxHeight: .infinity)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.shadow(color: Color.orangeMain500, radius: 0, x: 0, y: 2)
|
|
||||||
.frame(maxWidth: SharedMainViewModel.shared.maxWidth)
|
|
||||||
.position(x: geometry.size.width / 2, y: geometry.size.height / 2)
|
|
||||||
}
|
}
|
||||||
|
.padding(.horizontal, 20)
|
||||||
|
.padding(.vertical, 20)
|
||||||
|
.background(.white)
|
||||||
|
.cornerRadius(20)
|
||||||
|
.padding(.horizontal)
|
||||||
|
.shadow(color: Color.orangeMain500, radius: 0, x: 0, y: 2)
|
||||||
|
.frame(maxWidth: SharedMainViewModel.shared.maxWidth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,34 @@ struct HistoryListFragment: View {
|
||||||
ForEach(historyListViewModel.callLogs) { historyModel in
|
ForEach(historyListViewModel.callLogs) { historyModel in
|
||||||
HistoryRow(historyModel: historyModel, showingSheet: $showingSheet)
|
HistoryRow(historyModel: historyModel, showingSheet: $showingSheet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !historyListViewModel.callLogsFilter.isEmpty {
|
||||||
|
if !contactsManager.lastSearch.isEmpty {
|
||||||
|
HStack(alignment: .center) {
|
||||||
|
Text("contacts_list_all_contacts_title")
|
||||||
|
.default_text_style_800(styleSize: 16)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContactsListFragment(showingSheet: .constant(false), startCallFunc: { addr in
|
||||||
|
withAnimation {
|
||||||
|
telecomManager.doCallOrJoinConf(address: addr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if !contactsManager.lastSearchSuggestions.isEmpty {
|
||||||
|
HStack(alignment: .center) {
|
||||||
|
Text("generic_address_picker_suggestions_list_title")
|
||||||
|
.default_text_style_800(styleSize: 16)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
suggestionsList
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.safeAreaInset(edge: .top, content: {
|
.safeAreaInset(edge: .top, content: {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
@ -46,7 +74,13 @@ struct HistoryListFragment: View {
|
||||||
.listStyle(.plain)
|
.listStyle(.plain)
|
||||||
.overlay(
|
.overlay(
|
||||||
VStack {
|
VStack {
|
||||||
if historyListViewModel.callLogs.isEmpty {
|
if historyListViewModel.callLogs.isEmpty &&
|
||||||
|
(
|
||||||
|
historyListViewModel.callLogsFilter.isEmpty ||
|
||||||
|
(!historyListViewModel.callLogsFilter.isEmpty &&
|
||||||
|
contactsManager.lastSearch.isEmpty &&
|
||||||
|
contactsManager.lastSearchSuggestions.isEmpty)
|
||||||
|
) {
|
||||||
Spacer()
|
Spacer()
|
||||||
Image("illus-belledonne")
|
Image("illus-belledonne")
|
||||||
.resizable()
|
.resizable()
|
||||||
|
|
@ -62,10 +96,78 @@ struct HistoryListFragment: View {
|
||||||
}
|
}
|
||||||
.padding(.all)
|
.padding(.all)
|
||||||
)
|
)
|
||||||
|
.onDisappear {
|
||||||
|
if !historyListViewModel.callLogsFilter.isEmpty {
|
||||||
|
historyListViewModel.resetFilterCallLogs()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle("")
|
.navigationTitle("")
|
||||||
.navigationBarHidden(true)
|
.navigationBarHidden(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var suggestionsList: some View {
|
||||||
|
ForEach(0..<contactsManager.lastSearchSuggestions.count, id: \.self) { index in
|
||||||
|
Button {
|
||||||
|
if let address = contactsManager.lastSearchSuggestions[index].address {
|
||||||
|
withAnimation {
|
||||||
|
telecomManager.doCallOrJoinConf(address: address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
HStack {
|
||||||
|
if index < contactsManager.lastSearchSuggestions.count
|
||||||
|
&& contactsManager.lastSearchSuggestions[index].address != nil {
|
||||||
|
if contactsManager.lastSearchSuggestions[index].address!.domain != AppServices.corePreferences.defaultDomain {
|
||||||
|
Image(uiImage: contactsManager.textToImage(
|
||||||
|
firstName: String(contactsManager.lastSearchSuggestions[index].address!.asStringUriOnly().dropFirst(4)),
|
||||||
|
lastName: ""))
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 45, height: 45)
|
||||||
|
.clipShape(Circle())
|
||||||
|
|
||||||
|
Text(String(contactsManager.lastSearchSuggestions[index].address!.asStringUriOnly().dropFirst(4)))
|
||||||
|
.default_text_style(styleSize: 16)
|
||||||
|
.lineLimit(1)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.foregroundStyle(Color.orangeMain500)
|
||||||
|
} else {
|
||||||
|
if let address = contactsManager.lastSearchSuggestions[index].address {
|
||||||
|
let nameTmp = address.displayName
|
||||||
|
?? address.username
|
||||||
|
?? String(address.asStringUriOnly().dropFirst(4))
|
||||||
|
|
||||||
|
Image(uiImage: contactsManager.textToImage(
|
||||||
|
firstName: nameTmp,
|
||||||
|
lastName: ""))
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 45, height: 45)
|
||||||
|
.clipShape(Circle())
|
||||||
|
|
||||||
|
Text(nameTmp)
|
||||||
|
.default_text_style(styleSize: 16)
|
||||||
|
.lineLimit(1)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.foregroundStyle(Color.orangeMain500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Image("profil-picture-default")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 45, height: 45)
|
||||||
|
.clipShape(Circle())
|
||||||
|
|
||||||
|
Text("username_error")
|
||||||
|
.default_text_style(styleSize: 16)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.foregroundStyle(Color.orangeMain500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.buttonStyle(.borderless)
|
||||||
|
.listRowSeparator(.hidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HistoryRow: View {
|
struct HistoryRow: View {
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@ class HistoryListViewModel: ObservableObject {
|
||||||
var callLogsAddressToDelete = ""
|
var callLogsAddressToDelete = ""
|
||||||
var callLogCoreDelegate: CoreDelegate?
|
var callLogCoreDelegate: CoreDelegate?
|
||||||
|
|
||||||
|
@Published var callLogsFilter = ""
|
||||||
|
|
||||||
@Published var selectedCall: HistoryModel?
|
@Published var selectedCall: HistoryModel?
|
||||||
|
|
||||||
@Published var displayedConversation: ConversationModel?
|
@Published var displayedConversation: ConversationModel?
|
||||||
|
|
@ -171,6 +173,7 @@ class HistoryListViewModel: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterCallLogs(filter: String) {
|
func filterCallLogs(filter: String) {
|
||||||
|
callLogsFilter = filter
|
||||||
callLogs.removeAll()
|
callLogs.removeAll()
|
||||||
callLogsTmp.forEach { callLog in
|
callLogsTmp.forEach { callLog in
|
||||||
if callLog.addressName.lowercased().contains(filter.lowercased()) {
|
if callLog.addressName.lowercased().contains(filter.lowercased()) {
|
||||||
|
|
@ -180,6 +183,7 @@ class HistoryListViewModel: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
func resetFilterCallLogs() {
|
func resetFilterCallLogs() {
|
||||||
|
callLogsFilter = ""
|
||||||
callLogs = callLogsTmp
|
callLogs = callLogsTmp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue