Allow to long press conference info to select many of them & delete them at once + show cancelled conferences differently in meeting tab

This commit is contained in:
Sylvain Berfini 2022-09-05 15:06:57 +02:00
parent 31ef42c829
commit 77331e9b94
18 changed files with 154 additions and 27 deletions

View file

@ -27,10 +27,11 @@ import androidx.databinding.DataBindingUtil
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.linphone.R
import org.linphone.activities.main.adapters.SelectionListAdapter
import org.linphone.activities.main.conference.data.ScheduledConferenceData
import org.linphone.activities.main.viewmodels.ListTopBarViewModel
import org.linphone.databinding.ConferenceScheduleCellBinding
import org.linphone.databinding.ConferenceScheduleListHeaderBinding
import org.linphone.utils.Event
@ -38,8 +39,9 @@ import org.linphone.utils.HeaderAdapter
import org.linphone.utils.TimestampUtils
class ScheduledConferencesAdapter(
selectionVM: ListTopBarViewModel,
private val viewLifecycleOwner: LifecycleOwner
) : ListAdapter<ScheduledConferenceData, RecyclerView.ViewHolder>(ConferenceInfoDiffCallback()),
) : SelectionListAdapter<ScheduledConferenceData, RecyclerView.ViewHolder>(selectionVM, ConferenceInfoDiffCallback()),
HeaderAdapter {
val copyAddressToClipboardEvent: MutableLiveData<Event<String>> by lazy {
MutableLiveData<Event<String>>()
@ -106,6 +108,31 @@ class ScheduledConferencesAdapter(
lifecycleOwner = viewLifecycleOwner
// This is for item selection through ListTopBarFragment
selectionListViewModel = selectionViewModel
selectionViewModel.isEditionEnabled.observe(
viewLifecycleOwner
) {
position = bindingAdapterPosition
}
setClickListener {
if (selectionViewModel.isEditionEnabled.value == true) {
selectionViewModel.onToggleSelect(bindingAdapterPosition)
} else {
conferenceData.toggleExpand()
}
}
setLongClickListener {
if (selectionViewModel.isEditionEnabled.value == false) {
selectionViewModel.isEditionEnabled.value = true
// Selection will be handled by click listener
true
}
false
}
setCopyAddressClickListener {
val address = conferenceData.getAddressAsString()
if (address.isNotEmpty()) {

View file

@ -107,7 +107,13 @@ class ScheduledConferenceData(val conferenceInfo: ConferenceInfo, private val is
}
private fun computeBackgroundResId() {
backgroundResId.value = if (isFinished) {
backgroundResId.value = if (conferenceInfo.state == ConferenceInfoState.Cancelled) {
if (expanded.value == true) {
R.drawable.shape_round_red_background_with_orange_border
} else {
R.drawable.shape_round_red_background
}
} else if (isFinished) {
if (expanded.value == true) {
R.drawable.shape_round_dark_gray_background_with_orange_border
} else {

View file

@ -28,10 +28,11 @@ import android.view.View
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import org.linphone.R
import org.linphone.activities.GenericFragment
import org.linphone.activities.main.MainActivity
import org.linphone.activities.main.conference.adapters.ScheduledConferencesAdapter
import org.linphone.activities.main.conference.data.ScheduledConferenceData
import org.linphone.activities.main.conference.viewmodels.ScheduledConferencesViewModel
import org.linphone.activities.main.fragments.MasterFragment
import org.linphone.activities.main.viewmodels.DialogViewModel
import org.linphone.activities.navigateToConferenceScheduling
import org.linphone.activities.navigateToConferenceWaitingRoom
@ -41,9 +42,9 @@ import org.linphone.utils.DialogUtils
import org.linphone.utils.Event
import org.linphone.utils.RecyclerViewHeaderDecoration
class ScheduledConferencesFragment : GenericFragment<ConferencesScheduledFragmentBinding>() {
class ScheduledConferencesFragment : MasterFragment<ConferencesScheduledFragmentBinding, ScheduledConferencesAdapter>() {
override val dialogConfirmationMessageBeforeRemoval = R.plurals.conference_scheduled_delete_dialog
private lateinit var viewModel: ScheduledConferencesViewModel
private lateinit var adapter: ScheduledConferencesAdapter
override fun getLayoutId(): Int = R.layout.conferences_scheduled_fragment
@ -59,9 +60,7 @@ class ScheduledConferencesFragment : GenericFragment<ConferencesScheduledFragmen
)[ScheduledConferencesViewModel::class.java]
binding.viewModel = viewModel
adapter = ScheduledConferencesAdapter(
viewLifecycleOwner
)
_adapter = ScheduledConferencesAdapter(listSelectionViewModel, viewLifecycleOwner)
binding.conferenceInfoList.adapter = adapter
val layoutManager = LinearLayoutManager(requireContext())
@ -112,7 +111,7 @@ class ScheduledConferencesFragment : GenericFragment<ConferencesScheduledFragmen
) {
it.consume { data ->
val dialogViewModel =
DialogViewModel(AppUtils.getString(R.string.conference_info_confirm_removal))
DialogViewModel(AppUtils.getString(R.string.conference_scheduled_delete_one_dialog))
deleteConferenceInfoDialog =
DialogUtils.getVoipDialog(requireContext(), dialogViewModel)
@ -140,4 +139,13 @@ class ScheduledConferencesFragment : GenericFragment<ConferencesScheduledFragmen
navigateToConferenceScheduling()
}
}
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
val list = ArrayList<ScheduledConferenceData>()
for (index in indexesOfItemToDelete) {
val conferenceData = adapter.currentList[index]
list.add(conferenceData)
}
viewModel.deleteConferencesInfo(list)
}
}

View file

@ -69,6 +69,21 @@ class ScheduledConferencesViewModel : ViewModel() {
conferences.value = conferenceInfoList
}
fun deleteConferencesInfo(toRemoveList: List<ScheduledConferenceData>) {
val conferenceInfoList = arrayListOf<ScheduledConferenceData>()
for (confInfo in conferences.value.orEmpty()) {
if (confInfo in toRemoveList) {
confInfo.delete()
confInfo.destroy()
} else {
conferenceInfoList.add(confInfo)
}
}
conferences.value = conferenceInfoList
}
private fun computeConferenceInfoList() {
conferences.value.orEmpty().forEach(ScheduledConferenceData::destroy)

View file

@ -2,6 +2,8 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true"
android:drawable="@drawable/icon_info_selected" />
<item android:state_enabled="false"
android:drawable="@drawable/icon_info" />
<item android:state_pressed="true"
android:drawable="@drawable/icon_info_selected" />
<item

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="7dp" />
<solid android:color="@color/voip_conference_cancelled_bg_color"/>
</shape>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="7dp" />
<solid android:color="@color/voip_conference_cancelled_bg_color"/>
<stroke android:width="2dp" android:color="?attr/colorPrimary"/>
</shape>

View file

@ -5,6 +5,12 @@
<data>
<import type="android.view.View" />
<variable
name="clickListener"
type="android.view.View.OnClickListener" />
<variable
name="longClickListener"
type="android.view.View.OnLongClickListener" />
<variable
name="copyAddressClickListener"
type="android.view.View.OnClickListener" />
@ -17,6 +23,12 @@
<variable
name="deleteConferenceClickListener"
type="android.view.View.OnClickListener" />
<variable
name="position"
type="Integer" />
<variable
name="selectionListViewModel"
type="org.linphone.activities.main.viewmodels.ListTopBarViewModel" />
<variable
name="data"
type="org.linphone.activities.main.conference.data.ScheduledConferenceData" />
@ -25,7 +37,8 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{() -> data.toggleExpand()}"
android:onClick="@{clickListener}"
android:onLongClick="@{longClickListener}"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:orientation="vertical">
@ -35,6 +48,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="5dp"
android:background="@drawable/shape_round_gray_background"
backgroundImage="@{data.backgroundResId, default=@drawable/shape_round_gray_background}">
<RelativeLayout
@ -69,11 +83,22 @@
</LinearLayout>
<TextView
style="@style/conference_invite_desc_font"
<CheckBox
android:id="@+id/select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:checked="@{selectionListViewModel.selectedItems.contains(position)}"
android:onClick="@{() -> selectionListViewModel.onToggleSelect(position)}"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:visibility="@{selectionListViewModel.isEditionEnabled ? View.VISIBLE : View.GONE, default=gone}" />
<TextView
style="@style/conference_invite_desc_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toStartOf="@id/select"
android:layout_marginStart="2dp"
android:layout_marginEnd="5dp"
android:layout_toEndOf="@id/time"
@ -83,6 +108,16 @@
</RelativeLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
style="@style/conference_cancel_title_font"
android:visibility="@{data.isConferenceCancelled ? View.VISIBLE : View.GONE, default=gone}"
android:text="@{data.canEdit ? @string/conference_scheduled_cancelled_by_me : @string/conference_scheduled_cancelled_by_organizer, default=@string/conference_scheduled_cancelled_by_organizer}"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -119,6 +154,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:enabled="@{!selectionListViewModel.isEditionEnabled}"
android:contentDescription="@string/content_description_toggle_conference_info_details"
android:src="@drawable/button_conference_info"/>
@ -141,6 +177,7 @@
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:selected="@{true}"
android:enabled="@{!selectionListViewModel.isEditionEnabled}"
android:contentDescription="@string/content_description_toggle_conference_info_details"
android:src="@drawable/button_conference_info" />
@ -172,7 +209,6 @@
android:visibility="@{data.expanded ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="vertical">
<TextView
@ -201,6 +237,7 @@
android:layout_marginTop="10dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:visibility="@{data.isConferenceCancelled ? View.GONE : View.VISIBLE}"
android:text="@string/conference_schedule_address_title"/>
<LinearLayout
@ -209,7 +246,8 @@
android:layout_marginTop="5dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:orientation="horizontal">
android:orientation="horizontal"
android:visibility="@{data.isConferenceCancelled ? View.GONE : View.VISIBLE}">
<TextView
android:layout_width="0dp"
@ -248,7 +286,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_green_background"
android:enabled="@{!data.isConferenceCancelled}"
android:visibility="@{data.isConferenceCancelled ? View.GONE : View.VISIBLE}"
android:paddingLeft="20dp"
android:paddingTop="8dp"
android:paddingRight="20dp"
@ -259,7 +297,7 @@
<ImageView
android:onClick="@{editConferenceClickListener}"
android:visibility="@{data.canEdit ? View.VISIBLE : View.GONE, default=gone}"
android:visibility="@{data.canEdit &amp;&amp; !data.isConferenceCancelled ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
@ -56,6 +57,14 @@
</LinearLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/list_edit_top_bar_fragment"
android:name="org.linphone.activities.main.fragments.ListTopBarFragment"
android:layout_width="match_parent"
android:layout_height="@dimen/main_activity_top_bar_size"
android:layout_alignTop="@id/top_bar"
tools:layout="@layout/list_edit_top_bar_fragment" />
<com.google.android.material.chip.ChipGroup
android:id="@+id/chips"
android:layout_width="match_parent"

View file

@ -636,7 +636,8 @@
<string name="conference_waiting_room_video_disabled">La vidéo est actuellement désactivée</string>
<string name="conference_scheduled">Réunions</string>
<string name="conference_no_schedule">Aucune réunion planifiée pour le moment.</string>
<string name="conference_info_confirm_removal">Voulez-vous supprimer cette réunion \?</string>
<string name="conference_scheduled_delete_one_dialog">Voulez-vous supprimer cette réunion ?</string>
<string name="conference_scheduled_delete_many_dialog">Voulez-vous supprimer ces réunions ?</string>
<string name="conference_empty">Vous êtes actuellement seul dans cet appel de groupe</string>
<string name="conference_invitation_received_notification">Vous avez été invité à une réunion</string>
<string name="conference_invitation">Invitation à une réunion</string>
@ -750,4 +751,6 @@
<string name="account_setting_conference_factory_address">Adresse du serveur de conversation de groupe/sécurisées</string>
<string name="account_setting_audio_video_conference_factory_address">Adresse du serveur de conférence audio/vidéo</string>
<string name="account_setting_end_to_end_encryption_keys_server_url">URL du serveur de clés pour le chiffrement de bout en bout</string>
<string name="conference_scheduled_cancelled_by_organizer">L\'organisateur a annulé la conférence</string>
<string name="conference_scheduled_cancelled_by_me">Vous avez annulé la conférence</string>
</resources>

View file

@ -169,7 +169,7 @@
<string name="conference_admin_set">%s הוא מנהל</string>
<string name="conference_admin_unset">%s כבר לא מנהל</string>
<string name="conference_schedule_info_created">ועידה תוזמנה</string>
<string name="conference_info_confirm_removal">האם ברצונך למחוק ועידה זו\?</string>
<string name="conference_scheduled_delete_one_dialog">האם ברצונך למחוק ועידה זו\?</string>
<string name="conference_info_removed">מידע אודות הועידה נמחק</string>
<string name="conference_invitation">הזמנה לועידה</string>
<string name="conference_low_bandwidth">רוחב פס נמוך,מבטל וידאו</string>

View file

@ -189,7 +189,7 @@
<string name="conference_schedule_organizer">ორგანიზატორი:</string>
<string name="conference_admin_set">%s აწი ადმინისტრატორია</string>
<string name="conference_admin_unset">%s აღარ არის ადმინისტრატორი</string>
<string name="conference_info_confirm_removal">დარწმუნებული ხართ, რომ გსურთ ამ შეხვედრის წაშლა\?</string>
<string name="conference_scheduled_delete_one_dialog">დარწმუნებული ხართ, რომ გსურთ ამ შეხვედრის წაშლა\?</string>
<string name="conference_empty">თქვენ ამ მომენტისთვის მარტო ხართ ამ ჯგუფურ ზარში</string>
<string name="conference_invitation">შეხვედრის მოწვევა</string>
<string name="conference_first_to_join">თქვენ პირველი შეუერთდით ჯგუფურ ზარს</string>

View file

@ -670,7 +670,7 @@
<string name="conference_admin_set">%s - сейчас администратор</string>
<string name="conference_admin_unset">%s больше не администратор</string>
<string name="conference_schedule_info_created">Встреча была запланирована</string>
<string name="conference_info_confirm_removal">Вы действительно хотите удалить эту встречу\?</string>
<string name="conference_scheduled_delete_one_dialog">Вы действительно хотите удалить эту встречу\?</string>
<string name="conference_info_removed">Информация о встречи удалена</string>
<string name="contacts_settings_ldap_auth_method_simple">Простой</string>
<string name="contacts_settings_ldap_tls_title">Использовать TLS</string>

View file

@ -307,7 +307,7 @@
<string name="conference_layout_too_many_participants_for_mosaic">Ви не можете змінити схему групового виклику, оскільки забагато учасників</string>
<string name="conference_no_terminated_schedule">Припинених зустрічей ще немає.</string>
<string name="conference_schedule_info_created">Зустріч була призначена</string>
<string name="conference_info_confirm_removal">Ви справді хочете видалити цю зустріч\?</string>
<string name="conference_scheduled_delete_one_dialog">Ви справді хочете видалити цю зустріч\?</string>
<string name="conference_info_removed">Інформацію про зустріч видалено</string>
<string name="conference_low_bandwidth">Виявлено низьку пропускну здатність, відео вимикається</string>
<string name="conference_incoming_title">Вхідний груповий виклик</string>

View file

@ -735,7 +735,7 @@
<string name="conference_no_schedule">未安排會議。</string>
<string name="conference_schedule_organizer">主辦人:</string>
<string name="conference_go_to_chat">會議聊天室</string>
<string name="conference_info_confirm_removal">您真的要刪除這場會議嗎?</string>
<string name="conference_scheduled_delete_one_dialog">您真的要刪除這場會議嗎?</string>
<string name="conference_empty">您是目前通話中唯一的與會者</string>
<string name="conference_invitation_received_notification">您已受邀加入會議</string>
<string name="conference_invitation">會議邀請</string>

View file

@ -37,7 +37,8 @@
<color name="voip_text_dark_color">#6E8596</color> <!-- Text color above voip_dark_color5 -->
<color name="voip_conf_address_text_color">#A2A2A2</color>
<color name="voip_conference_updated_color">#EFAE00</color>
<color name="voip_conference_cancelled_color">#FF0000</color>
<color name="voip_conference_cancelled_title_color">#FF0000</color>
<color name="voip_conference_cancelled_bg_color">#FFE6E6</color>
<color name="form_field_gray_background">#F7F7F7</color>

View file

@ -293,7 +293,6 @@
<string name="conference_admin_set">%s is now admin</string>
<string name="conference_admin_unset">%s is no longer admin</string>
<string name="conference_schedule_info_created">Meeting has been scheduled</string>
<string name="conference_info_confirm_removal">Do you really want to delete this meeting?</string>
<string name="conference_info_removed">Meeting info has been deleted</string>
<string name="conference_empty">You are currently alone in this group call</string>
<string name="conference_invitation_received_notification">You have been invited to a meeting</string>
@ -308,6 +307,14 @@
<string name="conference_start_group_call_dialog_ok_button">Start</string>
<string name="conference_scheduled_terminated_filter">Terminated</string>
<string name="conference_scheduled_future_filter">Scheduled</string>
<string name="conference_scheduled_delete_one_dialog">Do you want to delete this meeting?</string>
<string name="conference_scheduled_delete_many_dialog">Do you want to delete these meetings?</string>
<plurals name="conference_scheduled_delete_dialog" translatable="false">
<item quantity="one">@string/conference_scheduled_delete_one_dialog</item>
<item quantity="other">@string/conference_scheduled_delete_many_dialog</item>
</plurals>
<string name="conference_scheduled_cancelled_by_organizer">Conference has been cancelled by organizer</string>
<string name="conference_scheduled_cancelled_by_me">You have cancelled the conference</string>
<!-- Call -->
<string name="call_incoming_title">Incoming Call</string>

View file

@ -152,7 +152,7 @@
</style>
<style name="conference_cancel_title_font" parent="@android:style/TextAppearance.Medium">
<item name="android:textColor">@color/voip_conference_cancelled_color</item>
<item name="android:textColor">@color/voip_conference_cancelled_title_color</item>
<item name="android:textStyle">bold</item>
<item name="android:textSize">16sp</item>
</style>