Grouped call logs in history for a shorter list
This commit is contained in:
parent
5e540dce71
commit
cadd5a84b2
7 changed files with 116 additions and 59 deletions
|
@ -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))
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue