Show conference edit button in schedule list for organizer + allow to edit conference + sort conferences by date when notified of a new conference schedule by callback while in conferences list view
This commit is contained in:
parent
aff768548a
commit
f4c89fbb2c
8 changed files with 106 additions and 31 deletions
|
@ -50,6 +50,10 @@ class ScheduledConferencesAdapter(
|
||||||
MutableLiveData<Event<Pair<String, String?>>>()
|
MutableLiveData<Event<Pair<String, String?>>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val editConferenceEvent: MutableLiveData<Event<String>> by lazy {
|
||||||
|
MutableLiveData<Event<String>>()
|
||||||
|
}
|
||||||
|
|
||||||
val deleteConferenceInfoEvent: MutableLiveData<Event<ScheduledConferenceData>> by lazy {
|
val deleteConferenceInfoEvent: MutableLiveData<Event<ScheduledConferenceData>> by lazy {
|
||||||
MutableLiveData<Event<ScheduledConferenceData>>()
|
MutableLiveData<Event<ScheduledConferenceData>>()
|
||||||
}
|
}
|
||||||
|
@ -117,6 +121,13 @@ class ScheduledConferencesAdapter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setEditConferenceClickListener {
|
||||||
|
val address = conferenceData.conferenceInfo.uri
|
||||||
|
if (address != null) {
|
||||||
|
editConferenceEvent.value = Event(address.asStringUriOnly())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setDeleteConferenceClickListener {
|
setDeleteConferenceClickListener {
|
||||||
deleteConferenceInfoEvent.value = Event(conferenceData)
|
deleteConferenceInfoEvent.value = Event(conferenceData)
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ class ScheduledConferenceData(val conferenceInfo: ConferenceInfo) {
|
||||||
val date = MutableLiveData<String>()
|
val date = MutableLiveData<String>()
|
||||||
val duration = MutableLiveData<String>()
|
val duration = MutableLiveData<String>()
|
||||||
val organizer = MutableLiveData<String>()
|
val organizer = MutableLiveData<String>()
|
||||||
|
val canEdit = MutableLiveData<Boolean>()
|
||||||
val participantsShort = MutableLiveData<String>()
|
val participantsShort = MutableLiveData<String>()
|
||||||
val participantsExpanded = MutableLiveData<String>()
|
val participantsExpanded = MutableLiveData<String>()
|
||||||
val showDuration = MutableLiveData<Boolean>()
|
val showDuration = MutableLiveData<Boolean>()
|
||||||
|
@ -59,12 +60,19 @@ class ScheduledConferenceData(val conferenceInfo: ConferenceInfo) {
|
||||||
|
|
||||||
val organizerAddress = conferenceInfo.organizer
|
val organizerAddress = conferenceInfo.organizer
|
||||||
if (organizerAddress != null) {
|
if (organizerAddress != null) {
|
||||||
|
val localAccount = coreContext.core.accountList.find { account ->
|
||||||
|
val address = account.params.identityAddress
|
||||||
|
address != null && organizerAddress.weakEqual(address)
|
||||||
|
}
|
||||||
|
canEdit.value = localAccount != null
|
||||||
|
|
||||||
val contact = coreContext.contactsManager.findContactByAddress(organizerAddress)
|
val contact = coreContext.contactsManager.findContactByAddress(organizerAddress)
|
||||||
organizer.value = if (contact != null)
|
organizer.value = if (contact != null)
|
||||||
contact.fullName
|
contact.fullName
|
||||||
else
|
else
|
||||||
LinphoneUtils.getDisplayName(conferenceInfo.organizer)
|
LinphoneUtils.getDisplayName(conferenceInfo.organizer)
|
||||||
} else {
|
} else {
|
||||||
|
canEdit.value = false
|
||||||
Log.e("[Scheduled Conference] No organizer SIP URI found for: ${conferenceInfo.uri?.asStringUriOnly()}")
|
Log.e("[Scheduled Conference] No organizer SIP URI found for: ${conferenceInfo.uri?.asStringUriOnly()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,20 +22,26 @@ package org.linphone.activities.main.conference.fragments
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.format.DateFormat.is24HourFormat
|
import android.text.format.DateFormat.is24HourFormat
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.navigation.navGraphViewModels
|
import androidx.navigation.navGraphViewModels
|
||||||
import com.google.android.material.datepicker.CalendarConstraints
|
import com.google.android.material.datepicker.CalendarConstraints
|
||||||
import com.google.android.material.datepicker.DateValidatorPointForward
|
import com.google.android.material.datepicker.DateValidatorPointForward
|
||||||
import com.google.android.material.datepicker.MaterialDatePicker
|
import com.google.android.material.datepicker.MaterialDatePicker
|
||||||
import com.google.android.material.timepicker.MaterialTimePicker
|
import com.google.android.material.timepicker.MaterialTimePicker
|
||||||
import com.google.android.material.timepicker.TimeFormat
|
import com.google.android.material.timepicker.TimeFormat
|
||||||
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.activities.GenericFragment
|
import org.linphone.activities.GenericFragment
|
||||||
import org.linphone.activities.main.conference.viewmodels.ConferenceSchedulingViewModel
|
import org.linphone.activities.main.conference.viewmodels.ConferenceSchedulingViewModel
|
||||||
|
import org.linphone.activities.main.viewmodels.SharedMainViewModel
|
||||||
import org.linphone.activities.navigateToParticipantsList
|
import org.linphone.activities.navigateToParticipantsList
|
||||||
|
import org.linphone.core.Factory
|
||||||
|
import org.linphone.core.tools.Log
|
||||||
import org.linphone.databinding.ConferenceSchedulingFragmentBinding
|
import org.linphone.databinding.ConferenceSchedulingFragmentBinding
|
||||||
|
|
||||||
class ConferenceSchedulingFragment : GenericFragment<ConferenceSchedulingFragmentBinding>() {
|
class ConferenceSchedulingFragment : GenericFragment<ConferenceSchedulingFragmentBinding>() {
|
||||||
private val viewModel: ConferenceSchedulingViewModel by navGraphViewModels(R.id.conference_scheduling_nav_graph)
|
private val viewModel: ConferenceSchedulingViewModel by navGraphViewModels(R.id.conference_scheduling_nav_graph)
|
||||||
|
private lateinit var sharedViewModel: SharedMainViewModel
|
||||||
|
|
||||||
override fun getLayoutId(): Int = R.layout.conference_scheduling_fragment
|
override fun getLayoutId(): Int = R.layout.conference_scheduling_fragment
|
||||||
|
|
||||||
|
@ -46,6 +52,29 @@ class ConferenceSchedulingFragment : GenericFragment<ConferenceSchedulingFragmen
|
||||||
|
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
sharedViewModel = requireActivity().run {
|
||||||
|
ViewModelProvider(this)[SharedMainViewModel::class.java]
|
||||||
|
}
|
||||||
|
|
||||||
|
sharedViewModel.conferenceInfoToEdit.observe(
|
||||||
|
viewLifecycleOwner
|
||||||
|
) {
|
||||||
|
it.consume { address ->
|
||||||
|
val conferenceAddress = Factory.instance().createAddress(address)
|
||||||
|
if (conferenceAddress != null) {
|
||||||
|
Log.i("[Conference Scheduling] Trying to edit conference info using address: $address")
|
||||||
|
val conferenceInfo = coreContext.core.findConferenceInformationFromUri(conferenceAddress)
|
||||||
|
if (conferenceInfo != null) {
|
||||||
|
viewModel.populateFromConferenceInfo(conferenceInfo)
|
||||||
|
} else {
|
||||||
|
Log.e("[Conference Scheduling] Failed to find ConferenceInfo matching address: $address")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.e("[Conference Scheduling] Failed to parse conference address: $address")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.setBackClickListener {
|
binding.setBackClickListener {
|
||||||
goBack()
|
goBack()
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,16 +33,19 @@ import org.linphone.activities.main.MainActivity
|
||||||
import org.linphone.activities.main.conference.adapters.ScheduledConferencesAdapter
|
import org.linphone.activities.main.conference.adapters.ScheduledConferencesAdapter
|
||||||
import org.linphone.activities.main.conference.viewmodels.ScheduledConferencesViewModel
|
import org.linphone.activities.main.conference.viewmodels.ScheduledConferencesViewModel
|
||||||
import org.linphone.activities.main.viewmodels.DialogViewModel
|
import org.linphone.activities.main.viewmodels.DialogViewModel
|
||||||
|
import org.linphone.activities.main.viewmodels.SharedMainViewModel
|
||||||
import org.linphone.activities.navigateToConferenceScheduling
|
import org.linphone.activities.navigateToConferenceScheduling
|
||||||
import org.linphone.activities.navigateToConferenceWaitingRoom
|
import org.linphone.activities.navigateToConferenceWaitingRoom
|
||||||
import org.linphone.databinding.ConferencesScheduledFragmentBinding
|
import org.linphone.databinding.ConferencesScheduledFragmentBinding
|
||||||
import org.linphone.utils.AppUtils
|
import org.linphone.utils.AppUtils
|
||||||
import org.linphone.utils.DialogUtils
|
import org.linphone.utils.DialogUtils
|
||||||
|
import org.linphone.utils.Event
|
||||||
import org.linphone.utils.RecyclerViewHeaderDecoration
|
import org.linphone.utils.RecyclerViewHeaderDecoration
|
||||||
|
|
||||||
class ScheduledConferencesFragment : GenericFragment<ConferencesScheduledFragmentBinding>() {
|
class ScheduledConferencesFragment : GenericFragment<ConferencesScheduledFragmentBinding>() {
|
||||||
private lateinit var viewModel: ScheduledConferencesViewModel
|
private lateinit var viewModel: ScheduledConferencesViewModel
|
||||||
private lateinit var adapter: ScheduledConferencesAdapter
|
private lateinit var adapter: ScheduledConferencesAdapter
|
||||||
|
private lateinit var sharedViewModel: SharedMainViewModel
|
||||||
|
|
||||||
override fun getLayoutId(): Int = R.layout.conferences_scheduled_fragment
|
override fun getLayoutId(): Int = R.layout.conferences_scheduled_fragment
|
||||||
|
|
||||||
|
@ -63,6 +66,10 @@ class ScheduledConferencesFragment : GenericFragment<ConferencesScheduledFragmen
|
||||||
)
|
)
|
||||||
binding.conferenceInfoList.adapter = adapter
|
binding.conferenceInfoList.adapter = adapter
|
||||||
|
|
||||||
|
sharedViewModel = requireActivity().run {
|
||||||
|
ViewModelProvider(this)[SharedMainViewModel::class.java]
|
||||||
|
}
|
||||||
|
|
||||||
val layoutManager = LinearLayoutManager(activity)
|
val layoutManager = LinearLayoutManager(activity)
|
||||||
binding.conferenceInfoList.layoutManager = layoutManager
|
binding.conferenceInfoList.layoutManager = layoutManager
|
||||||
|
|
||||||
|
@ -97,6 +104,15 @@ class ScheduledConferencesFragment : GenericFragment<ConferencesScheduledFragmen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adapter.editConferenceEvent.observe(
|
||||||
|
viewLifecycleOwner
|
||||||
|
) {
|
||||||
|
it.consume { address ->
|
||||||
|
sharedViewModel.conferenceInfoToEdit.value = Event(address)
|
||||||
|
navigateToConferenceScheduling()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
adapter.deleteConferenceInfoEvent.observe(
|
adapter.deleteConferenceInfoEvent.observe(
|
||||||
viewLifecycleOwner
|
viewLifecycleOwner
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -69,20 +69,9 @@ class ConferenceSchedulingViewModel : ContactsSelectionViewModel() {
|
||||||
var hour: Int = 0
|
var hour: Int = 0
|
||||||
var minutes: Int = 0
|
var minutes: Int = 0
|
||||||
|
|
||||||
|
private var confInfo: ConferenceInfo? = null
|
||||||
private val conferenceScheduler = coreContext.core.createConferenceScheduler()
|
private val conferenceScheduler = coreContext.core.createConferenceScheduler()
|
||||||
|
|
||||||
private val chatRoomListener = object : ChatRoomListenerStub() {
|
|
||||||
override fun onStateChanged(room: ChatRoom, state: ChatRoom.State) {
|
|
||||||
if (state == ChatRoom.State.Created) {
|
|
||||||
Log.i("[Conference Creation] Chat room created")
|
|
||||||
room.removeListener(this)
|
|
||||||
} else if (state == ChatRoom.State.CreationFailed) {
|
|
||||||
Log.e("[Conference Creation] Group chat room creation has failed !")
|
|
||||||
room.removeListener(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val listener = object : ConferenceSchedulerListenerStub() {
|
private val listener = object : ConferenceSchedulerListenerStub() {
|
||||||
override fun onStateChanged(
|
override fun onStateChanged(
|
||||||
conferenceScheduler: ConferenceScheduler,
|
conferenceScheduler: ConferenceScheduler,
|
||||||
|
@ -179,6 +168,30 @@ class ConferenceSchedulingViewModel : ContactsSelectionViewModel() {
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun populateFromConferenceInfo(conferenceInfo: ConferenceInfo) {
|
||||||
|
confInfo = conferenceInfo
|
||||||
|
address.value = conferenceInfo.uri
|
||||||
|
subject.value = conferenceInfo.subject
|
||||||
|
description.value = conferenceInfo.description
|
||||||
|
|
||||||
|
val dateTime = conferenceInfo.dateTime
|
||||||
|
val calendar = Calendar.getInstance()
|
||||||
|
calendar.timeInMillis = dateTime * 1000
|
||||||
|
setDate(calendar.timeInMillis)
|
||||||
|
setTime(calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE))
|
||||||
|
|
||||||
|
val conferenceDuration = conferenceInfo.duration
|
||||||
|
duration.value = durationList.find { it.value == conferenceDuration }
|
||||||
|
scheduleForLater.value = conferenceDuration > 0
|
||||||
|
|
||||||
|
val participantsList = arrayListOf<Address>()
|
||||||
|
for (participant in conferenceInfo.participants) {
|
||||||
|
participantsList.add(participant)
|
||||||
|
}
|
||||||
|
selectedAddresses.value = participantsList
|
||||||
|
computeParticipantsData()
|
||||||
|
}
|
||||||
|
|
||||||
fun toggleSchedule() {
|
fun toggleSchedule() {
|
||||||
scheduleForLater.value = scheduleForLater.value == false
|
scheduleForLater.value = scheduleForLater.value == false
|
||||||
}
|
}
|
||||||
|
@ -221,23 +234,10 @@ class ConferenceSchedulingViewModel : ContactsSelectionViewModel() {
|
||||||
val core = coreContext.core
|
val core = coreContext.core
|
||||||
val participants = arrayOfNulls<Address>(selectedAddresses.value.orEmpty().size)
|
val participants = arrayOfNulls<Address>(selectedAddresses.value.orEmpty().size)
|
||||||
selectedAddresses.value?.toArray(participants)
|
selectedAddresses.value?.toArray(participants)
|
||||||
val localAddress = core.defaultAccount?.params?.identityAddress
|
val localAccount = core.defaultAccount
|
||||||
|
val localAddress = localAccount?.params?.identityAddress
|
||||||
|
|
||||||
// TODO: Temporary workaround for chat room, to be removed once we can get matching chat room from conference
|
val conferenceInfo = confInfo ?: Factory.instance().createConferenceInfo()
|
||||||
/*val chatRoomParams = core.createDefaultChatRoomParams()
|
|
||||||
chatRoomParams.backend = ChatRoomBackend.FlexisipChat
|
|
||||||
chatRoomParams.enableGroup(true)
|
|
||||||
chatRoomParams.subject = subject.value
|
|
||||||
val chatRoom = core.createChatRoom(chatRoomParams, localAddress, participants)
|
|
||||||
if (chatRoom == null) {
|
|
||||||
Log.e("[Conference Creation] Failed to create a chat room with same subject & participants as for conference")
|
|
||||||
} else {
|
|
||||||
Log.i("[Conference Creation] Creating chat room with same subject [${subject.value}] & participants as for conference")
|
|
||||||
chatRoom.addListener(chatRoomListener)
|
|
||||||
}*/
|
|
||||||
// END OF TODO
|
|
||||||
|
|
||||||
val conferenceInfo = Factory.instance().createConferenceInfo()
|
|
||||||
conferenceInfo.organizer = localAddress
|
conferenceInfo.organizer = localAddress
|
||||||
conferenceInfo.subject = subject.value
|
conferenceInfo.subject = subject.value
|
||||||
conferenceInfo.description = description.value
|
conferenceInfo.description = description.value
|
||||||
|
@ -248,7 +248,10 @@ class ConferenceSchedulingViewModel : ContactsSelectionViewModel() {
|
||||||
val duration = duration.value?.value ?: 0
|
val duration = duration.value?.value ?: 0
|
||||||
conferenceInfo.duration = duration
|
conferenceInfo.duration = duration
|
||||||
}
|
}
|
||||||
conferenceScheduler.info = conferenceInfo // Will trigger the conference creation automatically
|
confInfo = conferenceInfo
|
||||||
|
conferenceScheduler.account = localAccount
|
||||||
|
// Will trigger the conference creation/update automatically
|
||||||
|
conferenceScheduler.info = conferenceInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun computeTimeZonesList(): List<TimeZoneData> {
|
private fun computeTimeZonesList(): List<TimeZoneData> {
|
||||||
|
|
|
@ -38,6 +38,7 @@ class ScheduledConferencesViewModel : ViewModel() {
|
||||||
conferencesList.addAll(conferences.value.orEmpty())
|
conferencesList.addAll(conferences.value.orEmpty())
|
||||||
val data = ScheduledConferenceData(conferenceInfo)
|
val data = ScheduledConferenceData(conferenceInfo)
|
||||||
conferencesList.add(data)
|
conferencesList.add(data)
|
||||||
|
conferencesList.sortBy { it.conferenceInfo.dateTime }
|
||||||
conferences.value = conferencesList
|
conferences.value = conferencesList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,12 @@ class SharedMainViewModel : ViewModel() {
|
||||||
|
|
||||||
var pendingCallTransfer: Boolean = false
|
var pendingCallTransfer: Boolean = false
|
||||||
|
|
||||||
|
/* Conference */
|
||||||
|
|
||||||
|
val conferenceInfoToEdit: MutableLiveData<Event<String>> by lazy {
|
||||||
|
MutableLiveData<Event<String>>()
|
||||||
|
}
|
||||||
|
|
||||||
/* Dialer */
|
/* Dialer */
|
||||||
|
|
||||||
var dialerUri: String = ""
|
var dialerUri: String = ""
|
||||||
|
|
|
@ -95,7 +95,7 @@
|
||||||
android:visibility="@{data.expanded ? View.GONE : View.VISIBLE}"
|
android:visibility="@{data.expanded ? View.GONE : View.VISIBLE}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="5dp"
|
||||||
android:layout_marginBottom="10dp"
|
android:layout_marginBottom="10dp"
|
||||||
android:layout_marginStart="5dp"
|
android:layout_marginStart="5dp"
|
||||||
android:layout_marginEnd="5dp"
|
android:layout_marginEnd="5dp"
|
||||||
|
@ -125,6 +125,7 @@
|
||||||
android:visibility="@{data.expanded ? View.VISIBLE : View.GONE, default=gone}"
|
android:visibility="@{data.expanded ? View.VISIBLE : View.GONE, default=gone}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
android:layout_marginStart="5dp"
|
android:layout_marginStart="5dp"
|
||||||
android:layout_marginEnd="5dp">
|
android:layout_marginEnd="5dp">
|
||||||
|
|
||||||
|
@ -255,7 +256,7 @@
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:onClick="@{editConferenceClickListener}"
|
android:onClick="@{editConferenceClickListener}"
|
||||||
android:visibility="gone"
|
android:visibility="@{data.canEdit ? View.VISIBLE : View.GONE, default=gone}"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
|
|
Loading…
Reference in a new issue