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({
|
viewModel.showDeleteButton({
|
||||||
listViewModel.deleteChatRoom(listViewModel.chatRooms.value?.get(viewHolder.adapterPosition))
|
listViewModel.deleteChatRoom(adapter.getItemAt(viewHolder.adapterPosition))
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}, getString(R.string.dialog_delete))
|
}, getString(R.string.dialog_delete))
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ class MasterContactsFragment : MasterFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.showDeleteButton({
|
viewModel.showDeleteButton({
|
||||||
listViewModel.deleteContact(listViewModel.contactsList.value?.get(viewHolder.adapterPosition))
|
listViewModel.deleteContact(adapter.getItemAt(viewHolder.adapterPosition))
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}, getString(R.string.dialog_delete))
|
}, getString(R.string.dialog_delete))
|
||||||
|
|
||||||
|
|
|
@ -29,16 +29,16 @@ import androidx.lifecycle.Observer
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.activities.main.history.viewmodels.CallLogViewModel
|
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.activities.main.viewmodels.ListTopBarViewModel
|
||||||
import org.linphone.core.Address
|
import org.linphone.core.Address
|
||||||
import org.linphone.core.CallLog
|
|
||||||
import org.linphone.databinding.GenericListHeaderBinding
|
import org.linphone.databinding.GenericListHeaderBinding
|
||||||
import org.linphone.databinding.HistoryListCellBinding
|
import org.linphone.databinding.HistoryListCellBinding
|
||||||
import org.linphone.utils.*
|
import org.linphone.utils.*
|
||||||
|
|
||||||
class CallLogsListAdapter(val selectionViewModel: ListTopBarViewModel) : LifecycleListAdapter<CallLog, CallLogsListAdapter.ViewHolder>(CallLogDiffCallback()), HeaderAdapter {
|
class CallLogsListAdapter(val selectionViewModel: ListTopBarViewModel) : LifecycleListAdapter<GroupedCallLogViewModel, CallLogsListAdapter.ViewHolder>(CallLogDiffCallback()), HeaderAdapter {
|
||||||
val selectedCallLogEvent: MutableLiveData<Event<CallLog>> by lazy {
|
val selectedCallLogEvent: MutableLiveData<Event<GroupedCallLogViewModel>> by lazy {
|
||||||
MutableLiveData<Event<CallLog>>()
|
MutableLiveData<Event<GroupedCallLogViewModel>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
val startCallToEvent: MutableLiveData<Event<Address>> by lazy {
|
val startCallToEvent: MutableLiveData<Event<Address>> by lazy {
|
||||||
|
@ -62,9 +62,9 @@ class CallLogsListAdapter(val selectionViewModel: ListTopBarViewModel) : Lifecyc
|
||||||
inner class ViewHolder(
|
inner class ViewHolder(
|
||||||
private val binding: HistoryListCellBinding
|
private val binding: HistoryListCellBinding
|
||||||
) : LifecycleViewHolder(binding) {
|
) : LifecycleViewHolder(binding) {
|
||||||
fun bind(callLog: CallLog) {
|
fun bind(callLogGroup: GroupedCallLogViewModel) {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
val callLogViewModel = CallLogViewModel(callLog)
|
val callLogViewModel = CallLogViewModel(callLogGroup.lastCallLog)
|
||||||
viewModel = callLogViewModel
|
viewModel = callLogViewModel
|
||||||
|
|
||||||
// This is for item selection through ListTopBarFragment
|
// This is for item selection through ListTopBarFragment
|
||||||
|
@ -77,15 +77,17 @@ class CallLogsListAdapter(val selectionViewModel: ListTopBarViewModel) : Lifecyc
|
||||||
if (selectionViewModel.isEditionEnabled.value == true) {
|
if (selectionViewModel.isEditionEnabled.value == true) {
|
||||||
selectionViewModel.onToggleSelect(adapterPosition)
|
selectionViewModel.onToggleSelect(adapterPosition)
|
||||||
} else {
|
} else {
|
||||||
startCallToEvent.value = Event(callLog.remoteAddress)
|
startCallToEvent.value = Event(callLogGroup.lastCallLog.remoteAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This listener is disabled when in edition mode
|
// This listener is disabled when in edition mode
|
||||||
setDetailsClickListener {
|
setDetailsClickListener {
|
||||||
selectedCallLogEvent.value = Event(callLog)
|
selectedCallLogEvent.value = Event(callLogGroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
groupCount = callLogGroup.callLogs.size
|
||||||
|
|
||||||
executePendingBindings()
|
executePendingBindings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,18 +95,18 @@ class CallLogsListAdapter(val selectionViewModel: ListTopBarViewModel) : Lifecyc
|
||||||
|
|
||||||
override fun displayHeaderForPosition(position: Int): Boolean {
|
override fun displayHeaderForPosition(position: Int): Boolean {
|
||||||
if (position >= itemCount) return false
|
if (position >= itemCount) return false
|
||||||
val callLog = getItem(position)
|
val callLogGroup = getItem(position)
|
||||||
val date = callLog.startDate
|
val date = callLogGroup.lastCallLog.startDate
|
||||||
val previousPosition = position - 1
|
val previousPosition = position - 1
|
||||||
return if (previousPosition >= 0) {
|
return if (previousPosition >= 0) {
|
||||||
val previousItemDate = getItem(previousPosition).startDate
|
val previousItemDate = getItem(previousPosition).lastCallLog.startDate
|
||||||
!TimestampUtils.isSameDay(date, previousItemDate)
|
!TimestampUtils.isSameDay(date, previousItemDate)
|
||||||
} else true
|
} else true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getHeaderViewForPosition(context: Context, position: Int): View {
|
override fun getHeaderViewForPosition(context: Context, position: Int): View {
|
||||||
val callLog = getItem(position)
|
val callLog = getItem(position)
|
||||||
val date = formatDate(context, callLog.startDate)
|
val date = formatDate(context, callLog.lastCallLog.startDate)
|
||||||
val binding: GenericListHeaderBinding = DataBindingUtil.inflate(
|
val binding: GenericListHeaderBinding = DataBindingUtil.inflate(
|
||||||
LayoutInflater.from(context),
|
LayoutInflater.from(context),
|
||||||
R.layout.generic_list_header, null, false
|
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(
|
override fun areItemsTheSame(
|
||||||
oldItem: CallLog,
|
oldItem: GroupedCallLogViewModel,
|
||||||
newItem: CallLog
|
newItem: GroupedCallLogViewModel
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return oldItem.callId == newItem.callId
|
return oldItem.lastCallLog.callId == newItem.lastCallLog.callId
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun areContentsTheSame(
|
override fun areContentsTheSame(
|
||||||
oldItem: CallLog,
|
oldItem: GroupedCallLogViewModel,
|
||||||
newItem: CallLog
|
newItem: GroupedCallLogViewModel
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return false // For headers
|
return false // For headers
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,10 +38,10 @@ import org.linphone.R
|
||||||
import org.linphone.activities.main.fragments.MasterFragment
|
import org.linphone.activities.main.fragments.MasterFragment
|
||||||
import org.linphone.activities.main.history.adapters.CallLogsListAdapter
|
import org.linphone.activities.main.history.adapters.CallLogsListAdapter
|
||||||
import org.linphone.activities.main.history.viewmodels.CallLogsListViewModel
|
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.DialogViewModel
|
||||||
import org.linphone.activities.main.viewmodels.SharedMainViewModel
|
import org.linphone.activities.main.viewmodels.SharedMainViewModel
|
||||||
import org.linphone.activities.main.viewmodels.TabsViewModel
|
import org.linphone.activities.main.viewmodels.TabsViewModel
|
||||||
import org.linphone.core.CallLog
|
|
||||||
import org.linphone.core.tools.Log
|
import org.linphone.core.tools.Log
|
||||||
import org.linphone.databinding.HistoryMasterFragmentBinding
|
import org.linphone.databinding.HistoryMasterFragmentBinding
|
||||||
import org.linphone.utils.*
|
import org.linphone.utils.*
|
||||||
|
@ -109,7 +109,7 @@ class MasterCallLogsFragment : MasterFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.showDeleteButton({
|
viewModel.showDeleteButton({
|
||||||
listViewModel.deleteCallLog(listViewModel.callLogs.value?.get(viewHolder.adapterPosition))
|
listViewModel.deleteCallLogGroup(adapter.getItemAt(viewHolder.adapterPosition))
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}, getString(R.string.dialog_delete))
|
}, getString(R.string.dialog_delete))
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ class MasterCallLogsFragment : MasterFragment() {
|
||||||
|
|
||||||
adapter.selectedCallLogEvent.observe(viewLifecycleOwner, Observer {
|
adapter.selectedCallLogEvent.observe(viewLifecycleOwner, Observer {
|
||||||
it.consume { callLog ->
|
it.consume { callLog ->
|
||||||
sharedViewModel.selectedCallLog.value = callLog
|
sharedViewModel.selectedCallLog.value = callLog.lastCallLog
|
||||||
if (!resources.getBoolean(R.bool.isTablet)) {
|
if (!resources.getBoolean(R.bool.isTablet)) {
|
||||||
if (findNavController().currentDestination?.id == R.id.masterCallLogsFragment) {
|
if (findNavController().currentDestination?.id == R.id.masterCallLogsFragment) {
|
||||||
findNavController().navigate(R.id.action_masterCallLogsFragment_to_detailCallLogFragment)
|
findNavController().navigate(R.id.action_masterCallLogsFragment_to_detailCallLogFragment)
|
||||||
|
@ -212,12 +212,12 @@ class MasterCallLogsFragment : MasterFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
|
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
|
||||||
val list = ArrayList<CallLog>()
|
val list = ArrayList<GroupedCallLogViewModel>()
|
||||||
for (index in indexesOfItemToDelete) {
|
for (index in indexesOfItemToDelete) {
|
||||||
val callLog = adapter.getItemAt(index)
|
val callLogGroup = adapter.getItemAt(index)
|
||||||
list.add(callLog)
|
list.add(callLogGroup)
|
||||||
}
|
}
|
||||||
listViewModel.deleteCallLogs(list)
|
listViewModel.deleteCallLogGroups(list)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun scrollToTop() {
|
private fun scrollToTop() {
|
||||||
|
|
|
@ -26,10 +26,11 @@ import org.linphone.contact.ContactsUpdatedListenerStub
|
||||||
import org.linphone.core.*
|
import org.linphone.core.*
|
||||||
import org.linphone.core.tools.Log
|
import org.linphone.core.tools.Log
|
||||||
import org.linphone.utils.Event
|
import org.linphone.utils.Event
|
||||||
|
import org.linphone.utils.TimestampUtils
|
||||||
|
|
||||||
class CallLogsListViewModel : ViewModel() {
|
class CallLogsListViewModel : ViewModel() {
|
||||||
val callLogs = MutableLiveData<ArrayList<CallLog>>()
|
val callLogs = MutableLiveData<ArrayList<GroupedCallLogViewModel>>()
|
||||||
val missedCallLogs = MutableLiveData<ArrayList<CallLog>>()
|
val missedCallLogs = MutableLiveData<ArrayList<GroupedCallLogViewModel>>()
|
||||||
|
|
||||||
val missedCallLogsSelected = MutableLiveData<Boolean>()
|
val missedCallLogsSelected = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
@ -70,47 +71,71 @@ class CallLogsListViewModel : ViewModel() {
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteCallLog(callLog: CallLog?) {
|
fun deleteCallLogGroup(callLog: GroupedCallLogViewModel?) {
|
||||||
val list = arrayListOf<CallLog>()
|
|
||||||
list.addAll(callLogs.value.orEmpty())
|
|
||||||
|
|
||||||
val missedList = arrayListOf<CallLog>()
|
|
||||||
missedList.addAll(missedCallLogs.value.orEmpty())
|
|
||||||
|
|
||||||
if (callLog != null) {
|
if (callLog != null) {
|
||||||
coreContext.core.removeCallLog(callLog)
|
for (log in callLog.callLogs) {
|
||||||
list.remove(callLog)
|
coreContext.core.removeCallLog(log)
|
||||||
missedList.remove(callLog)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callLogs.value = list
|
updateCallLogs()
|
||||||
missedCallLogs.value = missedList
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteCallLogs(listToDelete: ArrayList<CallLog>) {
|
fun deleteCallLogGroups(listToDelete: ArrayList<GroupedCallLogViewModel>) {
|
||||||
val list = arrayListOf<CallLog>()
|
|
||||||
list.addAll(callLogs.value.orEmpty())
|
|
||||||
|
|
||||||
val missedList = arrayListOf<CallLog>()
|
|
||||||
missedList.addAll(missedCallLogs.value.orEmpty())
|
|
||||||
|
|
||||||
for (callLog in listToDelete) {
|
for (callLog in listToDelete) {
|
||||||
coreContext.core.removeCallLog(callLog)
|
for (log in callLog.callLogs) {
|
||||||
list.remove(callLog)
|
coreContext.core.removeCallLog(log)
|
||||||
missedList.remove(callLog)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callLogs.value = list
|
updateCallLogs()
|
||||||
missedCallLogs.value = missedList
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateCallLogs() {
|
private fun updateCallLogs() {
|
||||||
val list = arrayListOf<CallLog>()
|
val list = arrayListOf<GroupedCallLogViewModel>()
|
||||||
val missedList = arrayListOf<CallLog>()
|
val missedList = arrayListOf<GroupedCallLogViewModel>()
|
||||||
|
|
||||||
|
var previousCallLogGroup: GroupedCallLogViewModel? = null
|
||||||
|
var previousMissedCallLogGroup: GroupedCallLogViewModel? = null
|
||||||
for (callLog in coreContext.core.callLogs) {
|
for (callLog in coreContext.core.callLogs) {
|
||||||
list.add(callLog)
|
if (previousCallLogGroup == null) {
|
||||||
if (callLog.status == Call.Status.Missed) missedList.add(callLog)
|
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
|
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
|
<variable
|
||||||
name="selectionListViewModel"
|
name="selectionListViewModel"
|
||||||
type="org.linphone.activities.main.viewmodels.ListTopBarViewModel" />
|
type="org.linphone.activities.main.viewmodels.ListTopBarViewModel" />
|
||||||
|
<variable
|
||||||
|
name="groupCount"
|
||||||
|
type="Integer"/>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
@ -53,7 +56,7 @@
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:onClick="@{() -> selectionListViewModel.onToggleSelect(position)}"
|
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:checked="@{selectionListViewModel.selectedItems.contains(position)}"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -90,7 +93,7 @@
|
||||||
|
|
||||||
<org.linphone.views.MarqueeTextView
|
<org.linphone.views.MarqueeTextView
|
||||||
android:id="@+id/sip_uri"
|
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"
|
style="@style/contact_name_list_cell_font"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
Loading…
Reference in a new issue