Update history details when a call is finished and we go back to it + fixed landscape layout vertical scrolling in history details

This commit is contained in:
Sylvain Berfini 2021-11-17 16:10:17 +01:00
parent 09cb05c923
commit 250c06ec06
8 changed files with 193 additions and 146 deletions

View file

@ -65,7 +65,7 @@ class CallLogsListAdapter(
) : RecyclerView.ViewHolder(binding.root) {
fun bind(callLogGroup: GroupedCallLogData) {
with(binding) {
val callLogViewModel = callLogGroup.lastCallLogViewModel
val callLogViewModel = callLogGroup.lastCallLogData
viewModel = callLogViewModel
lifecycleOwner = viewLifecycleOwner

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2010-2021 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.data
import java.text.SimpleDateFormat
import java.util.*
import org.linphone.R
import org.linphone.contact.GenericContactData
import org.linphone.core.Call
import org.linphone.core.CallLog
import org.linphone.utils.TimestampUtils
class CallLogData(callLog: CallLog) : GenericContactData(callLog.remoteAddress) {
val statusIconResource: Int by lazy {
if (callLog.dir == Call.Dir.Incoming) {
if (callLog.status == Call.Status.Missed) {
R.drawable.call_status_missed
} else {
R.drawable.call_status_incoming
}
} else {
R.drawable.call_status_outgoing
}
}
val iconContentDescription: Int by lazy {
if (callLog.dir == Call.Dir.Incoming) {
if (callLog.status == Call.Status.Missed) {
R.string.content_description_missed_call
} else {
R.string.content_description_incoming_call
}
} else {
R.string.content_description_outgoing_call
}
}
val directionIconResource: Int by lazy {
if (callLog.dir == Call.Dir.Incoming) {
if (callLog.status == Call.Status.Missed) {
R.drawable.call_missed
} else {
R.drawable.call_incoming
}
} else {
R.drawable.call_outgoing
}
}
val duration: String by lazy {
val dateFormat = SimpleDateFormat(if (callLog.duration >= 3600) "HH:mm:ss" else "mm:ss", Locale.getDefault())
val cal = Calendar.getInstance()
cal[0, 0, 0, 0, 0] = callLog.duration
dateFormat.format(cal.time)
}
val date: String by lazy {
TimestampUtils.toString(callLog.startDate, shortDate = false, hideYear = false)
}
}

View file

@ -19,15 +19,14 @@
*/
package org.linphone.activities.main.history.data
import org.linphone.activities.main.history.viewmodels.CallLogViewModel
import org.linphone.core.CallLog
class GroupedCallLogData(callLog: CallLog) {
var lastCallLog: CallLog = callLog
val callLogs = arrayListOf(callLog)
val lastCallLogViewModel = CallLogViewModel(lastCallLog)
val lastCallLogData = CallLogData(lastCallLog)
fun destroy() {
lastCallLogViewModel.destroy()
lastCallLogData.destroy()
}
}

View file

@ -70,7 +70,7 @@ class DetailCallLogFragment : GenericFragment<HistoryDetailFragmentBinding>() {
useMaterialSharedAxisXForwardAnimation = sharedViewModel.isSlidingPaneSlideable.value == false
viewModel.relatedCallLogs.value = callLogGroup.callLogs
viewModel.addRelatedCallLogs(callLogGroup.callLogs)
binding.setBackClickListener {
goBack()

View file

@ -22,17 +22,17 @@ package org.linphone.activities.main.history.viewmodels
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.R
import org.linphone.activities.main.history.data.CallLogData
import org.linphone.contact.GenericContactViewModel
import org.linphone.core.*
import org.linphone.core.tools.Log
import org.linphone.utils.Event
import org.linphone.utils.LinphoneUtils
import org.linphone.utils.TimestampUtils
class CallLogViewModelFactory(private val callLog: CallLog) :
ViewModelProvider.NewInstanceFactory() {
@ -48,53 +48,6 @@ class CallLogViewModel(val callLog: CallLog) : GenericContactViewModel(callLog.r
LinphoneUtils.getDisplayableAddress(callLog.remoteAddress)
}
val statusIconResource: Int by lazy {
if (callLog.dir == Call.Dir.Incoming) {
if (callLog.status == Call.Status.Missed) {
R.drawable.call_status_missed
} else {
R.drawable.call_status_incoming
}
} else {
R.drawable.call_status_outgoing
}
}
val iconContentDescription: Int by lazy {
if (callLog.dir == Call.Dir.Incoming) {
if (callLog.status == Call.Status.Missed) {
R.string.content_description_missed_call
} else {
R.string.content_description_incoming_call
}
} else {
R.string.content_description_outgoing_call
}
}
val directionIconResource: Int by lazy {
if (callLog.dir == Call.Dir.Incoming) {
if (callLog.status == Call.Status.Missed) {
R.drawable.call_missed
} else {
R.drawable.call_incoming
}
} else {
R.drawable.call_outgoing
}
}
val duration: String by lazy {
val dateFormat = SimpleDateFormat(if (callLog.duration >= 3600) "HH:mm:ss" else "mm:ss", Locale.getDefault())
val cal = Calendar.getInstance()
cal[0, 0, 0, 0, 0] = callLog.duration
dateFormat.format(cal.time)
}
val date: String by lazy {
TimestampUtils.toString(callLog.startDate, shortDate = false, hideYear = false)
}
val startCallEvent: MutableLiveData<Event<CallLog>> by lazy {
MutableLiveData<Event<CallLog>>()
}
@ -109,7 +62,16 @@ class CallLogViewModel(val callLog: CallLog) : GenericContactViewModel(callLog.r
val secureChatAllowed = contact.value?.friend?.getPresenceModelForUriOrTel(peerSipUri)?.hasCapability(FriendCapability.LimeX3Dh) ?: false
val relatedCallLogs = MutableLiveData<ArrayList<CallLog>>()
val relatedCallLogs = MutableLiveData<ArrayList<CallLogData>>()
private val listener = object : CoreListenerStub() {
override fun onCallLogUpdated(core: Core, log: CallLog) {
if (callLog.remoteAddress.weakEqual(log.remoteAddress) && callLog.localAddress.weakEqual(log.localAddress)) {
Log.i("[History Detail] New call log for ${callLog.remoteAddress.asStringUriOnly()} with local address ${callLog.localAddress.asStringUriOnly()}")
addRelatedCallLogs(arrayListOf(log))
}
}
}
private val chatRoomListener = object : ChatRoomListenerStub() {
override fun onStateChanged(chatRoom: ChatRoom, state: ChatRoom.State) {
@ -126,14 +88,19 @@ class CallLogViewModel(val callLog: CallLog) : GenericContactViewModel(callLog.r
init {
waitForChatRoomCreation.value = false
coreContext.core.addListener(listener)
}
override fun onCleared() {
coreContext.core.removeListener(listener)
destroy()
super.onCleared()
}
fun destroy() {
relatedCallLogs.value.orEmpty().forEach(CallLogData::destroy)
}
fun startCall() {
@ -157,11 +124,15 @@ class CallLogViewModel(val callLog: CallLog) : GenericContactViewModel(callLog.r
}
}
fun getCallsHistory(): ArrayList<CallLogViewModel> {
val callsHistory = ArrayList<CallLogViewModel>()
for (callLog in relatedCallLogs.value.orEmpty()) {
callsHistory.add(CallLogViewModel(callLog))
fun addRelatedCallLogs(logs: ArrayList<CallLog>) {
val callsHistory = ArrayList<CallLogData>()
// We assume new logs are more recent than the ones we already have, so we add them first
for (log in logs) {
callsHistory.add(CallLogData(log))
}
return callsHistory
callsHistory.addAll(relatedCallLogs.value.orEmpty())
relatedCallLogs.value = callsHistory
}
}

View file

@ -5,7 +5,7 @@
<import type="android.view.View"/>
<variable
name="data"
type="org.linphone.activities.main.history.viewmodels.CallLogViewModel" />
type="org.linphone.activities.main.history.data.CallLogData" />
</data>
<RelativeLayout

View file

@ -74,119 +74,119 @@
</LinearLayout>
<LinearLayout
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/top_bar"
android:gravity="center"
android:orientation="vertical"
android:paddingTop="10dp"
android:paddingBottom="5dp">
<org.linphone.contact.BigContactAvatarView
android:id="@+id/avatar"
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center"
android:layout_marginTop="10dp"
bind:layout="@layout/contact_avatar_big"
app:viewModel="@{viewModel}"/>
<TextView
android:text="@{viewModel.contact.fullName ?? viewModel.displayName}"
style="@style/big_contact_name_font"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal" />
<org.linphone.views.MarqueeTextView
android:text="@{viewModel.peerSipUri}"
style="@style/sip_uri_font"
android:singleLine="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
android:layout_height="match_parent"
android:layout_below="@id/top_bar">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
android:orientation="vertical"
android:paddingTop="10dp"
android:paddingBottom="5dp">
<ImageView
android:onClick="@{() -> viewModel.startCall()}"
android:contentDescription="@string/content_description_start_call"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="10dp"
android:background="@drawable/round_orange_button_background"
android:src="@drawable/call_start_default" />
<org.linphone.contact.BigContactAvatarView
android:id="@+id/avatar"
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center"
android:layout_marginTop="10dp"
bind:layout="@layout/contact_avatar_big"
app:viewModel="@{viewModel}"/>
<ImageView
android:onClick="@{() -> viewModel.startChat(false)}"
android:visibility="@{viewModel.chatAllowed ? View.VISIBLE : View.GONE}"
android:contentDescription="@string/content_description_start_chat"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="10dp"
android:background="@drawable/round_orange_button_background"
android:src="@drawable/chat_start_default" />
<TextView
android:text="@{viewModel.contact.fullName ?? viewModel.displayName}"
style="@style/big_contact_name_font"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal" />
<RelativeLayout
android:onClick="@{() -> viewModel.startChat(true)}"
android:visibility="@{viewModel.chatAllowed &amp;&amp; viewModel.secureChatAllowed ? View.VISIBLE : View.GONE}"
android:layout_width="65dp"
android:layout_height="60dp"
android:layout_margin="10dp">
<org.linphone.views.MarqueeTextView
android:text="@{viewModel.peerSipUri}"
style="@style/sip_uri_font"
android:singleLine="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:onClick="@{() -> viewModel.startCall()}"
android:contentDescription="@string/content_description_start_call"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:contentDescription="@string/content_description_start_encrypted_chat"
android:layout_margin="10dp"
android:background="@drawable/round_orange_button_background"
android:src="@drawable/call_start_default" />
<ImageView
android:onClick="@{() -> viewModel.startChat(false)}"
android:visibility="@{viewModel.chatAllowed ? View.VISIBLE : View.GONE}"
android:contentDescription="@string/content_description_start_chat"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="10dp"
android:background="@drawable/round_orange_button_background"
android:src="@drawable/chat_start_default" />
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:contentDescription="@string/content_description_start_encrypted_chat"
android:src="@drawable/security_toggle_icon_green" />
<RelativeLayout
android:onClick="@{() -> viewModel.startChat(true)}"
android:visibility="@{viewModel.chatAllowed &amp;&amp; viewModel.secureChatAllowed ? View.VISIBLE : View.GONE}"
android:layout_width="65dp"
android:layout_height="60dp"
android:layout_margin="10dp">
</RelativeLayout>
<ImageView
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:contentDescription="@string/content_description_start_encrypted_chat"
android:background="@drawable/round_orange_button_background"
android:src="@drawable/chat_start_default" />
</LinearLayout>
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:contentDescription="@string/content_description_start_encrypted_chat"
android:src="@drawable/security_toggle_icon_green" />
<View
android:layout_width="wrap_content"
android:layout_height="1dp"
android:background="?attr/dividerColor" />
</RelativeLayout>
<TextView
style="@style/assistant_input_field_header_font"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="5dp"
android:text="@string/history_calls_list"
android:textAllCaps="true" />
</LinearLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:layout_width="wrap_content"
android:layout_height="1dp"
android:background="?attr/dividerColor" />
<TextView
style="@style/assistant_input_field_header_font"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="5dp"
android:text="@string/history_calls_list"
android:textAllCaps="true" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:entries="@{viewModel.callsHistory}"
app:entries="@{viewModel.relatedCallLogs}"
app:layout="@{@layout/history_detail_cell}"/>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<include
layout="@layout/wait_layout"

View file

@ -19,7 +19,7 @@
type="Integer"/>
<variable
name="viewModel"
type="org.linphone.activities.main.history.viewmodels.CallLogViewModel" />
type="org.linphone.activities.main.history.data.CallLogData" />
<variable
name="selectionListViewModel"
type="org.linphone.activities.main.viewmodels.ListTopBarViewModel" />