diff --git a/app/src/main/java/org/linphone/core/CoreContext.kt b/app/src/main/java/org/linphone/core/CoreContext.kt
index a3db8c039..7fd5072db 100644
--- a/app/src/main/java/org/linphone/core/CoreContext.kt
+++ b/app/src/main/java/org/linphone/core/CoreContext.kt
@@ -279,7 +279,7 @@ class CoreContext @UiThread constructor(val context: Context) : HandlerThread("C
params.mediaEncryption = MediaEncryption.ZRTP
}
/*if (LinphoneUtils.checkIfNetworkHasLowBandwidth(context)) {
- Log.w("[Context] Enabling low bandwidth mode!")
+ Log.w("$TAG Enabling low bandwidth mode!")
params.isLowBandwidthEnabled = true
}*/
diff --git a/app/src/main/java/org/linphone/core/CorePreferences.kt b/app/src/main/java/org/linphone/core/CorePreferences.kt
index 7e7c3b1dc..73efdf879 100644
--- a/app/src/main/java/org/linphone/core/CorePreferences.kt
+++ b/app/src/main/java/org/linphone/core/CorePreferences.kt
@@ -146,10 +146,6 @@ class CorePreferences @UiThread constructor(private val context: Context) {
val ringtonesPath: String
get() = context.filesDir.absolutePath + "/share/sounds/linphone/rings/"
- @get:AnyThread
- val defaultRingtonePath: String
- get() = ringtonesPath + "notes_of_the_optimistic.mkv"
-
@UiThread
fun copyAssetsFromPackage() {
copy("linphonerc_default", configPath)
diff --git a/app/src/main/java/org/linphone/ui/assistant/fragment/QrCodeScannerFragment.kt b/app/src/main/java/org/linphone/ui/assistant/fragment/QrCodeScannerFragment.kt
index b24142fe7..278517653 100644
--- a/app/src/main/java/org/linphone/ui/assistant/fragment/QrCodeScannerFragment.kt
+++ b/app/src/main/java/org/linphone/ui/assistant/fragment/QrCodeScannerFragment.kt
@@ -104,6 +104,9 @@ class QrCodeScannerFragment : Fragment() {
super.onResume()
if (isCameraPermissionGranted()) {
+ Log.i(
+ "$TAG Record video permission is granted, starting video preview with back cam if possible"
+ )
viewModel.setBackCamera()
enableQrCodeVideoScanner()
}
diff --git a/app/src/main/java/org/linphone/ui/call/fragment/CallsListFragment.kt b/app/src/main/java/org/linphone/ui/call/fragment/CallsListFragment.kt
index 2cabff9ea..42741d5b0 100644
--- a/app/src/main/java/org/linphone/ui/call/fragment/CallsListFragment.kt
+++ b/app/src/main/java/org/linphone/ui/call/fragment/CallsListFragment.kt
@@ -64,9 +64,7 @@ class CallsListFragment : GenericCallFragment() {
adapter = CallsListAdapter(viewLifecycleOwner)
binding.callsList.setHasFixedSize(true)
binding.callsList.adapter = adapter
-
- val layoutManager = LinearLayoutManager(requireContext())
- binding.callsList.layoutManager = layoutManager
+ binding.callsList.layoutManager = LinearLayoutManager(requireContext())
adapter.callLongClickedEvent.observe(viewLifecycleOwner) {
it.consume { model ->
diff --git a/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt b/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt
index 9af83ced8..dfd4a8601 100644
--- a/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt
+++ b/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt
@@ -541,6 +541,7 @@ class CurrentCallViewModel @UiThread constructor() : ViewModel() {
@UiThread
fun switchCamera() {
coreContext.postOnCoreThread {
+ Log.i("$TAG Switching camera")
coreContext.switchCamera()
}
}
diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt
index 1120430d1..b6e03fb25 100644
--- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt
@@ -162,9 +162,7 @@ class ConversationFragment : GenericFragment() {
adapter = ConversationEventAdapter(viewLifecycleOwner)
binding.eventsList.setHasFixedSize(true)
binding.eventsList.adapter = adapter
-
- val layoutManager = LinearLayoutManager(requireContext())
- binding.eventsList.layoutManager = layoutManager
+ binding.eventsList.layoutManager = LinearLayoutManager(requireContext())
bottomSheetAdapter = ChatMessageBottomSheetAdapter(viewLifecycleOwner)
binding.messageBottomSheet.bottomSheetList.setHasFixedSize(true)
diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt
index 8b98203d7..ceb97c465 100644
--- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt
@@ -63,8 +63,7 @@ class ConversationInfoFragment : GenericFragment() {
}
override fun goBack(): Boolean {
- findNavController().popBackStack()
- return true
+ return findNavController().popBackStack()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
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 cfaa975a4..b395db1d9 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
@@ -112,7 +112,8 @@ class ConversationsFragment : GenericFragment() {
sharedViewModel.showStartConversationEvent.observe(viewLifecycleOwner) {
it.consume {
Log.i("$TAG Navigating to start conversation fragment")
- findNavController().navigate(R.id.action_global_startConversationFragment)
+ val action = ConversationsFragmentDirections.actionConversationsFragmentToStartConversationFragment()
+ findNavController().navigate(action)
}
}
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 e0fa23d80..c4b1f9407 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
@@ -70,9 +70,7 @@ class ConversationsListFragment : AbstractTopBarFragment() {
adapter = ConversationsListAdapter(viewLifecycleOwner)
binding.conversationsList.setHasFixedSize(true)
binding.conversationsList.adapter = adapter
-
- val layoutManager = LinearLayoutManager(requireContext())
- binding.conversationsList.layoutManager = layoutManager
+ binding.conversationsList.layoutManager = LinearLayoutManager(requireContext())
adapter.conversationLongClickedEvent.observe(viewLifecycleOwner) {
it.consume { model ->
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 d0101a86e..21f5cdc27 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
@@ -114,8 +114,8 @@ class ContactsFragment : GenericFragment() {
) {
it.consume {
Log.i("$TAG Opening contact editor for creating new contact")
- val navController = findNavController()
- navController.navigate(R.id.action_global_newContactFragment)
+ val action = ContactsFragmentDirections.actionContactsFragmentToNewContactFragment()
+ findNavController().navigate(action)
}
}
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 a8c75ea18..f86914230 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
@@ -81,9 +81,7 @@ class ContactsListFragment : AbstractTopBarFragment() {
binding.contactsList.setHasFixedSize(true)
binding.contactsList.adapter = adapter
configureAdapter(adapter)
-
- val layoutManager = LinearLayoutManager(requireContext())
- binding.contactsList.layoutManager = layoutManager
+ binding.contactsList.layoutManager = LinearLayoutManager(requireContext())
favouritesAdapter = ContactsListAdapter(viewLifecycleOwner, favourites = true)
binding.favouritesContactsList.setHasFixedSize(true)
diff --git a/app/src/main/java/org/linphone/ui/main/fragment/AddParticipantsFragment.kt b/app/src/main/java/org/linphone/ui/main/fragment/AddParticipantsFragment.kt
index 31bb8928a..4a97b4aec 100644
--- a/app/src/main/java/org/linphone/ui/main/fragment/AddParticipantsFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/fragment/AddParticipantsFragment.kt
@@ -54,8 +54,7 @@ class AddParticipantsFragment : GenericAddressPickerFragment() {
}
override fun goBack(): Boolean {
- findNavController().popBackStack()
- return true
+ return findNavController().popBackStack()
}
override fun onSingleAddressSelected(address: Address, friend: Friend) {
diff --git a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryContactFragment.kt b/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryContactFragment.kt
index 05bf72037..8ec940adf 100644
--- a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryContactFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryContactFragment.kt
@@ -93,9 +93,7 @@ class HistoryContactFragment : GenericFragment() {
adapter = ContactHistoryListAdapter(viewLifecycleOwner)
binding.callHistory.setHasFixedSize(true)
binding.callHistory.adapter = adapter
-
- val layoutManager = LinearLayoutManager(requireContext())
- binding.callHistory.layoutManager = layoutManager
+ binding.callHistory.layoutManager = LinearLayoutManager(requireContext())
binding.setBackClickListener {
goBack()
diff --git a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryFragment.kt b/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryFragment.kt
index 22f625e96..3a319d82a 100644
--- a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryFragment.kt
@@ -99,7 +99,8 @@ class HistoryFragment : GenericFragment() {
sharedViewModel.showStartCallEvent.observe(viewLifecycleOwner) {
it.consume {
Log.i("$TAG Navigating to start call fragment")
- findNavController().navigate(R.id.action_global_startCallFragment)
+ val action = HistoryFragmentDirections.actionHistoryFragmentToStartCallFragment()
+ findNavController().navigate(action)
}
}
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 eef9372a6..615d95d35 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
@@ -80,9 +80,7 @@ class HistoryListFragment : AbstractTopBarFragment() {
adapter = HistoryListAdapter(viewLifecycleOwner)
binding.historyList.setHasFixedSize(true)
binding.historyList.adapter = adapter
-
- val layoutManager = LinearLayoutManager(requireContext())
- binding.historyList.layoutManager = layoutManager
+ binding.historyList.layoutManager = LinearLayoutManager(requireContext())
adapter.callLogLongClickedEvent.observe(viewLifecycleOwner) {
it.consume { model ->
diff --git a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingFragment.kt b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingFragment.kt
index a825529b9..caffb64d0 100644
--- a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingFragment.kt
@@ -79,9 +79,7 @@ class MeetingFragment : GenericFragment() {
binding.lifecycleOwner = viewLifecycleOwner
- viewModel = requireActivity().run {
- ViewModelProvider(this)[MeetingViewModel::class.java]
- }
+ viewModel = ViewModelProvider(this)[MeetingViewModel::class.java]
binding.viewModel = viewModel
val uri = args.conferenceUri
@@ -95,6 +93,7 @@ class MeetingFragment : GenericFragment() {
}
binding.setShareClickListener {
+ Log.i("$TAG Sharing conference info as Google Calendar event")
shareMeetingInfoAsCalendarEvent()
}
@@ -102,6 +101,12 @@ class MeetingFragment : GenericFragment() {
showPopupMenu()
}
+ binding.setJoinClickListener {
+ val conferenceUri = args.conferenceUri
+ Log.i("$TAG Requesting to go to waiting room for conference URI [$conferenceUri]")
+ sharedViewModel.goToMeetingWaitingRoomEvent.value = Event(conferenceUri)
+ }
+
sharedViewModel.isSlidingPaneSlideable.observe(viewLifecycleOwner) { slideable ->
viewModel.showBackButton.value = slideable
}
@@ -181,7 +186,7 @@ class MeetingFragment : GenericFragment() {
try {
startActivity(intent)
} catch (exception: ActivityNotFoundException) {
- Log.e("${MeetingFragment.TAG} No activity found to handle intent: $exception")
+ Log.e("$TAG No activity found to handle intent: $exception")
}
}
}
diff --git a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingWaitingRoomFragment.kt b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingWaitingRoomFragment.kt
new file mode 100644
index 000000000..bf3911337
--- /dev/null
+++ b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingWaitingRoomFragment.kt
@@ -0,0 +1,158 @@
+/*
+ * 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.meetings.fragment
+
+import android.Manifest
+import android.content.pm.PackageManager
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.annotation.UiThread
+import androidx.core.content.ContextCompat
+import androidx.core.view.doOnPreDraw
+import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.fragment.findNavController
+import androidx.navigation.fragment.navArgs
+import org.linphone.LinphoneApplication.Companion.coreContext
+import org.linphone.core.tools.Log
+import org.linphone.databinding.MeetingWaitingRoomFragmentBinding
+import org.linphone.ui.main.fragment.GenericFragment
+import org.linphone.ui.main.meetings.viewmodel.MeetingWaitingRoomViewModel
+
+@UiThread
+class MeetingWaitingRoomFragment : GenericFragment() {
+ companion object {
+ private const val TAG = "[Meeting Waiting Room Fragment]"
+ }
+
+ private lateinit var binding: MeetingWaitingRoomFragmentBinding
+
+ private lateinit var viewModel: MeetingWaitingRoomViewModel
+
+ private val args: MeetingWaitingRoomFragmentArgs by navArgs()
+
+ private val requestPermissionLauncher = registerForActivityResult(
+ ActivityResultContracts.RequestPermission()
+ ) { isGranted ->
+ if (isGranted) {
+ Log.i("$TAG Camera permission has been granted")
+ enableVideoPreview()
+ } else {
+ Log.e("$TAG Camera permission has been denied, leaving this fragment")
+ goBack()
+ }
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ binding = MeetingWaitingRoomFragmentBinding.inflate(layoutInflater)
+ return binding.root
+ }
+
+ override fun goBack(): Boolean {
+ return findNavController().popBackStack()
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ postponeEnterTransition()
+
+ binding.lifecycleOwner = viewLifecycleOwner
+
+ viewModel = ViewModelProvider(this)[MeetingWaitingRoomViewModel::class.java]
+ binding.viewModel = viewModel
+
+ val uri = args.conferenceUri
+ Log.i(
+ "$TAG Looking up for conference with SIP URI [$uri]"
+ )
+ viewModel.findConferenceInfo(uri)
+
+ binding.setBackClickListener {
+ goBack()
+ }
+
+ viewModel.conferenceInfoFoundEvent.observe(viewLifecycleOwner) {
+ it.consume { found ->
+ if (found) {
+ (view.parent as? ViewGroup)?.doOnPreDraw {
+ startPostponedEnterTransition()
+ }
+ } else {
+ Log.e("$TAG Failed to find meeting with URI [$uri], going back")
+ (view.parent as? ViewGroup)?.doOnPreDraw {
+ goBack()
+ }
+ }
+ }
+ }
+
+ if (!isCameraPermissionGranted()) {
+ viewModel.isVideoAvailable.value = false
+ Log.w("$TAG Camera permission wasn't granted yet, asking for it now")
+ requestPermissionLauncher.launch(Manifest.permission.CAMERA)
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+
+ if (isCameraPermissionGranted()) {
+ Log.i(
+ "$TAG Record video permission is granted, starting video preview with front cam if possible"
+ )
+ viewModel.setFrontCamera()
+ enableVideoPreview()
+ }
+ }
+
+ override fun onPause() {
+ coreContext.postOnCoreThread { core ->
+ core.nativePreviewWindowId = null
+ core.isVideoPreviewEnabled = false
+ }
+
+ super.onPause()
+ }
+
+ private fun isCameraPermissionGranted(): Boolean {
+ val granted = ContextCompat.checkSelfPermission(
+ requireContext(),
+ Manifest.permission.CAMERA
+ ) == PackageManager.PERMISSION_GRANTED
+ Log.i("$TAG Camera permission is ${if (granted) "granted" else "denied"}")
+ return granted
+ }
+
+ private fun enableVideoPreview() {
+ coreContext.postOnCoreThread { core ->
+ if (core.isVideoEnabled) {
+ viewModel.isVideoAvailable.postValue(true)
+ core.nativePreviewWindowId = binding.videoPreview
+ core.isVideoPreviewEnabled = true
+ }
+ }
+ }
+}
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 c0f89095d..e0e03f452 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
@@ -99,7 +99,18 @@ class MeetingsFragment : GenericFragment() {
sharedViewModel.showScheduleMeetingEvent.observe(viewLifecycleOwner) {
it.consume {
Log.i("$TAG Navigating to schedule meeting fragment")
- findNavController().navigate(R.id.action_global_scheduleMeetingFragment)
+ val action = MeetingsFragmentDirections.actionMeetingsFragmentToScheduleMeetingFragment()
+ findNavController().navigate(action)
+ }
+ }
+
+ sharedViewModel.goToMeetingWaitingRoomEvent.observe(viewLifecycleOwner) {
+ it.consume { uri ->
+ Log.i("$TAG Navigating to meeting waiting room fragment with URI [$uri]")
+ val action = MeetingsFragmentDirections.actionMeetingsFragmentToMeetingWaitingRoomFragment(
+ uri
+ )
+ findNavController().navigate(action)
}
}
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 ce50cd9a9..b097aebb7 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
@@ -75,9 +75,7 @@ class MeetingsListFragment : AbstractTopBarFragment() {
val headerItemDecoration = RecyclerViewHeaderDecoration(requireContext(), adapter, true)
binding.meetingsList.addItemDecoration(headerItemDecoration)
-
- val layoutManager = LinearLayoutManager(requireContext())
- binding.meetingsList.layoutManager = layoutManager
+ binding.meetingsList.layoutManager = LinearLayoutManager(requireContext())
binding.setNewMeetingClicked {
sharedViewModel.showScheduleMeetingEvent.value = Event(true)
diff --git a/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingViewModel.kt b/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingViewModel.kt
index 0bc31adfa..e1acada39 100644
--- a/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingViewModel.kt
+++ b/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingViewModel.kt
@@ -91,23 +91,21 @@ class MeetingViewModel @UiThread constructor() : ViewModel() {
if (address != null) {
val found = core.findConferenceInformationFromUri(address)
if (found != null) {
+ Log.i("$TAG Conference info with SIP URI [$uri] was found")
conferenceInfo = found
configureConferenceInfo()
conferenceInfoFoundEvent.postValue(Event(true))
} else {
+ Log.e("$TAG Conference info with SIP URI [$uri] couldn't be found!")
conferenceInfoFoundEvent.postValue(Event(false))
}
} else {
+ Log.e("$TAG Failed to parse SIP URI [$uri] as Address!")
conferenceInfoFoundEvent.postValue(Event(false))
}
}
}
- @UiThread
- fun join() {
- // TODO
- }
-
@UiThread
fun delete() {
coreContext.postOnCoreThread { core ->
@@ -181,7 +179,7 @@ class MeetingViewModel @UiThread constructor() : ViewModel() {
val participant = info.address
val isOrganizer = organizer?.weakEqual(participant) ?: false
Log.i(
- "$TAG Conference [${subject.value}] ${if (isOrganizer) "organizer" else "participant"} [${participant.asStringUriOnly()}] is a [${info.role}]"
+ "$TAG Conference [${conferenceInfo.subject}] ${if (isOrganizer) "organizer" else "participant"} [${participant.asStringUriOnly()}] is a [${info.role}]"
)
if (isOrganizer) {
organizerFound = true
diff --git a/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingWaitingRoomViewModel.kt b/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingWaitingRoomViewModel.kt
new file mode 100644
index 000000000..d9b06697b
--- /dev/null
+++ b/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingWaitingRoomViewModel.kt
@@ -0,0 +1,189 @@
+/*
+ * 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.meetings.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.core.ConferenceInfo
+import org.linphone.core.Factory
+import org.linphone.core.tools.Log
+import org.linphone.ui.main.contacts.model.ContactAvatarModel
+import org.linphone.utils.Event
+import org.linphone.utils.LinphoneUtils
+import org.linphone.utils.TimestampUtils
+
+class MeetingWaitingRoomViewModel @UiThread constructor() : ViewModel() {
+ companion object {
+ private const val TAG = "[Meeting Waiting Room ViewModel]"
+ }
+
+ val subject = MutableLiveData()
+
+ val dateTime = MutableLiveData()
+
+ val selfAvatar = MutableLiveData()
+
+ val isMicrophoneMuted = MutableLiveData()
+
+ val isVideoAvailable = MutableLiveData()
+
+ val isVideoEnabled = MutableLiveData()
+
+ val isSwitchCameraAvailable = MutableLiveData()
+
+ val conferenceInfoFoundEvent = MutableLiveData>()
+
+ private lateinit var conferenceInfo: ConferenceInfo
+
+ @UiThread
+ override fun onCleared() {
+ super.onCleared()
+ }
+
+ @UiThread
+ fun findConferenceInfo(uri: String) {
+ coreContext.postOnCoreThread { core ->
+ val address = Factory.instance().createAddress(uri)
+ if (address != null) {
+ val found = core.findConferenceInformationFromUri(address)
+ if (found != null) {
+ Log.i("$TAG Conference info with SIP URI [$uri] was found")
+ conferenceInfo = found
+ configureConferenceInfo()
+ configureWaitingRoom()
+ conferenceInfoFoundEvent.postValue(Event(true))
+ } else {
+ Log.e("$TAG Conference info with SIP URI [$uri] couldn't be found!")
+ conferenceInfoFoundEvent.postValue(Event(false))
+ }
+ } else {
+ Log.e("$TAG Failed to parse SIP URI [$uri] as Address!")
+ conferenceInfoFoundEvent.postValue(Event(false))
+ }
+ }
+ }
+
+ @UiThread
+ fun setFrontCamera() {
+ coreContext.postOnCoreThread { core ->
+ for (camera in core.videoDevicesList) {
+ if (camera.contains("Front")) {
+ Log.i("$TAG Found front facing camera [$camera], using it")
+ coreContext.core.videoDevice = camera
+ return@postOnCoreThread
+ }
+ }
+
+ val first = core.videoDevicesList.firstOrNull()
+ if (first != null) {
+ Log.w("$TAG No front facing camera found, using first one available [$first]")
+ coreContext.core.videoDevice = first
+ }
+ }
+ }
+
+ @UiThread
+ fun join() {
+ coreContext.postOnCoreThread { core ->
+ if (::conferenceInfo.isInitialized) {
+ val conferenceUri = conferenceInfo.uri
+ if (conferenceUri == null) {
+ Log.e("$TAG Conference Info doesn't have a conference SIP URI to call!")
+ return@postOnCoreThread
+ }
+
+ val params = core.createCallParams(null)
+ params ?: return@postOnCoreThread
+
+ params.isVideoEnabled = isVideoEnabled.value == true
+ params.isMicEnabled = isMicrophoneMuted.value == false
+ params.account = core.defaultAccount
+ coreContext.startCall(conferenceUri, params)
+ }
+ }
+ }
+
+ @UiThread
+ fun switchCamera() {
+ coreContext.postOnCoreThread {
+ Log.i("$TAG Switching camera")
+ coreContext.switchCamera()
+ }
+ }
+
+ @UiThread
+ fun toggleVideo() {
+ isVideoEnabled.value = isVideoEnabled.value == false
+ }
+
+ @UiThread
+ fun toggleMuteMicrophone() {
+ isMicrophoneMuted.value = isMicrophoneMuted.value == false
+ }
+
+ @UiThread
+ fun toggleSpeaker() {
+ // TODO
+ }
+
+ @WorkerThread
+ private fun configureConferenceInfo() {
+ if (::conferenceInfo.isInitialized) {
+ subject.postValue(conferenceInfo.subject)
+
+ val timestamp = conferenceInfo.dateTime
+ val duration = conferenceInfo.duration
+ val date = TimestampUtils.toString(
+ timestamp,
+ onlyDate = true,
+ shortDate = false,
+ hideYear = false
+ )
+ val startTime = TimestampUtils.timeToString(timestamp)
+ val end = timestamp + (duration * 60)
+ val endTime = TimestampUtils.timeToString(end)
+ dateTime.postValue("$date | $startTime - $endTime")
+
+ val localAddress = coreContext.core.defaultAccount?.params?.identityAddress
+ val fakeFriend = coreContext.core.createFriend()
+ fakeFriend.address = localAddress
+ fakeFriend.name = LinphoneUtils.getDisplayName(localAddress)
+ val avatarModel = ContactAvatarModel(fakeFriend)
+ selfAvatar.postValue(avatarModel)
+ }
+ }
+
+ @WorkerThread
+ private fun configureWaitingRoom() {
+ val core = coreContext.core
+
+ isVideoEnabled.postValue(
+ core.isVideoEnabled && core.videoActivationPolicy.automaticallyInitiate
+ )
+ isSwitchCameraAvailable.postValue(coreContext.showSwitchCameraButton())
+
+ isMicrophoneMuted.postValue(!core.isMicEnabled)
+
+ // TODO: audio routes
+ }
+}
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 59ab0f426..64d83ae13 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
@@ -48,8 +48,7 @@ class AccountSettingsFragment : GenericFragment() {
}
override fun goBack(): Boolean {
- findNavController().popBackStack()
- return true
+ return findNavController().popBackStack()
}
override fun onCreateView(
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 d2cc5a364..dca355c74 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
@@ -123,6 +123,10 @@ class SharedMainViewModel @UiThread constructor() : ViewModel() {
MutableLiveData>()
}
+ val goToMeetingWaitingRoomEvent: MutableLiveData> by lazy {
+ MutableLiveData>()
+ }
+
/* Other */
val listOfSelectedSipUrisEvent: MutableLiveData>> by lazy {
diff --git a/app/src/main/res/drawable/shape_squircle_gray_2_background.xml b/app/src/main/res/drawable/shape_squircle_gray_100_background.xml
similarity index 100%
rename from app/src/main/res/drawable/shape_squircle_gray_2_background.xml
rename to app/src/main/res/drawable/shape_squircle_gray_100_background.xml
diff --git a/app/src/main/res/drawable/shape_squircle_gray_600_background.xml b/app/src/main/res/drawable/shape_squircle_gray_600_background.xml
new file mode 100644
index 000000000..deffe1a5e
--- /dev/null
+++ b/app/src/main/res/drawable/shape_squircle_gray_600_background.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/account_profile_device_list_cell.xml b/app/src/main/res/layout/account_profile_device_list_cell.xml
index b76e21414..94ff83b0b 100644
--- a/app/src/main/res/layout/account_profile_device_list_cell.xml
+++ b/app/src/main/res/layout/account_profile_device_list_cell.xml
@@ -15,7 +15,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:paddingBottom="27dp"
- android:background="@drawable/shape_squircle_gray_2_background">
+ android:background="@drawable/shape_squircle_gray_100_background">
+
@@ -198,7 +201,6 @@
android:layout_height="1dp"
android:layout_marginTop="16dp"
android:background="@color/gray_main2_200"
- android:visibility="@{viewModel.description.length() > 0 ? View.VISIBLE : View.GONE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/timezone" />
@@ -230,10 +232,18 @@
android:layout_height="1dp"
android:layout_marginTop="16dp"
android:background="@color/gray_main2_200"
+ android:visibility="@{viewModel.description.length() > 0 ? View.VISIBLE : View.GONE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/description" />
+
+
+ app:layout_constraintTop_toBottomOf="@id/speakers_bottom_barrier" />
+
+
+ app:layout_constraintTop_toBottomOf="@id/participants_bottom_barrier" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/main_nav_graph.xml b/app/src/main/res/navigation/main_nav_graph.xml
index 4154193d0..b5f6862ba 100644
--- a/app/src/main/res/navigation/main_nav_graph.xml
+++ b/app/src/main/res/navigation/main_nav_graph.xml
@@ -29,6 +29,12 @@
app:launchSingleTop="true"
app:popUpTo="@id/contactsFragment"
app:popUpToInclusive="true" />
+
+
-
-
-
-
+
-
-
+
+
-
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 07525e52c..6f4c0e9fc 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -394,6 +394,8 @@
Delete meeting
Meeting has been deleted
+ Join
+
Operation in progress, please wait
Transfer