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:
parent
09cb05c923
commit
250c06ec06
8 changed files with 193 additions and 146 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 && 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 && 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"
|
||||
|
|
|
@ -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" />
|
||||
|
|
Loading…
Reference in a new issue