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:
Sylvain Berfini 2022-03-28 14:41:47 +02:00
parent aff768548a
commit f4c89fbb2c
8 changed files with 106 additions and 31 deletions

View file

@ -50,6 +50,10 @@ class ScheduledConferencesAdapter(
MutableLiveData<Event<Pair<String, String?>>>()
}
val editConferenceEvent: MutableLiveData<Event<String>> by lazy {
MutableLiveData<Event<String>>()
}
val deleteConferenceInfoEvent: MutableLiveData<Event<ScheduledConferenceData>> by lazy {
MutableLiveData<Event<ScheduledConferenceData>>()
}
@ -117,6 +121,13 @@ class ScheduledConferencesAdapter(
}
}
setEditConferenceClickListener {
val address = conferenceData.conferenceInfo.uri
if (address != null) {
editConferenceEvent.value = Event(address.asStringUriOnly())
}
}
setDeleteConferenceClickListener {
deleteConferenceInfoEvent.value = Event(conferenceData)
}

View file

@ -37,6 +37,7 @@ class ScheduledConferenceData(val conferenceInfo: ConferenceInfo) {
val date = MutableLiveData<String>()
val duration = MutableLiveData<String>()
val organizer = MutableLiveData<String>()
val canEdit = MutableLiveData<Boolean>()
val participantsShort = MutableLiveData<String>()
val participantsExpanded = MutableLiveData<String>()
val showDuration = MutableLiveData<Boolean>()
@ -59,12 +60,19 @@ class ScheduledConferenceData(val conferenceInfo: ConferenceInfo) {
val organizerAddress = conferenceInfo.organizer
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)
organizer.value = if (contact != null)
contact.fullName
else
LinphoneUtils.getDisplayName(conferenceInfo.organizer)
} else {
canEdit.value = false
Log.e("[Scheduled Conference] No organizer SIP URI found for: ${conferenceInfo.uri?.asStringUriOnly()}")
}

View file

@ -22,20 +22,26 @@ package org.linphone.activities.main.conference.fragments
import android.os.Bundle
import android.text.format.DateFormat.is24HourFormat
import android.view.View
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.navGraphViewModels
import com.google.android.material.datepicker.CalendarConstraints
import com.google.android.material.datepicker.DateValidatorPointForward
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.timepicker.MaterialTimePicker
import com.google.android.material.timepicker.TimeFormat
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.R
import org.linphone.activities.GenericFragment
import org.linphone.activities.main.conference.viewmodels.ConferenceSchedulingViewModel
import org.linphone.activities.main.viewmodels.SharedMainViewModel
import org.linphone.activities.navigateToParticipantsList
import org.linphone.core.Factory
import org.linphone.core.tools.Log
import org.linphone.databinding.ConferenceSchedulingFragmentBinding
class ConferenceSchedulingFragment : GenericFragment<ConferenceSchedulingFragmentBinding>() {
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
@ -46,6 +52,29 @@ class ConferenceSchedulingFragment : GenericFragment<ConferenceSchedulingFragmen
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 {
goBack()
}

View file

@ -33,16 +33,19 @@ import org.linphone.activities.main.MainActivity
import org.linphone.activities.main.conference.adapters.ScheduledConferencesAdapter
import org.linphone.activities.main.conference.viewmodels.ScheduledConferencesViewModel
import org.linphone.activities.main.viewmodels.DialogViewModel
import org.linphone.activities.main.viewmodels.SharedMainViewModel
import org.linphone.activities.navigateToConferenceScheduling
import org.linphone.activities.navigateToConferenceWaitingRoom
import org.linphone.databinding.ConferencesScheduledFragmentBinding
import org.linphone.utils.AppUtils
import org.linphone.utils.DialogUtils
import org.linphone.utils.Event
import org.linphone.utils.RecyclerViewHeaderDecoration
class ScheduledConferencesFragment : GenericFragment<ConferencesScheduledFragmentBinding>() {
private lateinit var viewModel: ScheduledConferencesViewModel
private lateinit var adapter: ScheduledConferencesAdapter
private lateinit var sharedViewModel: SharedMainViewModel
override fun getLayoutId(): Int = R.layout.conferences_scheduled_fragment
@ -63,6 +66,10 @@ class ScheduledConferencesFragment : GenericFragment<ConferencesScheduledFragmen
)
binding.conferenceInfoList.adapter = adapter
sharedViewModel = requireActivity().run {
ViewModelProvider(this)[SharedMainViewModel::class.java]
}
val layoutManager = LinearLayoutManager(activity)
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(
viewLifecycleOwner
) {

View file

@ -69,20 +69,9 @@ class ConferenceSchedulingViewModel : ContactsSelectionViewModel() {
var hour: Int = 0
var minutes: Int = 0
private var confInfo: ConferenceInfo? = null
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() {
override fun onStateChanged(
conferenceScheduler: ConferenceScheduler,
@ -179,6 +168,30 @@ class ConferenceSchedulingViewModel : ContactsSelectionViewModel() {
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() {
scheduleForLater.value = scheduleForLater.value == false
}
@ -221,23 +234,10 @@ class ConferenceSchedulingViewModel : ContactsSelectionViewModel() {
val core = coreContext.core
val participants = arrayOfNulls<Address>(selectedAddresses.value.orEmpty().size)
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 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()
val conferenceInfo = confInfo ?: Factory.instance().createConferenceInfo()
conferenceInfo.organizer = localAddress
conferenceInfo.subject = subject.value
conferenceInfo.description = description.value
@ -248,7 +248,10 @@ class ConferenceSchedulingViewModel : ContactsSelectionViewModel() {
val duration = duration.value?.value ?: 0
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> {

View file

@ -38,6 +38,7 @@ class ScheduledConferencesViewModel : ViewModel() {
conferencesList.addAll(conferences.value.orEmpty())
val data = ScheduledConferenceData(conferenceInfo)
conferencesList.add(data)
conferencesList.sortBy { it.conferenceInfo.dateTime }
conferences.value = conferencesList
}
}

View file

@ -95,6 +95,12 @@ class SharedMainViewModel : ViewModel() {
var pendingCallTransfer: Boolean = false
/* Conference */
val conferenceInfoToEdit: MutableLiveData<Event<String>> by lazy {
MutableLiveData<Event<String>>()
}
/* Dialer */
var dialerUri: String = ""

View file

@ -95,7 +95,7 @@
android:visibility="@{data.expanded ? View.GONE : View.VISIBLE}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="10dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
@ -125,6 +125,7 @@
android:visibility="@{data.expanded ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp">
@ -255,7 +256,7 @@
<ImageView
android:onClick="@{editConferenceClickListener}"
android:visibility="gone"
android:visibility="@{data.canEdit ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"