diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsFragment.kt index b395db1d9..d576889d2 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsFragment.kt @@ -144,7 +144,7 @@ class ConversationsFragment : GenericFragment() { } } - sharedViewModel.navigateToCallsEvent.observe(viewLifecycleOwner) { + sharedViewModel.navigateToHistoryEvent.observe(viewLifecycleOwner) { it.consume { if (findNavController().currentDestination?.id == R.id.conversationsFragment) { // To prevent any previously seen conversation to show up when navigating back to here later diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsListFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsListFragment.kt index c4b1f9407..e61164b8c 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsListFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsListFragment.kt @@ -19,6 +19,7 @@ */ package org.linphone.ui.main.chat.fragment +import android.content.res.Configuration import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -34,8 +35,7 @@ import org.linphone.ui.main.chat.viewmodel.ConversationsListViewModel import org.linphone.ui.main.fragment.AbstractTopBarFragment import org.linphone.ui.main.history.fragment.HistoryMenuDialogFragment import org.linphone.utils.Event -import org.linphone.utils.hideKeyboard -import org.linphone.utils.showKeyboard +import org.linphone.utils.setKeyboardInsetListener @UiThread class ConversationsListFragment : AbstractTopBarFragment() { @@ -57,12 +57,11 @@ class ConversationsListFragment : AbstractTopBarFragment() { binding = ChatListFragmentBinding.inflate(layoutInflater) return binding.root } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - listViewModel = requireActivity().run { - ViewModelProvider(this)[ConversationsListViewModel::class.java] - } + listViewModel = ViewModelProvider(this)[ConversationsListViewModel::class.java] binding.lifecycleOwner = viewLifecycleOwner binding.viewModel = listViewModel @@ -129,6 +128,19 @@ class ConversationsListFragment : AbstractTopBarFragment() { } } + // TopBarFragment related + + setViewModelAndTitle( + binding.topBar.search, + listViewModel, + getString(R.string.bottom_navigation_conversations_label) + ) + + binding.root.setKeyboardInsetListener { keyboardVisible -> + val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE + binding.bottomNavBar.root.visibility = if (!portraitOrientation || !keyboardVisible) View.VISIBLE else View.GONE + } + sharedViewModel.defaultAccountChangedEvent.observe(viewLifecycleOwner) { it.consume { Log.i( @@ -137,27 +149,5 @@ class ConversationsListFragment : AbstractTopBarFragment() { listViewModel.applyFilter() } } - - // TopBarFragment related - - setViewModelAndTitle( - listViewModel, - getString(R.string.bottom_navigation_conversations_label) - ) - - listViewModel.searchFilter.observe(viewLifecycleOwner) { filter -> - listViewModel.applyFilter(filter.trim()) - } - - listViewModel.focusSearchBarEvent.observe(viewLifecycleOwner) { - it.consume { show -> - if (show) { - // To automatically open keyboard - binding.topBar.search.showKeyboard() - } else { - binding.topBar.search.hideKeyboard() - } - } - } } } diff --git a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationsListViewModel.kt b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationsListViewModel.kt index ffda2496c..70c40517d 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationsListViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationsListViewModel.kt @@ -43,8 +43,6 @@ class ConversationsListViewModel @UiThread constructor() : AbstractTopBarViewMod val fetchInProgress = MutableLiveData() - private var currentFilter = "" - private val coreListener = object : CoreListenerStub() { @WorkerThread override fun onChatRoomStateChanged( @@ -94,9 +92,7 @@ class ConversationsListViewModel @UiThread constructor() : AbstractTopBarViewMod } @UiThread - fun applyFilter(filter: String = currentFilter) { - currentFilter = filter - + override fun filter() { coreContext.postOnCoreThread { computeChatRoomsList(currentFilter) } diff --git a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsFragment.kt b/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsFragment.kt index 21f5cdc27..2ef9f5331 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsFragment.kt @@ -119,7 +119,7 @@ class ContactsFragment : GenericFragment() { } } - sharedViewModel.navigateToCallsEvent.observe(viewLifecycleOwner) { + sharedViewModel.navigateToHistoryEvent.observe(viewLifecycleOwner) { it.consume { if (findNavController().currentDestination?.id == R.id.contactsFragment) { // To prevent any previously seen contact to show up when navigating back to here later diff --git a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsListFragment.kt b/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsListFragment.kt index f86914230..0dab96121 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsListFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsListFragment.kt @@ -20,6 +20,7 @@ package org.linphone.ui.main.contacts.fragment import android.content.Intent +import android.content.res.Configuration import android.os.Bundle import android.provider.ContactsContract import android.view.Gravity @@ -42,8 +43,7 @@ import org.linphone.ui.main.contacts.adapter.ContactsListAdapter import org.linphone.ui.main.contacts.viewmodel.ContactsListViewModel import org.linphone.ui.main.fragment.AbstractTopBarFragment import org.linphone.utils.Event -import org.linphone.utils.hideKeyboard -import org.linphone.utils.showKeyboard +import org.linphone.utils.setKeyboardInsetListener @UiThread class ContactsListFragment : AbstractTopBarFragment() { @@ -70,9 +70,7 @@ class ContactsListFragment : AbstractTopBarFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - listViewModel = requireActivity().run { - ViewModelProvider(this)[ContactsListViewModel::class.java] - } + listViewModel = ViewModelProvider(this)[ContactsListViewModel::class.java] binding.lifecycleOwner = viewLifecycleOwner binding.viewModel = listViewModel @@ -131,6 +129,19 @@ class ContactsListFragment : AbstractTopBarFragment() { showFilterPopupMenu(binding.filter) } + // TopBarFragment related + + setViewModelAndTitle( + binding.topBar.search, + listViewModel, + getString(R.string.bottom_navigation_contacts_label) + ) + + binding.root.setKeyboardInsetListener { keyboardVisible -> + val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE + binding.bottomNavBar.root.visibility = if (!portraitOrientation || !keyboardVisible) View.VISIBLE else View.GONE + } + sharedViewModel.defaultAccountChangedEvent.observe(viewLifecycleOwner) { it.consume { Log.i( @@ -140,25 +151,6 @@ class ContactsListFragment : AbstractTopBarFragment() { listViewModel.applyCurrentDefaultAccountFilter() } } - - // TopBarFragment related - - setViewModelAndTitle(listViewModel, getString(R.string.bottom_navigation_contacts_label)) - - listViewModel.searchFilter.observe(viewLifecycleOwner) { filter -> - listViewModel.applyFilter(filter.trim()) - } - - listViewModel.focusSearchBarEvent.observe(viewLifecycleOwner) { - it.consume { show -> - if (show) { - // To automatically open keyboard - binding.topBar.search.showKeyboard() - } else { - binding.topBar.search.hideKeyboard() - } - } - } } private fun configureAdapter(adapter: ContactsListAdapter) { diff --git a/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactsListViewModel.kt b/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactsListViewModel.kt index 666560c3b..262befe00 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactsListViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactsListViewModel.kt @@ -60,7 +60,6 @@ class ContactsListViewModel @UiThread constructor() : AbstractTopBarViewModel() MutableLiveData>>() } - private var currentFilter = "" private var previousFilter = "NotSet" private var limitSearchToLinphoneAccounts = true @@ -189,11 +188,11 @@ class ContactsListViewModel @UiThread constructor() : AbstractTopBarViewModel() } @UiThread - fun applyFilter(filter: String = currentFilter) { - isListFiltered.value = filter.isNotEmpty() + override fun filter() { + isListFiltered.value = currentFilter.isNotEmpty() coreContext.postOnCoreThread { applyFilter( - filter, + currentFilter, if (limitSearchToLinphoneAccounts) corePreferences.defaultDomain else "", MagicSearch.Source.Friends.toInt() or MagicSearch.Source.LdapServers.toInt() ) diff --git a/app/src/main/java/org/linphone/ui/main/fragment/AbstractTopBarFragment.kt b/app/src/main/java/org/linphone/ui/main/fragment/AbstractTopBarFragment.kt index cc003b7aa..90706385c 100644 --- a/app/src/main/java/org/linphone/ui/main/fragment/AbstractTopBarFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/fragment/AbstractTopBarFragment.kt @@ -20,18 +20,84 @@ package org.linphone.ui.main.fragment import androidx.annotation.UiThread +import com.google.android.material.textfield.TextInputLayout +import org.linphone.R import org.linphone.ui.main.MainActivity import org.linphone.ui.main.viewmodel.AbstractTopBarViewModel +import org.linphone.utils.Event +import org.linphone.utils.hideKeyboard +import org.linphone.utils.showKeyboard @UiThread abstract class AbstractTopBarFragment : GenericFragment() { - fun setViewModelAndTitle(viewModel: AbstractTopBarViewModel, title: String) { + fun setViewModelAndTitle( + searchBar: TextInputLayout, + viewModel: AbstractTopBarViewModel, + title: String + ) { viewModel.title.value = title + viewModel.focusSearchBarEvent.observe(viewLifecycleOwner) { + it.consume { show -> + if (show) { + // To automatically open keyboard + searchBar.showKeyboard() + } else { + searchBar.hideKeyboard() + } + } + } + viewModel.openDrawerMenuEvent.observe(viewLifecycleOwner) { it.consume { (requireActivity() as MainActivity).toggleDrawerMenu() } } + + viewModel.searchFilter.observe(viewLifecycleOwner) { filter -> + viewModel.applyFilter(filter.trim()) + } + + viewModel.navigateToContactsEvent.observe(viewLifecycleOwner) { + if (sharedViewModel.currentlyDisplayedFragment.value != R.id.contactsFragment) { + sharedViewModel.navigateToContactsEvent.value = Event(true) + } + } + + viewModel.navigateToHistoryEvent.observe(viewLifecycleOwner) { + if (sharedViewModel.currentlyDisplayedFragment.value != R.id.historyFragment) { + sharedViewModel.navigateToHistoryEvent.value = Event(true) + } + } + + viewModel.navigateToConversationsEvent.observe(viewLifecycleOwner) { + if (sharedViewModel.currentlyDisplayedFragment.value != R.id.conversationsFragment) { + sharedViewModel.navigateToConversationsEvent.value = Event(true) + } + } + + viewModel.navigateToMeetingsEvent.observe(viewLifecycleOwner) { + if (sharedViewModel.currentlyDisplayedFragment.value != R.id.meetingsFragment) { + sharedViewModel.navigateToMeetingsEvent.value = Event(true) + } + } + + sharedViewModel.currentlyDisplayedFragment.observe(viewLifecycleOwner) { + viewModel.contactsSelected.value = it == R.id.contactsFragment + viewModel.callsSelected.value = it == R.id.historyFragment + viewModel.conversationsSelected.value = it == R.id.conversationsFragment + viewModel.meetingsSelected.value = it == R.id.meetingsFragment + } + + sharedViewModel.resetMissedCallsCountEvent.observe(viewLifecycleOwner) { + it.consume { + viewModel.resetMissedCallsCount() + } + } + + sharedViewModel.defaultAccountChangedEvent.observe(viewLifecycleOwner) { + // Do not consume it! + viewModel.updateAvailableMenus() + } } } diff --git a/app/src/main/java/org/linphone/ui/main/fragment/BottomNavBarFragment.kt b/app/src/main/java/org/linphone/ui/main/fragment/BottomNavBarFragment.kt deleted file mode 100644 index 2bf7eceae..000000000 --- a/app/src/main/java/org/linphone/ui/main/fragment/BottomNavBarFragment.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2010-2023 Belledonne Communications SARL. - * - * This file is part of linphone-android - * (see https://www.linphone.org). - * - * 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 . - */ -package org.linphone.ui.main.fragment - -import android.content.res.Configuration -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.annotation.UiThread -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import org.linphone.R -import org.linphone.databinding.BottomNavBarBinding -import org.linphone.ui.main.viewmodel.BottomNavBarViewModel -import org.linphone.ui.main.viewmodel.SharedMainViewModel -import org.linphone.utils.Event -import org.linphone.utils.setKeyboardInsetListener - -@UiThread -class BottomNavBarFragment : Fragment() { - private lateinit var binding: BottomNavBarBinding - - private lateinit var viewModel: BottomNavBarViewModel - - private lateinit var sharedViewModel: SharedMainViewModel - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - binding = BottomNavBarBinding.inflate(layoutInflater) - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - binding.lifecycleOwner = viewLifecycleOwner - - viewModel = requireActivity().run { - ViewModelProvider(this)[BottomNavBarViewModel::class.java] - } - binding.viewModel = viewModel - - sharedViewModel = requireActivity().run { - ViewModelProvider(this)[SharedMainViewModel::class.java] - } - - binding.root.setKeyboardInsetListener { keyboardVisible -> - val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE - binding.bottomNavBar.visibility = if (!portraitOrientation || !keyboardVisible) View.VISIBLE else View.GONE - } - - binding.setOnContactsClicked { - if (sharedViewModel.currentlyDisplayedFragment.value != R.id.contactsFragment) { - sharedViewModel.navigateToContactsEvent.value = Event(true) - } - } - - binding.setOnCallsClicked { - if (sharedViewModel.currentlyDisplayedFragment.value != R.id.historyFragment) { - sharedViewModel.navigateToCallsEvent.value = Event(true) - } - } - - binding.setOnConversationsClicked { - if (sharedViewModel.currentlyDisplayedFragment.value != R.id.conversationsFragment) { - sharedViewModel.navigateToConversationsEvent.value = Event(true) - } - } - - binding.setOnMeetingsClicked { - if (sharedViewModel.currentlyDisplayedFragment.value != R.id.meetingsFragment) { - sharedViewModel.navigateToMeetingsEvent.value = Event(true) - } - } - - sharedViewModel.currentlyDisplayedFragment.observe(viewLifecycleOwner) { - viewModel.contactsSelected.value = it == R.id.contactsFragment - viewModel.callsSelected.value = it == R.id.historyFragment - viewModel.conversationsSelected.value = it == R.id.conversationsFragment - viewModel.meetingsSelected.value = it == R.id.meetingsFragment - } - - sharedViewModel.resetMissedCallsCountEvent.observe(viewLifecycleOwner) { - it.consume { - viewModel.resetMissedCallsCount() - } - } - - sharedViewModel.defaultAccountChangedEvent.observe(viewLifecycleOwner) { - // Do not consume it! - viewModel.updateAvailableMenus() - } - } -} diff --git a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryListFragment.kt b/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryListFragment.kt index 615d95d35..0099a8c07 100644 --- a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryListFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryListFragment.kt @@ -22,6 +22,7 @@ package org.linphone.ui.main.history.fragment import android.content.ClipData import android.content.ClipboardManager import android.content.Context +import android.content.res.Configuration import android.os.Bundle import android.view.Gravity import android.view.LayoutInflater @@ -44,8 +45,7 @@ import org.linphone.ui.main.history.model.ConfirmationDialogModel import org.linphone.ui.main.history.viewmodel.HistoryListViewModel import org.linphone.utils.DialogUtils import org.linphone.utils.Event -import org.linphone.utils.hideKeyboard -import org.linphone.utils.showKeyboard +import org.linphone.utils.setKeyboardInsetListener @UiThread class HistoryListFragment : AbstractTopBarFragment() { @@ -67,12 +67,11 @@ class HistoryListFragment : AbstractTopBarFragment() { binding = HistoryListFragmentBinding.inflate(layoutInflater) return binding.root } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - listViewModel = requireActivity().run { - ViewModelProvider(this)[HistoryListViewModel::class.java] - } + listViewModel = ViewModelProvider(this)[HistoryListViewModel::class.java] binding.lifecycleOwner = viewLifecycleOwner binding.viewModel = listViewModel @@ -177,6 +176,19 @@ class HistoryListFragment : AbstractTopBarFragment() { sharedViewModel.showStartCallEvent.value = Event(true) } + // TopBarFragment related + + setViewModelAndTitle( + binding.topBar.search, + listViewModel, + getString(R.string.bottom_navigation_calls_label) + ) + + binding.root.setKeyboardInsetListener { keyboardVisible -> + val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE + binding.bottomNavBar.root.visibility = if (!portraitOrientation || !keyboardVisible) View.VISIBLE else View.GONE + } + sharedViewModel.defaultAccountChangedEvent.observe(viewLifecycleOwner) { it.consume { Log.i( @@ -186,25 +198,6 @@ class HistoryListFragment : AbstractTopBarFragment() { listViewModel.applyFilter() } } - - // TopBarFragment related - - setViewModelAndTitle(listViewModel, getString(R.string.bottom_navigation_calls_label)) - - listViewModel.searchFilter.observe(viewLifecycleOwner) { filter -> - listViewModel.applyFilter(filter.trim()) - } - - listViewModel.focusSearchBarEvent.observe(viewLifecycleOwner) { - it.consume { show -> - if (show) { - // To automatically open keyboard - binding.topBar.search.showKeyboard() - } else { - binding.topBar.search.hideKeyboard() - } - } - } } override fun onResume() { diff --git a/app/src/main/java/org/linphone/ui/main/history/viewmodel/HistoryListViewModel.kt b/app/src/main/java/org/linphone/ui/main/history/viewmodel/HistoryListViewModel.kt index 0f7716a9d..e15a64894 100644 --- a/app/src/main/java/org/linphone/ui/main/history/viewmodel/HistoryListViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/history/viewmodel/HistoryListViewModel.kt @@ -46,8 +46,6 @@ class HistoryListViewModel @UiThread constructor() : AbstractTopBarViewModel() { MutableLiveData>() } - private var currentFilter = "" - private val coreListener = object : CoreListenerStub() { override fun onCallLogUpdated(core: Core, callLog: CallLog) { computeCallLogsList(currentFilter) @@ -81,15 +79,6 @@ class HistoryListViewModel @UiThread constructor() : AbstractTopBarViewModel() { } } - @UiThread - fun applyFilter(filter: String = currentFilter) { - currentFilter = filter - - coreContext.postOnCoreThread { - computeCallLogsList(currentFilter) - } - } - @UiThread fun removeAllCallLogs() { coreContext.postOnCoreThread { core -> @@ -107,6 +96,13 @@ class HistoryListViewModel @UiThread constructor() : AbstractTopBarViewModel() { } } + @UiThread + override fun filter() { + coreContext.postOnCoreThread { + computeCallLogsList(currentFilter) + } + } + @WorkerThread private fun computeCallLogsList(filter: String) { if (callLogs.value.orEmpty().isEmpty()) { diff --git a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsFragment.kt b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsFragment.kt index e0e03f452..9bb51213c 100644 --- a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsFragment.kt @@ -134,7 +134,7 @@ class MeetingsFragment : GenericFragment() { } } - sharedViewModel.navigateToCallsEvent.observe(viewLifecycleOwner) { + sharedViewModel.navigateToHistoryEvent.observe(viewLifecycleOwner) { it.consume { if (findNavController().currentDestination?.id == R.id.meetingsFragment) { // To prevent any previously seen meeting to show up when navigating back to here later diff --git a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsListFragment.kt b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsListFragment.kt index 8b9196f75..29d1468f9 100644 --- a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsListFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsListFragment.kt @@ -19,6 +19,7 @@ */ package org.linphone.ui.main.meetings.fragment +import android.content.res.Configuration import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -36,8 +37,7 @@ import org.linphone.ui.main.meetings.viewmodel.MeetingsListViewModel import org.linphone.utils.AppUtils import org.linphone.utils.Event import org.linphone.utils.RecyclerViewHeaderDecoration -import org.linphone.utils.hideKeyboard -import org.linphone.utils.showKeyboard +import org.linphone.utils.setKeyboardInsetListener @UiThread class MeetingsListFragment : AbstractTopBarFragment() { @@ -59,13 +59,12 @@ class MeetingsListFragment : AbstractTopBarFragment() { binding = MeetingsListFragmentBinding.inflate(layoutInflater) return binding.root } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) postponeEnterTransition() - listViewModel = requireActivity().run { - ViewModelProvider(this)[MeetingsListViewModel::class.java] - } + listViewModel = ViewModelProvider(this)[MeetingsListViewModel::class.java] binding.lifecycleOwner = viewLifecycleOwner binding.viewModel = listViewModel @@ -98,7 +97,6 @@ class MeetingsListFragment : AbstractTopBarFragment() { adapter.submitList(it) Log.i("$TAG Meetings list ready with [${it.size}] items") - val newCount = it.size if (currentCount < it.size) { (view.parent as? ViewGroup)?.doOnPreDraw { startPostponedEnterTransition() @@ -114,6 +112,19 @@ class MeetingsListFragment : AbstractTopBarFragment() { } } + // TopBarFragment related + + setViewModelAndTitle( + binding.topBar.search, + listViewModel, + getString(R.string.bottom_navigation_meetings_label) + ) + + binding.root.setKeyboardInsetListener { keyboardVisible -> + val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE + binding.bottomNavBar.root.visibility = if (!portraitOrientation || !keyboardVisible) View.VISIBLE else View.GONE + } + sharedViewModel.defaultAccountChangedEvent.observe(viewLifecycleOwner) { it.consume { Log.i( @@ -122,28 +133,6 @@ class MeetingsListFragment : AbstractTopBarFragment() { listViewModel.applyFilter() } } - - // TopBarFragment related - - setViewModelAndTitle( - listViewModel, - getString(R.string.bottom_navigation_meetings_label) - ) - - listViewModel.searchFilter.observe(viewLifecycleOwner) { filter -> - listViewModel.applyFilter(filter.trim()) - } - - listViewModel.focusSearchBarEvent.observe(viewLifecycleOwner) { - it.consume { show -> - if (show) { - // To automatically open keyboard - binding.topBar.search.showKeyboard() - } else { - binding.topBar.search.hideKeyboard() - } - } - } } private fun scrollToToday() { diff --git a/app/src/main/java/org/linphone/ui/main/meetings/fragment/ScheduleMeetingFragment.kt b/app/src/main/java/org/linphone/ui/main/meetings/fragment/ScheduleMeetingFragment.kt index 81dad2dbb..d20f9c0c0 100644 --- a/app/src/main/java/org/linphone/ui/main/meetings/fragment/ScheduleMeetingFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/meetings/fragment/ScheduleMeetingFragment.kt @@ -67,9 +67,7 @@ class ScheduleMeetingFragment : GenericFragment() { binding.lifecycleOwner = viewLifecycleOwner - viewModel = requireActivity().run { - ViewModelProvider(this)[ScheduleMeetingViewModel::class.java] - } + viewModel = ViewModelProvider(this)[ScheduleMeetingViewModel::class.java] binding.viewModel = viewModel binding.setBackClickListener { diff --git a/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingsListViewModel.kt b/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingsListViewModel.kt index c18b42e8c..15f5056c8 100644 --- a/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingsListViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingsListViewModel.kt @@ -40,8 +40,6 @@ class MeetingsListViewModel @UiThread constructor() : AbstractTopBarViewModel() val fetchInProgress = MutableLiveData() - private var currentFilter = "" - private val coreListener = object : CoreListenerStub() { @WorkerThread override fun onConferenceInfoReceived(core: Core, conferenceInfo: ConferenceInfo) { @@ -68,11 +66,9 @@ class MeetingsListViewModel @UiThread constructor() : AbstractTopBarViewModel() } @UiThread - fun applyFilter(filter: String = currentFilter) { - currentFilter = filter - + override fun filter() { coreContext.postOnCoreThread { - computeMeetingsList(filter) + computeMeetingsList(currentFilter) } } diff --git a/app/src/main/java/org/linphone/ui/main/settings/fragment/AccountSettingsFragment.kt b/app/src/main/java/org/linphone/ui/main/settings/fragment/AccountSettingsFragment.kt index 64d83ae13..2dfd2afad 100644 --- a/app/src/main/java/org/linphone/ui/main/settings/fragment/AccountSettingsFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/settings/fragment/AccountSettingsFragment.kt @@ -66,9 +66,7 @@ class AccountSettingsFragment : GenericFragment() { binding.lifecycleOwner = viewLifecycleOwner - viewModel = requireActivity().run { - ViewModelProvider(this)[AccountSettingsViewModel::class.java] - } + viewModel = ViewModelProvider(this)[AccountSettingsViewModel::class.java] binding.viewModel = viewModel val identity = args.accountIdentity diff --git a/app/src/main/java/org/linphone/ui/main/viewmodel/AbstractTopBarViewModel.kt b/app/src/main/java/org/linphone/ui/main/viewmodel/AbstractTopBarViewModel.kt index 606617374..f67c3e1b3 100644 --- a/app/src/main/java/org/linphone/ui/main/viewmodel/AbstractTopBarViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/viewmodel/AbstractTopBarViewModel.kt @@ -20,12 +20,20 @@ package org.linphone.ui.main.viewmodel import androidx.annotation.UiThread +import androidx.annotation.WorkerThread import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import org.linphone.LinphoneApplication.Companion.coreContext +import org.linphone.LinphoneApplication.Companion.corePreferences +import org.linphone.core.Call +import org.linphone.core.ChatMessage +import org.linphone.core.ChatRoom +import org.linphone.core.Core +import org.linphone.core.CoreListenerStub import org.linphone.core.tools.Log import org.linphone.ui.main.model.AccountModel import org.linphone.utils.Event +import org.linphone.utils.LinphoneUtils open class AbstractTopBarViewModel @UiThread constructor() : ViewModel() { companion object { @@ -40,6 +48,22 @@ open class AbstractTopBarViewModel @UiThread constructor() : ViewModel() { val searchFilter = MutableLiveData() + val contactsSelected = MutableLiveData() + + val callsSelected = MutableLiveData() + + val conversationsSelected = MutableLiveData() + + val meetingsSelected = MutableLiveData() + + val hideConversations = MutableLiveData() + + val hideMeetings = MutableLiveData() + + val missedCallsCount = MutableLiveData() + + val unreadMessages = MutableLiveData() + val focusSearchBarEvent: MutableLiveData> by lazy { MutableLiveData>() } @@ -48,9 +72,62 @@ open class AbstractTopBarViewModel @UiThread constructor() : ViewModel() { MutableLiveData>() } + val navigateToHistoryEvent: MutableLiveData> by lazy { + MutableLiveData>() + } + + val navigateToContactsEvent: MutableLiveData> by lazy { + MutableLiveData>() + } + + val navigateToConversationsEvent: MutableLiveData> by lazy { + MutableLiveData>() + } + + val navigateToMeetingsEvent: MutableLiveData> by lazy { + MutableLiveData>() + } + + protected var currentFilter = "" + + private val coreListener = object : CoreListenerStub() { + @WorkerThread + override fun onCallStateChanged( + core: Core, + call: Call, + state: Call.State?, + message: String + ) { + if (state == Call.State.End || state == Call.State.Error) { + updateMissedCallsCount() + } + } + + @WorkerThread + override fun onMessagesReceived( + core: Core, + chatRoom: ChatRoom, + messages: Array + ) { + updateUnreadMessagesCount() + } + + @WorkerThread + override fun onChatRoomRead(core: Core, chatRoom: ChatRoom) { + updateUnreadMessagesCount() + } + } + init { searchBarVisible.value = false + coreContext.postOnCoreThread { core -> + core.addListener(coreListener) + updateMissedCallsCount() + updateUnreadMessagesCount() + } + + updateAvailableMenus() update() } @@ -59,6 +136,7 @@ open class AbstractTopBarViewModel @UiThread constructor() : ViewModel() { super.onCleared() coreContext.postOnCoreThread { core -> + core.removeListener(coreListener) account.value?.destroy() } } @@ -86,6 +164,17 @@ open class AbstractTopBarViewModel @UiThread constructor() : ViewModel() { searchFilter.value = "" } + @UiThread + fun applyFilter(filter: String = currentFilter) { + Log.i("$TAG New filter set by user [$filter]") + currentFilter = filter + filter() + } + + @UiThread + open fun filter() { + } + @UiThread fun update() { coreContext.postOnCoreThread { core -> @@ -98,4 +187,68 @@ open class AbstractTopBarViewModel @UiThread constructor() : ViewModel() { } } } + + @UiThread + fun navigateToContacts() { + navigateToContactsEvent.value = Event(true) + } + + @UiThread + fun navigateToHistory() { + navigateToHistoryEvent.value = Event(true) + } + + @UiThread + fun navigateToConversations() { + navigateToConversationsEvent.value = Event(true) + } + + @UiThread + fun navigateToMeetings() { + navigateToMeetingsEvent.value = Event(true) + } + + @WorkerThread + fun updateMissedCallsCount() { + val account = LinphoneUtils.getDefaultAccount() + val count = account?.missedCallsCount ?: coreContext.core.missedCallsCount + val moreThanOne = count > 1 + Log.i( + "$TAG There ${if (moreThanOne) "are" else "is"} [$count] missed ${if (moreThanOne) "calls" else "call"}" + ) + missedCallsCount.postValue(count) + } + + @WorkerThread + fun updateUnreadMessagesCount() { + val account = LinphoneUtils.getDefaultAccount() + val count = account?.unreadChatMessageCount ?: coreContext.core.unreadChatMessageCount + val moreThanOne = count > 1 + Log.i( + "$TAG There ${if (moreThanOne) "are" else "is"} [$count] unread ${if (moreThanOne) "messages" else "message"}" + ) + unreadMessages.postValue(count) + } + + @UiThread + fun resetMissedCallsCount() { + coreContext.postOnCoreThread { core -> + val account = LinphoneUtils.getDefaultAccount() + account?.resetMissedCallsCount() ?: core.resetMissedCallsCount() + updateMissedCallsCount() + } + } + + @UiThread + fun updateAvailableMenus() { + coreContext.postOnCoreThread { core -> + hideConversations.postValue(corePreferences.disableChat) + + val hideGroupCall = + corePreferences.disableMeetings || !LinphoneUtils.isRemoteConferencingAvailable( + core + ) + hideMeetings.postValue(hideGroupCall) + } + } } diff --git a/app/src/main/java/org/linphone/ui/main/viewmodel/BottomNavBarViewModel.kt b/app/src/main/java/org/linphone/ui/main/viewmodel/BottomNavBarViewModel.kt deleted file mode 100644 index 01648c035..000000000 --- a/app/src/main/java/org/linphone/ui/main/viewmodel/BottomNavBarViewModel.kt +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2010-2023 Belledonne Communications SARL. - * - * This file is part of linphone-android - * (see https://www.linphone.org). - * - * 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 . - */ -package org.linphone.ui.main.viewmodel - -import androidx.annotation.UiThread -import androidx.annotation.WorkerThread -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import org.linphone.LinphoneApplication.Companion.coreContext -import org.linphone.LinphoneApplication.Companion.corePreferences -import org.linphone.core.Call -import org.linphone.core.ChatMessage -import org.linphone.core.ChatRoom -import org.linphone.core.Core -import org.linphone.core.CoreListenerStub -import org.linphone.core.tools.Log -import org.linphone.utils.LinphoneUtils - -class BottomNavBarViewModel @UiThread constructor() : ViewModel() { - companion object { - private const val TAG = "[Bottom Navigation Bar ViewModel]" - } - - val contactsSelected = MutableLiveData() - - val callsSelected = MutableLiveData() - - val conversationsSelected = MutableLiveData() - - val meetingsSelected = MutableLiveData() - - val hideConversations = MutableLiveData() - - val hideMeetings = MutableLiveData() - - val missedCallsCount = MutableLiveData() - - val unreadMessages = MutableLiveData() - - private val coreListener = object : CoreListenerStub() { - @WorkerThread - override fun onCallStateChanged( - core: Core, - call: Call, - state: Call.State?, - message: String - ) { - if (state == Call.State.End || state == Call.State.Error) { - updateMissedCallsCount() - } - } - - @WorkerThread - override fun onMessagesReceived( - core: Core, - chatRoom: ChatRoom, - messages: Array - ) { - updateUnreadMessagesCount() - } - - @WorkerThread - override fun onChatRoomRead(core: Core, chatRoom: ChatRoom) { - updateUnreadMessagesCount() - } - } - - init { - coreContext.postOnCoreThread { core -> - core.addListener(coreListener) - updateMissedCallsCount() - updateUnreadMessagesCount() - } - - updateAvailableMenus() - } - - @UiThread - override fun onCleared() { - super.onCleared() - - coreContext.postOnCoreThread { core -> - core.removeListener(coreListener) - } - } - - @WorkerThread - fun updateMissedCallsCount() { - val account = LinphoneUtils.getDefaultAccount() - val count = account?.missedCallsCount ?: coreContext.core.missedCallsCount - val moreThanOne = count > 1 - Log.i( - "$TAG There ${if (moreThanOne) "are" else "is"} [$count] missed ${if (moreThanOne) "calls" else "call"}" - ) - missedCallsCount.postValue(count) - } - - @WorkerThread - fun updateUnreadMessagesCount() { - val account = LinphoneUtils.getDefaultAccount() - val count = account?.unreadChatMessageCount ?: coreContext.core.unreadChatMessageCount - val moreThanOne = count > 1 - Log.i( - "$TAG There ${if (moreThanOne) "are" else "is"} [$count] unread ${if (moreThanOne) "messages" else "message"}" - ) - unreadMessages.postValue(count) - } - - @UiThread - fun resetMissedCallsCount() { - coreContext.postOnCoreThread { core -> - val account = LinphoneUtils.getDefaultAccount() - account?.resetMissedCallsCount() ?: core.resetMissedCallsCount() - updateMissedCallsCount() - } - } - - @UiThread - fun updateAvailableMenus() { - coreContext.postOnCoreThread { core -> - hideConversations.postValue(corePreferences.disableChat) - - val hideGroupCall = - corePreferences.disableMeetings || !LinphoneUtils.isRemoteConferencingAvailable( - core - ) - hideMeetings.postValue(hideGroupCall) - } - } -} diff --git a/app/src/main/java/org/linphone/ui/main/viewmodel/SharedMainViewModel.kt b/app/src/main/java/org/linphone/ui/main/viewmodel/SharedMainViewModel.kt index dca355c74..e9440cb15 100644 --- a/app/src/main/java/org/linphone/ui/main/viewmodel/SharedMainViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/viewmodel/SharedMainViewModel.kt @@ -37,7 +37,7 @@ class SharedMainViewModel @UiThread constructor() : ViewModel() { MutableLiveData>() } - val navigateToCallsEvent: MutableLiveData> by lazy { + val navigateToHistoryEvent: MutableLiveData> by lazy { MutableLiveData>() } diff --git a/app/src/main/res/layout-land/bottom_nav_bar.xml b/app/src/main/res/layout-land/bottom_nav_bar.xml index 8189d9b6a..91fbaf139 100644 --- a/app/src/main/res/layout-land/bottom_nav_bar.xml +++ b/app/src/main/res/layout-land/bottom_nav_bar.xml @@ -6,21 +6,9 @@ - - - - + type="org.linphone.ui.main.viewmodel.AbstractTopBarViewModel" /> - diff --git a/app/src/main/res/layout-land/contacts_list_fragment.xml b/app/src/main/res/layout-land/contacts_list_fragment.xml index 521cf143e..4b1813777 100644 --- a/app/src/main/res/layout-land/contacts_list_fragment.xml +++ b/app/src/main/res/layout-land/contacts_list_fragment.xml @@ -31,12 +31,12 @@ app:constraint_referenced_ids="no_contacts_image, no_contacts_label" android:visibility="@{viewModel.contactsList.empty ? View.VISIBLE : View.GONE}" /> - diff --git a/app/src/main/res/layout-land/history_list_fragment.xml b/app/src/main/res/layout-land/history_list_fragment.xml index 6c073e8c6..18cb55905 100644 --- a/app/src/main/res/layout-land/history_list_fragment.xml +++ b/app/src/main/res/layout-land/history_list_fragment.xml @@ -37,6 +37,16 @@ app:constraint_referenced_ids="no_calls_image, no_calls_label" android:visibility="@{viewModel.callLogs.empty ? View.VISIBLE : View.GONE}" /> + + - - - diff --git a/app/src/main/res/layout/bottom_nav_bar.xml b/app/src/main/res/layout/bottom_nav_bar.xml index c915ef2bc..d4d776f47 100644 --- a/app/src/main/res/layout/bottom_nav_bar.xml +++ b/app/src/main/res/layout/bottom_nav_bar.xml @@ -6,33 +6,22 @@ - - - - + type="org.linphone.ui.main.viewmodel.AbstractTopBarViewModel" /> - diff --git a/app/src/main/res/layout/contacts_list_fragment.xml b/app/src/main/res/layout/contacts_list_fragment.xml index c7d832cf9..48783f863 100644 --- a/app/src/main/res/layout/contacts_list_fragment.xml +++ b/app/src/main/res/layout/contacts_list_fragment.xml @@ -144,12 +144,12 @@ app:layout_constraintTop_toBottomOf="@id/all_contacts_label" app:layout_constraintBottom_toTopOf="@id/bottom_nav_bar" /> - diff --git a/app/src/main/res/layout/history_list_fragment.xml b/app/src/main/res/layout/history_list_fragment.xml index a15237c7c..d8b55aa5b 100644 --- a/app/src/main/res/layout/history_list_fragment.xml +++ b/app/src/main/res/layout/history_list_fragment.xml @@ -106,12 +106,12 @@ app:layout_constraintTop_toBottomOf="@id/top_bar" app:layout_constraintBottom_toTopOf="@id/bottom_nav_bar" /> - diff --git a/app/src/main/res/layout/meetings_list_fragment.xml b/app/src/main/res/layout/meetings_list_fragment.xml index 4887c9eb9..74f0dcedd 100644 --- a/app/src/main/res/layout/meetings_list_fragment.xml +++ b/app/src/main/res/layout/meetings_list_fragment.xml @@ -103,12 +103,12 @@ app:layout_constraintTop_toTopOf="@id/background" app:layout_constraintBottom_toTopOf="@id/bottom_nav_bar" /> -