mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 11:28:06 +00:00
Update some info dynamically
This commit is contained in:
parent
d9b6f0482a
commit
8269228b8a
8 changed files with 167 additions and 59 deletions
|
|
@ -125,7 +125,7 @@ class ConversationFragment : GenericFragment() {
|
|||
}
|
||||
|
||||
adapter = ConversationEventAdapter(viewLifecycleOwner)
|
||||
binding.eventsList.setHasFixedSize(false)
|
||||
binding.eventsList.setHasFixedSize(true)
|
||||
binding.eventsList.adapter = adapter
|
||||
|
||||
val layoutManager = LinearLayoutManager(requireContext())
|
||||
|
|
@ -142,9 +142,11 @@ class ConversationFragment : GenericFragment() {
|
|||
adapter.submitList(items)
|
||||
Log.i("$TAG Events (messages) list updated with [${items.size}] items")
|
||||
|
||||
(view.parent as? ViewGroup)?.doOnPreDraw {
|
||||
startPostponedEnterTransition()
|
||||
sharedViewModel.openSlidingPaneEvent.value = Event(true)
|
||||
if (currentCount == 0 && items.isNotEmpty()) {
|
||||
(view.parent as? ViewGroup)?.doOnPreDraw {
|
||||
startPostponedEnterTransition()
|
||||
sharedViewModel.openSlidingPaneEvent.value = Event(true)
|
||||
}
|
||||
}
|
||||
|
||||
if (currentCount < items.size) {
|
||||
|
|
|
|||
|
|
@ -24,9 +24,13 @@ import androidx.annotation.WorkerThread
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.R
|
||||
import org.linphone.core.Address
|
||||
import org.linphone.core.ChatMessage
|
||||
import org.linphone.core.ChatMessageListenerStub
|
||||
import org.linphone.core.ChatRoom
|
||||
import org.linphone.core.ChatRoom.Capabilities
|
||||
import org.linphone.core.ChatRoomListenerStub
|
||||
import org.linphone.core.EventLog
|
||||
import org.linphone.core.Friend
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.ui.main.contacts.model.ContactAvatarModel
|
||||
|
|
@ -62,7 +66,7 @@ class ConversationModel @WorkerThread constructor(private val chatRoom: ChatRoom
|
|||
|
||||
val composingLabel = MutableLiveData<Boolean>()
|
||||
|
||||
val lastMessage = MutableLiveData<String>()
|
||||
val lastMessageText = MutableLiveData<String>()
|
||||
|
||||
val lastMessageIcon = MutableLiveData<Int>()
|
||||
|
||||
|
|
@ -76,9 +80,47 @@ class ConversationModel @WorkerThread constructor(private val chatRoom: ChatRoom
|
|||
|
||||
val groupAvatarModel: GroupAvatarModel
|
||||
|
||||
private var lastMessage: ChatMessage? = null
|
||||
|
||||
private val chatRoomListener = object : ChatRoomListenerStub() {
|
||||
@WorkerThread
|
||||
override fun onIsComposingReceived(
|
||||
chatRoom: ChatRoom,
|
||||
remoteAddress: Address,
|
||||
isComposing: Boolean
|
||||
) {
|
||||
computeComposingLabel()
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun onMessagesReceived(chatRoom: ChatRoom, chatMessages: Array<out ChatMessage>) {
|
||||
updateLastMessage()
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun onChatMessageSending(chatRoom: ChatRoom, eventLog: EventLog) {
|
||||
updateLastMessage()
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun onChatRoomRead(chatRoom: ChatRoom) {
|
||||
unreadMessageCount.postValue(chatRoom.unreadMessagesCount)
|
||||
}
|
||||
}
|
||||
|
||||
private val chatMessageListener = object : ChatMessageListenerStub() {
|
||||
@WorkerThread
|
||||
override fun onMsgStateChanged(message: ChatMessage, state: ChatMessage.State?) {
|
||||
updateLastMessageStatus(message)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
chatRoom.addListener(chatRoomListener)
|
||||
|
||||
subject.postValue(chatRoom.subject)
|
||||
lastUpdateTime.postValue(chatRoom.lastUpdateTime)
|
||||
computeComposingLabel()
|
||||
|
||||
val friends = arrayListOf<Friend>()
|
||||
val address = if (chatRoom.hasCapability(Capabilities.Basic.toInt())) {
|
||||
|
|
@ -123,6 +165,14 @@ class ConversationModel @WorkerThread constructor(private val chatRoom: ChatRoom
|
|||
unreadMessageCount.postValue(chatRoom.unreadMessagesCount)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun destroy() {
|
||||
lastMessage?.removeListener(chatMessageListener)
|
||||
lastMessage = null
|
||||
|
||||
chatRoom.removeListener(chatRoomListener)
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun markAsRead() {
|
||||
coreContext.postOnCoreThread {
|
||||
|
|
@ -171,37 +221,55 @@ class ConversationModel @WorkerThread constructor(private val chatRoom: ChatRoom
|
|||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun updateLastMessageStatus(message: ChatMessage) {
|
||||
val text = LinphoneUtils.getTextDescribingMessage(message)
|
||||
lastMessageText.postValue(text)
|
||||
|
||||
val isOutgoing = message.isOutgoing
|
||||
isLastMessageOutgoing.postValue(isOutgoing)
|
||||
if (isOutgoing) {
|
||||
val icon = when (message.state) {
|
||||
ChatMessage.State.Displayed -> {
|
||||
R.drawable.checks
|
||||
}
|
||||
|
||||
ChatMessage.State.DeliveredToUser -> {
|
||||
R.drawable.check
|
||||
}
|
||||
|
||||
ChatMessage.State.Delivered -> {
|
||||
R.drawable.sent
|
||||
}
|
||||
|
||||
ChatMessage.State.InProgress, ChatMessage.State.FileTransferInProgress -> {
|
||||
R.drawable.in_progress
|
||||
}
|
||||
|
||||
ChatMessage.State.NotDelivered, ChatMessage.State.FileTransferError -> {
|
||||
R.drawable.warning_circle
|
||||
}
|
||||
|
||||
else -> {
|
||||
R.drawable.info
|
||||
}
|
||||
}
|
||||
lastMessageIcon.postValue(icon)
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun updateLastMessage() {
|
||||
lastMessage?.removeListener(chatMessageListener)
|
||||
lastMessage = null
|
||||
|
||||
val message = chatRoom.lastMessageInHistory
|
||||
if (message != null) {
|
||||
val text = LinphoneUtils.getTextDescribingMessage(message)
|
||||
lastMessage.postValue(text)
|
||||
updateLastMessageStatus(message)
|
||||
|
||||
val isOutgoing = message.isOutgoing
|
||||
isLastMessageOutgoing.postValue(isOutgoing)
|
||||
if (isOutgoing) {
|
||||
val icon = when (message.state) {
|
||||
ChatMessage.State.Displayed -> {
|
||||
R.drawable.checks
|
||||
}
|
||||
ChatMessage.State.DeliveredToUser -> {
|
||||
R.drawable.check
|
||||
}
|
||||
ChatMessage.State.Delivered -> {
|
||||
R.drawable.sent
|
||||
}
|
||||
ChatMessage.State.InProgress, ChatMessage.State.FileTransferInProgress -> {
|
||||
R.drawable.in_progress
|
||||
}
|
||||
ChatMessage.State.NotDelivered, ChatMessage.State.FileTransferError -> {
|
||||
R.drawable.warning_circle
|
||||
}
|
||||
else -> {
|
||||
R.drawable.info
|
||||
}
|
||||
}
|
||||
lastMessageIcon.postValue(icon)
|
||||
if (message.isOutgoing && message.state != ChatMessage.State.Displayed) {
|
||||
message.addListener(chatMessageListener)
|
||||
lastMessage = message
|
||||
}
|
||||
} else {
|
||||
Log.w("$TAG No last message to display for chat room [$id]")
|
||||
|
|
@ -225,4 +293,9 @@ class ConversationModel @WorkerThread constructor(private val chatRoom: ChatRoom
|
|||
}
|
||||
dateTime.postValue(humanReadableTimestamp)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun computeComposingLabel() {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ class ConversationsListViewModel @UiThread constructor() : AbstractTopBarViewMod
|
|||
super.onCleared()
|
||||
|
||||
coreContext.postOnCoreThread { core ->
|
||||
conversations.value.orEmpty().forEach(ConversationModel::destroy)
|
||||
coreContext.contactsManager.removeListener(contactsListener)
|
||||
core.removeListener(coreListener)
|
||||
}
|
||||
|
|
@ -103,6 +104,8 @@ class ConversationsListViewModel @UiThread constructor() : AbstractTopBarViewMod
|
|||
|
||||
@WorkerThread
|
||||
private fun computeChatRoomsList(filter: String) {
|
||||
conversations.value.orEmpty().forEach(ConversationModel::destroy)
|
||||
|
||||
if (conversations.value.orEmpty().isEmpty()) {
|
||||
fetchInProgress.postValue(true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,29 +95,7 @@ class MeetingFragment : GenericFragment() {
|
|||
}
|
||||
|
||||
binding.setShareClickListener {
|
||||
val intent = Intent(Intent.ACTION_EDIT)
|
||||
intent.type = "vnd.android.cursor.item/event"
|
||||
intent.putExtra(CalendarContract.Events.TITLE, viewModel.subject.value)
|
||||
|
||||
val description = viewModel.description.value.orEmpty()
|
||||
if (description.isNotEmpty()) {
|
||||
intent.putExtra(CalendarContract.Events.DESCRIPTION, description)
|
||||
}
|
||||
|
||||
intent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, viewModel.startTimeStamp.value)
|
||||
intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, viewModel.endTimeStamp.value)
|
||||
|
||||
intent.putExtra(CalendarContract.Events.CUSTOM_APP_URI, viewModel.sipUri.value)
|
||||
intent.putExtra(
|
||||
CalendarContract.Events.CUSTOM_APP_PACKAGE,
|
||||
requireContext().packageName
|
||||
)
|
||||
|
||||
try {
|
||||
startActivity(intent)
|
||||
} catch (exception: ActivityNotFoundException) {
|
||||
Log.e("$TAG No activity found to handle intent: $exception")
|
||||
}
|
||||
shareMeetingInfoAsCalendarEvent()
|
||||
}
|
||||
|
||||
binding.setMenuClickListener {
|
||||
|
|
@ -180,4 +158,30 @@ class MeetingFragment : GenericFragment() {
|
|||
popupWindow.elevation = 20f
|
||||
popupWindow.showAsDropDown(binding.menu, 0, 0, Gravity.BOTTOM)
|
||||
}
|
||||
|
||||
private fun shareMeetingInfoAsCalendarEvent() {
|
||||
val intent = Intent(Intent.ACTION_EDIT)
|
||||
intent.type = "vnd.android.cursor.item/event"
|
||||
intent.putExtra(CalendarContract.Events.TITLE, viewModel.subject.value)
|
||||
|
||||
val description = viewModel.description.value.orEmpty()
|
||||
if (description.isNotEmpty()) {
|
||||
intent.putExtra(CalendarContract.Events.DESCRIPTION, description)
|
||||
}
|
||||
|
||||
intent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, viewModel.startTimeStamp.value)
|
||||
intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, viewModel.endTimeStamp.value)
|
||||
|
||||
intent.putExtra(CalendarContract.Events.CUSTOM_APP_URI, viewModel.sipUri.value)
|
||||
intent.putExtra(
|
||||
CalendarContract.Events.CUSTOM_APP_PACKAGE,
|
||||
requireContext().packageName
|
||||
)
|
||||
|
||||
try {
|
||||
startActivity(intent)
|
||||
} catch (exception: ActivityNotFoundException) {
|
||||
Log.e("${MeetingFragment.TAG} No activity found to handle intent: $exception")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ import org.linphone.LinphoneApplication.Companion.coreContext
|
|||
import org.linphone.R
|
||||
import org.linphone.core.Account
|
||||
import org.linphone.core.AccountListenerStub
|
||||
import org.linphone.core.ChatMessage
|
||||
import org.linphone.core.ChatRoom
|
||||
import org.linphone.core.Core
|
||||
import org.linphone.core.CoreListenerStub
|
||||
import org.linphone.core.RegistrationState
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.utils.AppUtils
|
||||
|
|
@ -75,8 +79,25 @@ class AccountModel @WorkerThread constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private val coreListener = object : CoreListenerStub() {
|
||||
@WorkerThread
|
||||
override fun onChatRoomRead(core: Core, chatRoom: ChatRoom) {
|
||||
computeNotificationsCount()
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun onMessagesReceived(
|
||||
core: Core,
|
||||
chatRoom: ChatRoom,
|
||||
messages: Array<out ChatMessage>
|
||||
) {
|
||||
computeNotificationsCount()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
account.addListener(accountListener)
|
||||
coreContext.core.addListener(coreListener)
|
||||
|
||||
showTrust.postValue(account.isInSecureMode())
|
||||
|
||||
|
|
@ -85,6 +106,7 @@ class AccountModel @WorkerThread constructor(
|
|||
|
||||
@WorkerThread
|
||||
fun destroy() {
|
||||
coreContext.core.removeListener(coreListener)
|
||||
account.removeListener(accountListener)
|
||||
}
|
||||
|
||||
|
|
@ -139,7 +161,7 @@ class AccountModel @WorkerThread constructor(
|
|||
}
|
||||
|
||||
isDefault.postValue(coreContext.core.defaultAccount == account)
|
||||
notificationsCount.postValue(account.unreadChatMessageCount + account.missedCallsCount)
|
||||
computeNotificationsCount()
|
||||
|
||||
val state = account.state
|
||||
registrationState.postValue(state)
|
||||
|
|
@ -187,6 +209,11 @@ class AccountModel @WorkerThread constructor(
|
|||
}
|
||||
registrationStateSummary.postValue(summary)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun computeNotificationsCount() {
|
||||
notificationsCount.postValue(account.unreadChatMessageCount + account.missedCallsCount)
|
||||
}
|
||||
}
|
||||
|
||||
fun Account.isInSecureMode(): Boolean {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
<ImageView
|
||||
android:id="@+id/emojis_background"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/chat_bubble_long_press_menu_emojis_height"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/shape_squircle_white_background"
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@
|
|||
android:gravity="center_vertical|start"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
android:text="@{model.isComposing ? model.composingLabel : model.lastMessage, default=`Hello there!`}"
|
||||
android:text="@{model.isComposing ? model.composingLabel : model.lastMessageText, default=`Hello there!`}"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/gray_main2_400"
|
||||
android:textStyle="@{model.unreadMessageCount > 0 ? Typeface.BOLD : Typeface.NORMAL}"
|
||||
|
|
|
|||
|
|
@ -55,6 +55,5 @@
|
|||
|
||||
<dimen name="chat_bubble_grouped_top_margin">4dp</dimen>
|
||||
<dimen name="chat_bubble_top_margin">16dp</dimen>
|
||||
<dimen name="chat_bubble_long_press_menu_emojis_height">60dp</dimen>
|
||||
<dimen name="chat_bubble_long_press_menu_bubble_offset">105dp</dimen>
|
||||
<dimen name="chat_bubble_long_press_menu_bubble_offset">110dp</dimen>
|
||||
</resources>
|
||||
Loading…
Add table
Reference in a new issue