Added swipe to remove on call logs & contacts + improved confirmation dialog messages

This commit is contained in:
Sylvain Berfini 2020-06-17 15:52:01 +02:00
parent 766891301c
commit bf24a6b2a9
8 changed files with 150 additions and 9 deletions

View file

@ -49,6 +49,7 @@ import org.linphone.databinding.ChatRoomMasterFragmentBinding
import org.linphone.utils.*
class MasterChatRoomsFragment : MasterFragment() {
override val dialogConfirmationMessageBeforeRemoval = R.plurals.chat_room_delete_dialog
private lateinit var binding: ChatRoomMasterFragmentBinding
private lateinit var listViewModel: ChatRoomsListViewModel
private lateinit var adapter: ChatRoomsListAdapter
@ -94,6 +95,7 @@ class MasterChatRoomsFragment : MasterFragment() {
val layoutManager = LinearLayoutManager(activity)
binding.chatList.layoutManager = layoutManager
// Swipe action
val swipeConfiguration = RecyclerViewSwipeConfiguration()
val white = ContextCompat.getColor(requireContext(), R.color.white_color)
@ -102,7 +104,7 @@ class MasterChatRoomsFragment : MasterFragment() {
override fun onLeftToRightSwipe(viewHolder: RecyclerView.ViewHolder) {}
override fun onRightToLeftSwipe(viewHolder: RecyclerView.ViewHolder) {
val viewModel = DialogViewModel(getString(R.string.dialog_default_delete_message))
val viewModel = DialogViewModel(getString(R.string.chat_room_delete_one_dialog))
val dialog: Dialog = DialogUtils.getDialog(requireContext(), viewModel)
viewModel.showCancelButton {

View file

@ -131,7 +131,7 @@ class DetailContactFragment : Fragment() {
}
private fun confirmContactRemoval() {
val dialogViewModel = DialogViewModel(getString(R.string.contact_confirm_removal_dialog))
val dialogViewModel = DialogViewModel(getString(R.string.contact_delete_one_dialog))
val dialog: Dialog = DialogUtils.getDialog(requireContext(), dialogViewModel)
dialogViewModel.showCancelButton {

View file

@ -19,33 +19,37 @@
*/
package org.linphone.activities.main.contact.fragments
import android.app.Dialog
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.R
import org.linphone.activities.main.MainActivity
import org.linphone.activities.main.contact.adapters.ContactsListAdapter
import org.linphone.activities.main.contact.viewmodels.ContactsListViewModel
import org.linphone.activities.main.fragments.MasterFragment
import org.linphone.activities.main.viewmodels.DialogViewModel
import org.linphone.activities.main.viewmodels.SharedMainViewModel
import org.linphone.contact.Contact
import org.linphone.core.Factory
import org.linphone.core.tools.Log
import org.linphone.databinding.ContactMasterFragmentBinding
import org.linphone.utils.Event
import org.linphone.utils.PermissionHelper
import org.linphone.utils.RecyclerViewHeaderDecoration
import org.linphone.utils.*
class MasterContactsFragment : MasterFragment() {
override val dialogConfirmationMessageBeforeRemoval = R.plurals.contact_delete_dialog
private lateinit var binding: ContactMasterFragmentBinding
private lateinit var listViewModel: ContactsListViewModel
private lateinit var adapter: ContactsListAdapter
@ -90,6 +94,34 @@ class MasterContactsFragment : MasterFragment() {
val layoutManager = LinearLayoutManager(activity)
binding.contactsList.layoutManager = layoutManager
// Swipe action
val swipeConfiguration = RecyclerViewSwipeConfiguration()
val white = ContextCompat.getColor(requireContext(), R.color.white_color)
swipeConfiguration.rightToLeftAction = RecyclerViewSwipeConfiguration.Action("Delete", white, ContextCompat.getColor(requireContext(), R.color.red_color))
val swipeListener = object : RecyclerViewSwipeListener {
override fun onLeftToRightSwipe(viewHolder: RecyclerView.ViewHolder) {}
override fun onRightToLeftSwipe(viewHolder: RecyclerView.ViewHolder) {
val viewModel = DialogViewModel(getString(R.string.contact_delete_one_dialog))
val dialog: Dialog = DialogUtils.getDialog(requireContext(), viewModel)
viewModel.showCancelButton {
adapter.notifyItemChanged(viewHolder.adapterPosition)
dialog.dismiss()
}
viewModel.showDeleteButton({
listViewModel.deleteContact(listViewModel.contactsList.value?.get(viewHolder.adapterPosition))
dialog.dismiss()
}, getString(R.string.dialog_delete))
dialog.show()
}
}
RecyclerViewSwipeUtils(ItemTouchHelper.LEFT, swipeConfiguration, swipeListener)
.attachToRecyclerView(binding.contactsList)
// Divider between items
val dividerItemDecoration = DividerItemDecoration(context, layoutManager.orientation)
dividerItemDecoration.setDrawable(resources.getDrawable(R.drawable.divider, null))

View file

@ -73,6 +73,38 @@ class ContactsListViewModel : ViewModel() {
}
}
fun deleteContact(contact: Contact?) {
contact ?: return
val select = ContactsContract.Data.CONTACT_ID + " = ?"
val ops = ArrayList<ContentProviderOperation>()
if (contact is NativeContact) {
val nativeContact: NativeContact = contact
Log.i("[Contacts] Adding Android contact id ${nativeContact.nativeId} to batch removal")
val args = arrayOf(nativeContact.nativeId)
ops.add(
ContentProviderOperation.newDelete(ContactsContract.RawContacts.CONTENT_URI)
.withSelection(select, args)
.build()
)
}
if (contact.friend != null) {
Log.i("[Contacts] Removing friend")
contact.friend?.remove()
}
if (ops.isNotEmpty()) {
try {
Log.i("[Contacts] Removing ${ops.size} contacts")
coreContext.context.contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)
} catch (e: Exception) {
Log.e("[Contacts] $e")
}
}
}
fun deleteContacts(list: ArrayList<Contact>) {
val select = ContactsContract.Data.CONTACT_ID + " = ?"
val ops = ArrayList<ContentProviderOperation>()

View file

@ -27,6 +27,7 @@ import androidx.lifecycle.ViewModelProvider
import org.linphone.R
import org.linphone.activities.main.viewmodels.DialogViewModel
import org.linphone.activities.main.viewmodels.ListTopBarViewModel
import org.linphone.utils.AppUtils
import org.linphone.utils.DialogUtils
/**
@ -35,6 +36,7 @@ import org.linphone.utils.DialogUtils
*/
abstract class MasterFragment : Fragment() {
protected lateinit var listSelectionViewModel: ListTopBarViewModel
protected open val dialogConfirmationMessageBeforeRemoval: Int = R.plurals.dialog_default_delete
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
@ -60,7 +62,8 @@ abstract class MasterFragment : Fragment() {
listSelectionViewModel.deleteSelectionEvent.observe(viewLifecycleOwner, Observer {
it.consume {
val viewModel = DialogViewModel(getString(R.string.dialog_default_delete_message))
val confirmationDialog = AppUtils.getStringWithPlural(dialogConfirmationMessageBeforeRemoval, listSelectionViewModel.selectedItems.value.orEmpty().size)
val viewModel = DialogViewModel(confirmationDialog)
val dialog: Dialog = DialogUtils.getDialog(requireContext(), viewModel)
viewModel.showCancelButton {

View file

@ -19,15 +19,18 @@
*/
package org.linphone.activities.main.history.fragments
import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import org.linphone.LinphoneApplication.Companion.coreContext
@ -35,14 +38,16 @@ import org.linphone.R
import org.linphone.activities.main.fragments.MasterFragment
import org.linphone.activities.main.history.adapters.CallLogsListAdapter
import org.linphone.activities.main.history.viewmodels.CallLogsListViewModel
import org.linphone.activities.main.viewmodels.DialogViewModel
import org.linphone.activities.main.viewmodels.SharedMainViewModel
import org.linphone.activities.main.viewmodels.TabsViewModel
import org.linphone.core.CallLog
import org.linphone.core.tools.Log
import org.linphone.databinding.HistoryMasterFragmentBinding
import org.linphone.utils.RecyclerViewHeaderDecoration
import org.linphone.utils.*
class MasterCallLogsFragment : MasterFragment() {
override val dialogConfirmationMessageBeforeRemoval = R.plurals.history_delete_dialog
private lateinit var binding: HistoryMasterFragmentBinding
private lateinit var listViewModel: CallLogsListViewModel
private lateinit var adapter: CallLogsListAdapter
@ -86,6 +91,34 @@ class MasterCallLogsFragment : MasterFragment() {
val layoutManager = LinearLayoutManager(activity)
binding.callLogsList.layoutManager = layoutManager
// Swipe action
val swipeConfiguration = RecyclerViewSwipeConfiguration()
val white = ContextCompat.getColor(requireContext(), R.color.white_color)
swipeConfiguration.rightToLeftAction = RecyclerViewSwipeConfiguration.Action("Delete", white, ContextCompat.getColor(requireContext(), R.color.red_color))
val swipeListener = object : RecyclerViewSwipeListener {
override fun onLeftToRightSwipe(viewHolder: RecyclerView.ViewHolder) {}
override fun onRightToLeftSwipe(viewHolder: RecyclerView.ViewHolder) {
val viewModel = DialogViewModel(getString(R.string.history_delete_one_dialog))
val dialog: Dialog = DialogUtils.getDialog(requireContext(), viewModel)
viewModel.showCancelButton {
adapter.notifyItemChanged(viewHolder.adapterPosition)
dialog.dismiss()
}
viewModel.showDeleteButton({
listViewModel.deleteCallLog(listViewModel.callLogs.value?.get(viewHolder.adapterPosition))
dialog.dismiss()
}, getString(R.string.dialog_delete))
dialog.show()
}
}
RecyclerViewSwipeUtils(ItemTouchHelper.LEFT, swipeConfiguration, swipeListener)
.attachToRecyclerView(binding.callLogsList)
// Divider between items
val dividerItemDecoration = DividerItemDecoration(context, layoutManager.orientation)
dividerItemDecoration.setDrawable(resources.getDrawable(R.drawable.divider, null))

View file

@ -70,6 +70,23 @@ class CallLogsListViewModel : ViewModel() {
super.onCleared()
}
fun deleteCallLog(callLog: CallLog?) {
val list = arrayListOf<CallLog>()
list.addAll(callLogs.value.orEmpty())
val missedList = arrayListOf<CallLog>()
missedList.addAll(missedCallLogs.value.orEmpty())
if (callLog != null) {
coreContext.core.removeCallLog(callLog)
list.remove(callLog)
missedList.remove(callLog)
}
callLogs.value = list
missedCallLogs.value = missedList
}
fun deleteCallLogs(listToDelete: ArrayList<CallLog>) {
val list = arrayListOf<CallLog>()
list.addAll(callLogs.value.orEmpty())

View file

@ -81,6 +81,12 @@
<string name="history_calls_list">Calls</string>
<string name="no_call_history">No call in your history</string>
<string name="no_missed_call_history">No missed call in your history</string>
<string name="history_delete_one_dialog">Do you want to delete this record?</string>
<string name="history_delete_many_dialog">Do you want to delete these records?</string>
<plurals name="history_delete_dialog">
<item quantity="one">@string/history_delete_one_dialog</item>
<item quantity="other">@string/history_delete_many_dialog</item>
</plurals>
<!-- Contacts -->
<string name="contact_invite_friend">Invite</string>
@ -94,7 +100,12 @@
<string name="contact_organization">Organization</string>
<string name="contact_choose_existing_or_new_to_add_number">Select a contact or create a new one</string>
<string name="contact_editor_write_permission_denied">Write Contacts permission denied, can\'t edit contact</string>
<string name="contact_confirm_removal_dialog">Do you want to delete this contact?\nIt will also be removed from your device addressbook</string>
<string name="contact_delete_one_dialog">Do you want to delete this contact?\nIt will also be removed from your device addressbook</string>
<string name="contact_delete_many_dialog">Are you sure you want to delete these contacts?\nThey will also be removed from your device addressbook</string>
<plurals name="contact_delete_dialog">
<item quantity="one">@string/contact_delete_one_dialog</item>
<item quantity="other">@string/contact_delete_many_dialog</item>
</plurals>
<!-- Dialer -->
<string name="dialer_address_bar_hint">Enter a number or an address</string>
@ -178,6 +189,12 @@
</plurals>
<string name="chat_room_creation_failed_snack">Chat room creation failed</string>
<string name="chat_room_removal_failed_snack">Chat room removal failed</string>
<string name="chat_room_delete_one_dialog">Are you sure you want to delete this conversation?</string>
<string name="chat_room_delete_many_dialog">Are you sure you want to delete these conversations?</string>
<plurals name="chat_room_delete_dialog">
<item quantity="one">@string/chat_room_delete_one_dialog</item>
<item quantity="other">@string/chat_room_delete_many_dialog</item>
</plurals>
<!-- Recordings -->
<string name="recordings_empty_list">No recordings</string>
@ -531,9 +548,14 @@
<string name="dialog_delete">Delete</string>
<string name="dialog_ok">OK</string>
<string name="dialog_call">Call</string>
<string name="dialog_default_delete_message">Are you sure you want to delete your selection?</string>
<string name="dialog_lime_security_message">Instant messages are end-to-end encrypted in secured conversations. It is possible to upgrade the security level of a conversation by authenticating participants. To do so, call the contact and follow the authentication process.</string>
<string name="operation_in_progress_wait">Operation in progress, please wait</string>
<string name="dialog_default_delete_one">Are you sure you want to delete this item?</string>
<string name="dialog_default_delete_many">Are you sure you want to delete your selection?</string>
<plurals name="dialog_default_delete">
<item quantity="one">@string/dialog_default_delete_one</item>
<item quantity="other">@string/dialog_default_delete_many</item>
</plurals>
<!-- Content description -->
<string name="content_description_add_sip_address_field">Add a SIP address field</string>