Grouped call logs in history for a shorter list

This commit is contained in:
Sylvain Berfini 2020-06-24 15:27:53 +02:00
parent 5e540dce71
commit cadd5a84b2
7 changed files with 116 additions and 59 deletions

View file

@ -113,7 +113,7 @@ class MasterChatRoomsFragment : MasterFragment() {
}
viewModel.showDeleteButton({
listViewModel.deleteChatRoom(listViewModel.chatRooms.value?.get(viewHolder.adapterPosition))
listViewModel.deleteChatRoom(adapter.getItemAt(viewHolder.adapterPosition))
dialog.dismiss()
}, getString(R.string.dialog_delete))

View file

@ -112,7 +112,7 @@ class MasterContactsFragment : MasterFragment() {
}
viewModel.showDeleteButton({
listViewModel.deleteContact(listViewModel.contactsList.value?.get(viewHolder.adapterPosition))
listViewModel.deleteContact(adapter.getItemAt(viewHolder.adapterPosition))
dialog.dismiss()
}, getString(R.string.dialog_delete))

View file

@ -29,16 +29,16 @@ import androidx.lifecycle.Observer
import androidx.recyclerview.widget.DiffUtil
import org.linphone.R
import org.linphone.activities.main.history.viewmodels.CallLogViewModel
import org.linphone.activities.main.history.viewmodels.GroupedCallLogViewModel
import org.linphone.activities.main.viewmodels.ListTopBarViewModel
import org.linphone.core.Address
import org.linphone.core.CallLog
import org.linphone.databinding.GenericListHeaderBinding
import org.linphone.databinding.HistoryListCellBinding
import org.linphone.utils.*
class CallLogsListAdapter(val selectionViewModel: ListTopBarViewModel) : LifecycleListAdapter<CallLog, CallLogsListAdapter.ViewHolder>(CallLogDiffCallback()), HeaderAdapter {
val selectedCallLogEvent: MutableLiveData<Event<CallLog>> by lazy {
MutableLiveData<Event<CallLog>>()
class CallLogsListAdapter(val selectionViewModel: ListTopBarViewModel) : LifecycleListAdapter<GroupedCallLogViewModel, CallLogsListAdapter.ViewHolder>(CallLogDiffCallback()), HeaderAdapter {
val selectedCallLogEvent: MutableLiveData<Event<GroupedCallLogViewModel>> by lazy {
MutableLiveData<Event<GroupedCallLogViewModel>>()
}
val startCallToEvent: MutableLiveData<Event<Address>> by lazy {
@ -62,9 +62,9 @@ class CallLogsListAdapter(val selectionViewModel: ListTopBarViewModel) : Lifecyc
inner class ViewHolder(
private val binding: HistoryListCellBinding
) : LifecycleViewHolder(binding) {
fun bind(callLog: CallLog) {
fun bind(callLogGroup: GroupedCallLogViewModel) {
with(binding) {
val callLogViewModel = CallLogViewModel(callLog)
val callLogViewModel = CallLogViewModel(callLogGroup.lastCallLog)
viewModel = callLogViewModel
// This is for item selection through ListTopBarFragment
@ -77,15 +77,17 @@ class CallLogsListAdapter(val selectionViewModel: ListTopBarViewModel) : Lifecyc
if (selectionViewModel.isEditionEnabled.value == true) {
selectionViewModel.onToggleSelect(adapterPosition)
} else {
startCallToEvent.value = Event(callLog.remoteAddress)
startCallToEvent.value = Event(callLogGroup.lastCallLog.remoteAddress)
}
}
// This listener is disabled when in edition mode
setDetailsClickListener {
selectedCallLogEvent.value = Event(callLog)
selectedCallLogEvent.value = Event(callLogGroup)
}
groupCount = callLogGroup.callLogs.size
executePendingBindings()
}
}
@ -93,18 +95,18 @@ class CallLogsListAdapter(val selectionViewModel: ListTopBarViewModel) : Lifecyc
override fun displayHeaderForPosition(position: Int): Boolean {
if (position >= itemCount) return false
val callLog = getItem(position)
val date = callLog.startDate
val callLogGroup = getItem(position)
val date = callLogGroup.lastCallLog.startDate
val previousPosition = position - 1
return if (previousPosition >= 0) {
val previousItemDate = getItem(previousPosition).startDate
val previousItemDate = getItem(previousPosition).lastCallLog.startDate
!TimestampUtils.isSameDay(date, previousItemDate)
} else true
}
override fun getHeaderViewForPosition(context: Context, position: Int): View {
val callLog = getItem(position)
val date = formatDate(context, callLog.startDate)
val date = formatDate(context, callLog.lastCallLog.startDate)
val binding: GenericListHeaderBinding = DataBindingUtil.inflate(
LayoutInflater.from(context),
R.layout.generic_list_header, null, false
@ -124,17 +126,17 @@ class CallLogsListAdapter(val selectionViewModel: ListTopBarViewModel) : Lifecyc
}
}
private class CallLogDiffCallback : DiffUtil.ItemCallback<CallLog>() {
private class CallLogDiffCallback : DiffUtil.ItemCallback<GroupedCallLogViewModel>() {
override fun areItemsTheSame(
oldItem: CallLog,
newItem: CallLog
oldItem: GroupedCallLogViewModel,
newItem: GroupedCallLogViewModel
): Boolean {
return oldItem.callId == newItem.callId
return oldItem.lastCallLog.callId == newItem.lastCallLog.callId
}
override fun areContentsTheSame(
oldItem: CallLog,
newItem: CallLog
oldItem: GroupedCallLogViewModel,
newItem: GroupedCallLogViewModel
): Boolean {
return false // For headers
}

View file

@ -38,10 +38,10 @@ 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.history.viewmodels.GroupedCallLogViewModel
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.*
@ -109,7 +109,7 @@ class MasterCallLogsFragment : MasterFragment() {
}
viewModel.showDeleteButton({
listViewModel.deleteCallLog(listViewModel.callLogs.value?.get(viewHolder.adapterPosition))
listViewModel.deleteCallLogGroup(adapter.getItemAt(viewHolder.adapterPosition))
dialog.dismiss()
}, getString(R.string.dialog_delete))
@ -156,7 +156,7 @@ class MasterCallLogsFragment : MasterFragment() {
adapter.selectedCallLogEvent.observe(viewLifecycleOwner, Observer {
it.consume { callLog ->
sharedViewModel.selectedCallLog.value = callLog
sharedViewModel.selectedCallLog.value = callLog.lastCallLog
if (!resources.getBoolean(R.bool.isTablet)) {
if (findNavController().currentDestination?.id == R.id.masterCallLogsFragment) {
findNavController().navigate(R.id.action_masterCallLogsFragment_to_detailCallLogFragment)
@ -212,12 +212,12 @@ class MasterCallLogsFragment : MasterFragment() {
}
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
val list = ArrayList<CallLog>()
val list = ArrayList<GroupedCallLogViewModel>()
for (index in indexesOfItemToDelete) {
val callLog = adapter.getItemAt(index)
list.add(callLog)
val callLogGroup = adapter.getItemAt(index)
list.add(callLogGroup)
}
listViewModel.deleteCallLogs(list)
listViewModel.deleteCallLogGroups(list)
}
private fun scrollToTop() {

View file

@ -26,10 +26,11 @@ import org.linphone.contact.ContactsUpdatedListenerStub
import org.linphone.core.*
import org.linphone.core.tools.Log
import org.linphone.utils.Event
import org.linphone.utils.TimestampUtils
class CallLogsListViewModel : ViewModel() {
val callLogs = MutableLiveData<ArrayList<CallLog>>()
val missedCallLogs = MutableLiveData<ArrayList<CallLog>>()
val callLogs = MutableLiveData<ArrayList<GroupedCallLogViewModel>>()
val missedCallLogs = MutableLiveData<ArrayList<GroupedCallLogViewModel>>()
val missedCallLogsSelected = MutableLiveData<Boolean>()
@ -70,47 +71,71 @@ 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())
fun deleteCallLogGroup(callLog: GroupedCallLogViewModel?) {
if (callLog != null) {
coreContext.core.removeCallLog(callLog)
list.remove(callLog)
missedList.remove(callLog)
for (log in callLog.callLogs) {
coreContext.core.removeCallLog(log)
}
}
callLogs.value = list
missedCallLogs.value = missedList
updateCallLogs()
}
fun deleteCallLogs(listToDelete: ArrayList<CallLog>) {
val list = arrayListOf<CallLog>()
list.addAll(callLogs.value.orEmpty())
val missedList = arrayListOf<CallLog>()
missedList.addAll(missedCallLogs.value.orEmpty())
fun deleteCallLogGroups(listToDelete: ArrayList<GroupedCallLogViewModel>) {
for (callLog in listToDelete) {
coreContext.core.removeCallLog(callLog)
list.remove(callLog)
missedList.remove(callLog)
for (log in callLog.callLogs) {
coreContext.core.removeCallLog(log)
}
}
callLogs.value = list
missedCallLogs.value = missedList
updateCallLogs()
}
private fun updateCallLogs() {
val list = arrayListOf<CallLog>()
val missedList = arrayListOf<CallLog>()
val list = arrayListOf<GroupedCallLogViewModel>()
val missedList = arrayListOf<GroupedCallLogViewModel>()
var previousCallLogGroup: GroupedCallLogViewModel? = null
var previousMissedCallLogGroup: GroupedCallLogViewModel? = null
for (callLog in coreContext.core.callLogs) {
list.add(callLog)
if (callLog.status == Call.Status.Missed) missedList.add(callLog)
if (previousCallLogGroup == null) {
previousCallLogGroup = GroupedCallLogViewModel(callLog)
} else if (previousCallLogGroup.lastCallLog.localAddress.weakEqual(callLog.localAddress) && previousCallLogGroup.lastCallLog.remoteAddress.weakEqual(callLog.remoteAddress)) {
if (TimestampUtils.isSameDay(previousCallLogGroup.lastCallLog.startDate, callLog.startDate)) {
previousCallLogGroup.callLogs.add(callLog)
previousCallLogGroup.lastCallLog = callLog
} else {
list.add(previousCallLogGroup)
previousCallLogGroup = GroupedCallLogViewModel(callLog)
}
} else {
list.add(previousCallLogGroup)
previousCallLogGroup = GroupedCallLogViewModel(callLog)
}
if (callLog.status == Call.Status.Missed) {
if (previousMissedCallLogGroup == null) {
previousMissedCallLogGroup = GroupedCallLogViewModel(callLog)
} else if (previousMissedCallLogGroup.lastCallLog.localAddress.weakEqual(callLog.localAddress) && previousMissedCallLogGroup.lastCallLog.remoteAddress.weakEqual(callLog.remoteAddress)) {
if (TimestampUtils.isSameDay(previousMissedCallLogGroup.lastCallLog.startDate, callLog.startDate)) {
previousMissedCallLogGroup.callLogs.add(callLog)
previousMissedCallLogGroup.lastCallLog = callLog
} else {
missedList.add(previousMissedCallLogGroup)
previousMissedCallLogGroup = GroupedCallLogViewModel(callLog)
}
} else {
missedList.add(previousMissedCallLogGroup)
previousMissedCallLogGroup = GroupedCallLogViewModel(callLog)
}
}
}
if (previousCallLogGroup != null && !list.contains(previousCallLogGroup)) {
list.add(previousCallLogGroup)
}
if (previousMissedCallLogGroup != null && !missedList.contains(previousMissedCallLogGroup)) {
missedList.add(previousMissedCallLogGroup)
}
callLogs.value = list

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2010-2020 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 <http://www.gnu.org/licenses/>.
*/
package org.linphone.activities.main.history.viewmodels
import org.linphone.core.CallLog
class GroupedCallLogViewModel(callLog: CallLog) {
var lastCallLog: CallLog = callLog
val callLogs = arrayListOf(callLog)
}

View file

@ -20,6 +20,9 @@
<variable
name="selectionListViewModel"
type="org.linphone.activities.main.viewmodels.ListTopBarViewModel" />
<variable
name="groupCount"
type="Integer"/>
</data>
<RelativeLayout
@ -53,7 +56,7 @@
<CheckBox
android:onClick="@{() -> selectionListViewModel.onToggleSelect(position)}"
android:visibility="@{selectionListViewModel.isEditionEnabled ? View.VISIBLE : View.GONE}"
android:visibility="@{selectionListViewModel.isEditionEnabled ? View.VISIBLE : View.GONE, default=gone}"
android:checked="@{selectionListViewModel.selectedItems.contains(position)}"
android:layout_width="wrap_content"
android:layout_height="match_parent"
@ -90,7 +93,7 @@
<org.linphone.views.MarqueeTextView
android:id="@+id/sip_uri"
android:text="@{viewModel.contact.fullName ?? viewModel.displayName}"
android:text="@{(viewModel.contact.fullName ?? viewModel.displayName) + (groupCount > 1 ? ` (` + groupCount + `)` : ``)}"
style="@style/contact_name_list_cell_font"
android:layout_width="wrap_content"
android:layout_height="match_parent"