From 6b95cc6a5cb2c7d8bec803998674bbc3340bb97e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 17 Nov 2023 14:46:31 +0100 Subject: [PATCH] Added long press bottom sheet menu to meetings list cell --- .../meetings/adapter/MeetingsListAdapter.kt | 14 ++- .../meetings/fragment/MeetingsListFragment.kt | 16 ++++ .../fragment/MeetingsMenuDialogFragment.kt | 64 ++++++++++++++ .../ui/main/meetings/model/MeetingModel.kt | 17 +++- .../drawable/primary_cell_r10_background.xml | 9 ++ ...squircle_gray_main2_100_r10_background.xml | 5 ++ .../chat_message_bottom_sheet_list_cell.xml | 4 +- app/src/main/res/layout/meeting_list_cell.xml | 87 +++++++++---------- .../layout/meetings_list_long_press_menu.xml | 33 +++++++ .../start_call_suggestion_list_cell.xml | 4 +- 10 files changed, 200 insertions(+), 53 deletions(-) create mode 100644 app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsMenuDialogFragment.kt create mode 100644 app/src/main/res/drawable/primary_cell_r10_background.xml create mode 100644 app/src/main/res/drawable/shape_squircle_gray_main2_100_r10_background.xml create mode 100644 app/src/main/res/layout/meetings_list_long_press_menu.xml diff --git a/app/src/main/java/org/linphone/ui/main/meetings/adapter/MeetingsListAdapter.kt b/app/src/main/java/org/linphone/ui/main/meetings/adapter/MeetingsListAdapter.kt index cc43691f0..a038c7195 100644 --- a/app/src/main/java/org/linphone/ui/main/meetings/adapter/MeetingsListAdapter.kt +++ b/app/src/main/java/org/linphone/ui/main/meetings/adapter/MeetingsListAdapter.kt @@ -23,6 +23,8 @@ class MeetingsListAdapter : MeetingDiffCallback() ), HeaderAdapter { + var selectedAdapterPosition = -1 + val meetingClickedEvent: MutableLiveData> by lazy { MutableLiveData>() } @@ -53,6 +55,7 @@ class MeetingsListAdapter : parent, false ) + val viewHolder = ViewHolder(binding) binding.apply { lifecycleOwner = parent.findViewTreeLifecycleOwner() @@ -61,18 +64,24 @@ class MeetingsListAdapter : } setOnLongClickListener { + selectedAdapterPosition = viewHolder.bindingAdapterPosition root.isSelected = true meetingLongClickedEvent.value = Event(model!!) true } } - return ViewHolder(binding) + return viewHolder } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { (holder as ViewHolder).bind(getItem(position)) } + fun resetSelection() { + notifyItemChanged(selectedAdapterPosition) + selectedAdapterPosition = -1 + } + inner class ViewHolder( val binding: MeetingListCellBinding ) : RecyclerView.ViewHolder(binding.root) { @@ -80,6 +89,9 @@ class MeetingsListAdapter : fun bind(meetingModel: MeetingModel) { with(binding) { model = meetingModel + + binding.root.isSelected = bindingAdapterPosition == selectedAdapterPosition + executePendingBindings() } } 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 93659cefc..7b5986dfa 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 @@ -140,6 +140,22 @@ class MeetingsListFragment : AbstractTopBarFragment() { } } + adapter.meetingLongClickedEvent.observe(viewLifecycleOwner) { + it.consume { model -> + val modalBottomSheet = MeetingsMenuDialogFragment( + { // onDismiss + adapter.resetSelection() + }, + { // onDelete + Log.i("$TAG Deleting meeting [${model.id}]") + model.delete() + listViewModel.applyFilter() + } + ) + modalBottomSheet.show(parentFragmentManager, MeetingsMenuDialogFragment.TAG) + } + } + sharedViewModel.forceRefreshMeetingsListEvent.observe(viewLifecycleOwner) { it.consume { Log.i("$TAG We were asked to refresh the meetings list, doing it now") diff --git a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsMenuDialogFragment.kt b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsMenuDialogFragment.kt new file mode 100644 index 000000000..8a5c81ac0 --- /dev/null +++ b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsMenuDialogFragment.kt @@ -0,0 +1,64 @@ +/* + * 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.content.DialogInterface +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.UiThread +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import org.linphone.databinding.MeetingsListLongPressMenuBinding + +@UiThread +class MeetingsMenuDialogFragment( + private val onDismiss: (() -> Unit)? = null, + private val onDeleteMeeting: (() -> Unit)? = null +) : BottomSheetDialogFragment() { + companion object { + const val TAG = "MeetingsMenuDialogFragment" + } + + override fun onCancel(dialog: DialogInterface) { + onDismiss?.invoke() + super.onCancel(dialog) + } + + override fun onDismiss(dialog: DialogInterface) { + onDismiss?.invoke() + super.onDismiss(dialog) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val view = MeetingsListLongPressMenuBinding.inflate(layoutInflater) + + view.setDeleteClickListener { + onDeleteMeeting?.invoke() + dismiss() + } + + return view.root + } +} diff --git a/app/src/main/java/org/linphone/ui/main/meetings/model/MeetingModel.kt b/app/src/main/java/org/linphone/ui/main/meetings/model/MeetingModel.kt index 1ac045953..0e3cca069 100644 --- a/app/src/main/java/org/linphone/ui/main/meetings/model/MeetingModel.kt +++ b/app/src/main/java/org/linphone/ui/main/meetings/model/MeetingModel.kt @@ -19,13 +19,20 @@ */ package org.linphone.ui.main.meetings.model +import androidx.annotation.UiThread import androidx.annotation.WorkerThread import androidx.lifecycle.MutableLiveData +import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.core.ConferenceInfo import org.linphone.core.Participant +import org.linphone.core.tools.Log import org.linphone.utils.TimestampUtils -class MeetingModel @WorkerThread constructor(conferenceInfo: ConferenceInfo) { +class MeetingModel @WorkerThread constructor(private val conferenceInfo: ConferenceInfo) { + companion object { + private const val TAG = "[Meeting Model]" + } + val id = conferenceInfo.uri?.asStringUriOnly() ?: "" val timestamp = conferenceInfo.dateTime @@ -65,4 +72,12 @@ class MeetingModel @WorkerThread constructor(conferenceInfo: ConferenceInfo) { isBroadcast.postValue(!allSpeaker) } + + @UiThread + fun delete() { + coreContext.postOnCoreThread { core -> + Log.w("$TAG Deleting conference info [${conferenceInfo.uri?.asStringUriOnly()}]") + core.deleteConferenceInformation(conferenceInfo) + } + } } diff --git a/app/src/main/res/drawable/primary_cell_r10_background.xml b/app/src/main/res/drawable/primary_cell_r10_background.xml new file mode 100644 index 000000000..e3a99d27e --- /dev/null +++ b/app/src/main/res/drawable/primary_cell_r10_background.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_squircle_gray_main2_100_r10_background.xml b/app/src/main/res/drawable/shape_squircle_gray_main2_100_r10_background.xml new file mode 100644 index 000000000..324fbdb57 --- /dev/null +++ b/app/src/main/res/drawable/shape_squircle_gray_main2_100_r10_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/chat_message_bottom_sheet_list_cell.xml b/app/src/main/res/layout/chat_message_bottom_sheet_list_cell.xml index b2c603441..95d126f8d 100644 --- a/app/src/main/res/layout/chat_message_bottom_sheet_list_cell.xml +++ b/app/src/main/res/layout/chat_message_bottom_sheet_list_cell.xml @@ -16,9 +16,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="@{() -> model.clicked()}" - android:background="@drawable/primary_cell_background" android:layout_marginStart="16dp" - android:layout_marginEnd="16dp"> + android:layout_marginEnd="16dp" + android:background="@drawable/primary_cell_background"> - - + - + - - - - - + diff --git a/app/src/main/res/layout/meetings_list_long_press_menu.xml b/app/src/main/res/layout/meetings_list_long_press_menu.xml new file mode 100644 index 000000000..8bdb82b04 --- /dev/null +++ b/app/src/main/res/layout/meetings_list_long_press_menu.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/start_call_suggestion_list_cell.xml b/app/src/main/res/layout/start_call_suggestion_list_cell.xml index e3dec781a..653125fe4 100644 --- a/app/src/main/res/layout/start_call_suggestion_list_cell.xml +++ b/app/src/main/res/layout/start_call_suggestion_list_cell.xml @@ -17,9 +17,9 @@ android:onClick="@{onClickListener}" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/primary_cell_background" android:layout_marginStart="16dp" - android:layout_marginEnd="16dp"> + android:layout_marginEnd="16dp" + android:background="@drawable/primary_cell_background">