Fixed more leaks
This commit is contained in:
parent
ebda69e739
commit
2433921f22
22 changed files with 290 additions and 261 deletions
|
@ -27,8 +27,10 @@ import android.view.MenuItem
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
|
@ -42,10 +44,12 @@ import org.linphone.core.EventLog
|
||||||
import org.linphone.databinding.ChatEventListCellBinding
|
import org.linphone.databinding.ChatEventListCellBinding
|
||||||
import org.linphone.databinding.ChatMessageListCellBinding
|
import org.linphone.databinding.ChatMessageListCellBinding
|
||||||
import org.linphone.utils.Event
|
import org.linphone.utils.Event
|
||||||
import org.linphone.utils.LifecycleListAdapter
|
import org.linphone.utils.SelectionListAdapter
|
||||||
import org.linphone.utils.LifecycleViewHolder
|
|
||||||
|
|
||||||
class ChatMessagesListAdapter(val selectionViewModel: ListTopBarViewModel) : LifecycleListAdapter<EventLog, LifecycleViewHolder>(ChatMessageDiffCallback()) {
|
class ChatMessagesListAdapter(
|
||||||
|
selectionVM: ListTopBarViewModel,
|
||||||
|
private val viewLifecycleOwner: LifecycleOwner
|
||||||
|
) : SelectionListAdapter<EventLog, RecyclerView.ViewHolder>(selectionVM, ChatMessageDiffCallback()) {
|
||||||
companion object {
|
companion object {
|
||||||
const val MAX_TIME_TO_GROUP_MESSAGES = 60 // 1 minute
|
const val MAX_TIME_TO_GROUP_MESSAGES = 60 // 1 minute
|
||||||
}
|
}
|
||||||
|
@ -80,7 +84,7 @@ class ChatMessagesListAdapter(val selectionViewModel: ListTopBarViewModel) : Lif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LifecycleViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
EventLog.Type.ConferenceChatMessage.toInt() -> createChatMessageViewHolder(parent)
|
EventLog.Type.ConferenceChatMessage.toInt() -> createChatMessageViewHolder(parent)
|
||||||
else -> createEventViewHolder(parent)
|
else -> createEventViewHolder(parent)
|
||||||
|
@ -92,9 +96,7 @@ class ChatMessagesListAdapter(val selectionViewModel: ListTopBarViewModel) : Lif
|
||||||
LayoutInflater.from(parent.context),
|
LayoutInflater.from(parent.context),
|
||||||
R.layout.chat_message_list_cell, parent, false
|
R.layout.chat_message_list_cell, parent, false
|
||||||
)
|
)
|
||||||
val viewHolder = ChatMessageViewHolder(binding)
|
return ChatMessageViewHolder(binding)
|
||||||
binding.lifecycleOwner = viewHolder
|
|
||||||
return viewHolder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createEventViewHolder(parent: ViewGroup): EventViewHolder {
|
private fun createEventViewHolder(parent: ViewGroup): EventViewHolder {
|
||||||
|
@ -102,12 +104,10 @@ class ChatMessagesListAdapter(val selectionViewModel: ListTopBarViewModel) : Lif
|
||||||
LayoutInflater.from(parent.context),
|
LayoutInflater.from(parent.context),
|
||||||
R.layout.chat_event_list_cell, parent, false
|
R.layout.chat_event_list_cell, parent, false
|
||||||
)
|
)
|
||||||
val viewHolder = EventViewHolder(binding)
|
return EventViewHolder(binding)
|
||||||
binding.lifecycleOwner = viewHolder
|
|
||||||
return viewHolder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: LifecycleViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
val eventLog = getItem(position)
|
val eventLog = getItem(position)
|
||||||
when (holder) {
|
when (holder) {
|
||||||
is ChatMessageViewHolder -> holder.bind(eventLog)
|
is ChatMessageViewHolder -> holder.bind(eventLog)
|
||||||
|
@ -122,7 +122,7 @@ class ChatMessagesListAdapter(val selectionViewModel: ListTopBarViewModel) : Lif
|
||||||
|
|
||||||
inner class ChatMessageViewHolder(
|
inner class ChatMessageViewHolder(
|
||||||
private val binding: ChatMessageListCellBinding
|
private val binding: ChatMessageListCellBinding
|
||||||
) : LifecycleViewHolder(binding), PopupMenu.OnMenuItemClickListener {
|
) : RecyclerView.ViewHolder(binding.root), PopupMenu.OnMenuItemClickListener {
|
||||||
fun bind(eventLog: EventLog) {
|
fun bind(eventLog: EventLog) {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
if (eventLog.type == EventLog.Type.ConferenceChatMessage) {
|
if (eventLog.type == EventLog.Type.ConferenceChatMessage) {
|
||||||
|
@ -131,9 +131,11 @@ class ChatMessagesListAdapter(val selectionViewModel: ListTopBarViewModel) : Lif
|
||||||
val chatMessageViewModel = ChatMessageViewModel(chatMessage, contentClickedListener)
|
val chatMessageViewModel = ChatMessageViewModel(chatMessage, contentClickedListener)
|
||||||
viewModel = chatMessageViewModel
|
viewModel = chatMessageViewModel
|
||||||
|
|
||||||
|
binding.lifecycleOwner = viewLifecycleOwner
|
||||||
|
|
||||||
// This is for item selection through ListTopBarFragment
|
// This is for item selection through ListTopBarFragment
|
||||||
selectionListViewModel = selectionViewModel
|
selectionListViewModel = selectionViewModel
|
||||||
selectionViewModel.isEditionEnabled.observe(this@ChatMessageViewHolder, {
|
selectionViewModel.isEditionEnabled.observe(viewLifecycleOwner, {
|
||||||
position = adapterPosition
|
position = adapterPosition
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -284,15 +286,17 @@ class ChatMessagesListAdapter(val selectionViewModel: ListTopBarViewModel) : Lif
|
||||||
|
|
||||||
inner class EventViewHolder(
|
inner class EventViewHolder(
|
||||||
private val binding: ChatEventListCellBinding
|
private val binding: ChatEventListCellBinding
|
||||||
) : LifecycleViewHolder(binding) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
fun bind(eventLog: EventLog) {
|
fun bind(eventLog: EventLog) {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
val eventViewModel = EventViewModel(eventLog)
|
val eventViewModel = EventViewModel(eventLog)
|
||||||
viewModel = eventViewModel
|
viewModel = eventViewModel
|
||||||
|
|
||||||
|
binding.lifecycleOwner = viewLifecycleOwner
|
||||||
|
|
||||||
// This is for item selection through ListTopBarFragment
|
// This is for item selection through ListTopBarFragment
|
||||||
selectionListViewModel = selectionViewModel
|
selectionListViewModel = selectionViewModel
|
||||||
selectionViewModel.isEditionEnabled.observe(this@EventViewHolder, {
|
selectionViewModel.isEditionEnabled.observe(viewLifecycleOwner, {
|
||||||
position = adapterPosition
|
position = adapterPosition
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,11 @@ package org.linphone.activities.main.chat.adapters
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.activities.main.chat.viewmodels.ChatRoomCreationContactViewModel
|
import org.linphone.activities.main.chat.viewmodels.ChatRoomCreationContactViewModel
|
||||||
|
@ -32,51 +35,57 @@ import org.linphone.core.FriendCapability
|
||||||
import org.linphone.core.SearchResult
|
import org.linphone.core.SearchResult
|
||||||
import org.linphone.databinding.ChatRoomCreationContactCellBinding
|
import org.linphone.databinding.ChatRoomCreationContactCellBinding
|
||||||
import org.linphone.utils.Event
|
import org.linphone.utils.Event
|
||||||
import org.linphone.utils.LifecycleListAdapter
|
|
||||||
import org.linphone.utils.LifecycleViewHolder
|
|
||||||
|
|
||||||
class ChatRoomCreationContactsAdapter : LifecycleListAdapter<SearchResult, ChatRoomCreationContactsAdapter.ViewHolder>(SearchResultDiffCallback()) {
|
class ChatRoomCreationContactsAdapter(
|
||||||
|
private val viewLifecycleOwner: LifecycleOwner
|
||||||
|
) : ListAdapter<SearchResult, RecyclerView.ViewHolder>(SearchResultDiffCallback()) {
|
||||||
val selectedContact = MutableLiveData<Event<SearchResult>>()
|
val selectedContact = MutableLiveData<Event<SearchResult>>()
|
||||||
|
|
||||||
val selectedAddresses = MutableLiveData<ArrayList<Address>>()
|
|
||||||
|
|
||||||
var groupChatEnabled: Boolean = false
|
var groupChatEnabled: Boolean = false
|
||||||
|
|
||||||
val securityEnabled = MutableLiveData<Boolean>()
|
private var selectedAddresses = ArrayList<Address>()
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
private var securityEnabled: Boolean = false
|
||||||
|
|
||||||
|
fun updateSelectedAddresses(selection: ArrayList<Address>) {
|
||||||
|
selectedAddresses = selection
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateSecurity(enabled: Boolean) {
|
||||||
|
securityEnabled = enabled
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val binding: ChatRoomCreationContactCellBinding = DataBindingUtil.inflate(
|
val binding: ChatRoomCreationContactCellBinding = DataBindingUtil.inflate(
|
||||||
LayoutInflater.from(parent.context),
|
LayoutInflater.from(parent.context),
|
||||||
R.layout.chat_room_creation_contact_cell, parent, false
|
R.layout.chat_room_creation_contact_cell, parent, false
|
||||||
)
|
)
|
||||||
val viewHolder = ViewHolder(binding)
|
return ViewHolder(binding)
|
||||||
binding.lifecycleOwner = viewHolder
|
|
||||||
return viewHolder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
holder.bind(getItem(position))
|
(holder as ViewHolder).bind(getItem(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(
|
inner class ViewHolder(
|
||||||
private val binding: ChatRoomCreationContactCellBinding
|
private val binding: ChatRoomCreationContactCellBinding
|
||||||
) : LifecycleViewHolder(binding) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
fun bind(searchResult: SearchResult) {
|
fun bind(searchResult: SearchResult) {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
val searchResultViewModel = ChatRoomCreationContactViewModel(searchResult)
|
val searchResultViewModel = ChatRoomCreationContactViewModel(searchResult)
|
||||||
viewModel = searchResultViewModel
|
viewModel = searchResultViewModel
|
||||||
|
|
||||||
securityEnabled.observe(this@ViewHolder, {
|
binding.lifecycleOwner = viewLifecycleOwner
|
||||||
updateSecurity(searchResult, searchResultViewModel, it)
|
|
||||||
})
|
|
||||||
|
|
||||||
selectedAddresses.observe(this@ViewHolder, {
|
updateSecurity(searchResult, searchResultViewModel, securityEnabled)
|
||||||
val selected = it.find { address ->
|
|
||||||
|
val selected = selectedAddresses.find { address ->
|
||||||
val searchAddress = searchResult.address
|
val searchAddress = searchResult.address
|
||||||
if (searchAddress != null) address.weakEqual(searchAddress) else false
|
if (searchAddress != null) address.weakEqual(searchAddress) else false
|
||||||
}
|
}
|
||||||
searchResultViewModel.isSelected.value = selected != null
|
searchResultViewModel.isSelected.value = selected != null
|
||||||
})
|
|
||||||
|
|
||||||
setClickListener {
|
setClickListener {
|
||||||
selectedContact.value = Event(searchResult)
|
selectedContact.value = Event(searchResult)
|
||||||
|
|
|
@ -22,47 +22,55 @@ package org.linphone.activities.main.chat.adapters
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.activities.main.chat.viewmodels.ChatRoomViewModel
|
import org.linphone.activities.main.chat.viewmodels.ChatRoomViewModel
|
||||||
import org.linphone.activities.main.viewmodels.ListTopBarViewModel
|
import org.linphone.activities.main.viewmodels.ListTopBarViewModel
|
||||||
import org.linphone.core.ChatRoom
|
import org.linphone.core.ChatRoom
|
||||||
import org.linphone.databinding.ChatRoomListCellBinding
|
import org.linphone.databinding.ChatRoomListCellBinding
|
||||||
import org.linphone.utils.Event
|
import org.linphone.utils.Event
|
||||||
import org.linphone.utils.LifecycleListAdapter
|
import org.linphone.utils.SelectionListAdapter
|
||||||
import org.linphone.utils.LifecycleViewHolder
|
|
||||||
|
|
||||||
class ChatRoomsListAdapter(val selectionViewModel: ListTopBarViewModel) : LifecycleListAdapter<ChatRoom, ChatRoomsListAdapter.ViewHolder>(ChatRoomDiffCallback()) {
|
class ChatRoomsListAdapter(
|
||||||
|
selectionVM: ListTopBarViewModel,
|
||||||
|
private val viewLifecycleOwner: LifecycleOwner
|
||||||
|
) : SelectionListAdapter<ChatRoom, RecyclerView.ViewHolder>(selectionVM, ChatRoomDiffCallback()) {
|
||||||
val selectedChatRoomEvent: MutableLiveData<Event<ChatRoom>> by lazy {
|
val selectedChatRoomEvent: MutableLiveData<Event<ChatRoom>> by lazy {
|
||||||
MutableLiveData<Event<ChatRoom>>()
|
MutableLiveData<Event<ChatRoom>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val toggledPositionForSelectionEvent: MutableLiveData<Event<Int>> by lazy {
|
||||||
|
MutableLiveData<Event<Int>>()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
val binding: ChatRoomListCellBinding = DataBindingUtil.inflate(
|
val binding: ChatRoomListCellBinding = DataBindingUtil.inflate(
|
||||||
LayoutInflater.from(parent.context),
|
LayoutInflater.from(parent.context),
|
||||||
R.layout.chat_room_list_cell, parent, false
|
R.layout.chat_room_list_cell, parent, false
|
||||||
)
|
)
|
||||||
val viewHolder = ViewHolder(binding)
|
return ViewHolder(binding)
|
||||||
binding.lifecycleOwner = viewHolder
|
|
||||||
return viewHolder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
holder.bind(getItem(position))
|
(holder as ViewHolder).bind(getItem(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(
|
inner class ViewHolder(
|
||||||
private val binding: ChatRoomListCellBinding
|
private val binding: ChatRoomListCellBinding
|
||||||
) : LifecycleViewHolder(binding) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
fun bind(chatRoom: ChatRoom) {
|
fun bind(chatRoom: ChatRoom) {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
val chatRoomViewModel = ChatRoomViewModel(chatRoom)
|
val chatRoomViewModel = ChatRoomViewModel(chatRoom)
|
||||||
viewModel = chatRoomViewModel
|
viewModel = chatRoomViewModel
|
||||||
|
|
||||||
|
binding.lifecycleOwner = viewLifecycleOwner
|
||||||
|
|
||||||
// This is for item selection through ListTopBarFragment
|
// This is for item selection through ListTopBarFragment
|
||||||
selectionListViewModel = selectionViewModel
|
selectionListViewModel = selectionViewModel
|
||||||
selectionViewModel.isEditionEnabled.observe(this@ViewHolder, {
|
selectionViewModel.isEditionEnabled.observe(viewLifecycleOwner, {
|
||||||
position = adapterPosition
|
position = adapterPosition
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -22,18 +22,21 @@ package org.linphone.activities.main.chat.adapters
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.activities.main.chat.GroupChatRoomMember
|
import org.linphone.activities.main.chat.GroupChatRoomMember
|
||||||
import org.linphone.activities.main.chat.viewmodels.GroupInfoParticipantViewModel
|
import org.linphone.activities.main.chat.viewmodels.GroupInfoParticipantViewModel
|
||||||
import org.linphone.databinding.ChatRoomGroupInfoParticipantCellBinding
|
import org.linphone.databinding.ChatRoomGroupInfoParticipantCellBinding
|
||||||
import org.linphone.utils.Event
|
import org.linphone.utils.Event
|
||||||
import org.linphone.utils.LifecycleListAdapter
|
|
||||||
import org.linphone.utils.LifecycleViewHolder
|
|
||||||
|
|
||||||
class GroupInfoParticipantsAdapter(private val isEncryptionEnabled: Boolean) : LifecycleListAdapter<GroupChatRoomMember,
|
class GroupInfoParticipantsAdapter(
|
||||||
GroupInfoParticipantsAdapter.ViewHolder>(ParticipantDiffCallback()) {
|
private val viewLifecycleOwner: LifecycleOwner,
|
||||||
|
private val isEncryptionEnabled: Boolean
|
||||||
|
) : ListAdapter<GroupChatRoomMember, RecyclerView.ViewHolder>(ParticipantDiffCallback()) {
|
||||||
private var showAdmin: Boolean = false
|
private var showAdmin: Boolean = false
|
||||||
|
|
||||||
val participantRemovedEvent: MutableLiveData<Event<GroupChatRoomMember>> by lazy {
|
val participantRemovedEvent: MutableLiveData<Event<GroupChatRoomMember>> by lazy {
|
||||||
|
@ -45,13 +48,11 @@ class GroupInfoParticipantsAdapter(private val isEncryptionEnabled: Boolean) : L
|
||||||
LayoutInflater.from(parent.context),
|
LayoutInflater.from(parent.context),
|
||||||
R.layout.chat_room_group_info_participant_cell, parent, false
|
R.layout.chat_room_group_info_participant_cell, parent, false
|
||||||
)
|
)
|
||||||
val viewHolder = ViewHolder(binding)
|
return ViewHolder(binding)
|
||||||
binding.lifecycleOwner = viewHolder
|
|
||||||
return viewHolder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
holder.bind(getItem(position))
|
(holder as ViewHolder).bind(getItem(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showAdminControls(show: Boolean) {
|
fun showAdminControls(show: Boolean) {
|
||||||
|
@ -61,13 +62,15 @@ class GroupInfoParticipantsAdapter(private val isEncryptionEnabled: Boolean) : L
|
||||||
|
|
||||||
inner class ViewHolder(
|
inner class ViewHolder(
|
||||||
private val binding: ChatRoomGroupInfoParticipantCellBinding
|
private val binding: ChatRoomGroupInfoParticipantCellBinding
|
||||||
) : LifecycleViewHolder(binding) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
fun bind(participant: GroupChatRoomMember) {
|
fun bind(participant: GroupChatRoomMember) {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
val participantViewModel = GroupInfoParticipantViewModel(participant)
|
val participantViewModel = GroupInfoParticipantViewModel(participant)
|
||||||
participantViewModel.showAdminControls.value = showAdmin
|
participantViewModel.showAdminControls.value = showAdmin
|
||||||
viewModel = participantViewModel
|
viewModel = participantViewModel
|
||||||
|
|
||||||
|
binding.lifecycleOwner = viewLifecycleOwner
|
||||||
|
|
||||||
setRemoveClickListener {
|
setRemoveClickListener {
|
||||||
participantRemovedEvent.value = Event(participant)
|
participantRemovedEvent.value = Event(participant)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,10 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.activities.main.chat.viewmodels.ImdnParticipantViewModel
|
import org.linphone.activities.main.chat.viewmodels.ImdnParticipantViewModel
|
||||||
import org.linphone.core.ChatMessage
|
import org.linphone.core.ChatMessage
|
||||||
|
@ -33,31 +35,30 @@ import org.linphone.core.ParticipantImdnState
|
||||||
import org.linphone.databinding.ChatRoomImdnParticipantCellBinding
|
import org.linphone.databinding.ChatRoomImdnParticipantCellBinding
|
||||||
import org.linphone.databinding.ImdnListHeaderBinding
|
import org.linphone.databinding.ImdnListHeaderBinding
|
||||||
import org.linphone.utils.HeaderAdapter
|
import org.linphone.utils.HeaderAdapter
|
||||||
import org.linphone.utils.LifecycleViewHolder
|
|
||||||
|
|
||||||
class ImdnAdapter : ListAdapter<ParticipantImdnState,
|
class ImdnAdapter(
|
||||||
ImdnAdapter.ViewHolder>(ParticipantImdnStateDiffCallback()), HeaderAdapter {
|
private val viewLifecycleOwner: LifecycleOwner
|
||||||
|
) : ListAdapter<ParticipantImdnState, RecyclerView.ViewHolder>(ParticipantImdnStateDiffCallback()), HeaderAdapter {
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
val binding: ChatRoomImdnParticipantCellBinding = DataBindingUtil.inflate(
|
val binding: ChatRoomImdnParticipantCellBinding = DataBindingUtil.inflate(
|
||||||
LayoutInflater.from(parent.context),
|
LayoutInflater.from(parent.context),
|
||||||
R.layout.chat_room_imdn_participant_cell, parent, false
|
R.layout.chat_room_imdn_participant_cell, parent, false
|
||||||
)
|
)
|
||||||
val viewHolder = ViewHolder(binding)
|
return ViewHolder(binding)
|
||||||
binding.lifecycleOwner = viewHolder
|
|
||||||
return viewHolder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
holder.bind(getItem(position))
|
(holder as ViewHolder).bind(getItem(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewHolder(
|
inner class ViewHolder(
|
||||||
private val binding: ChatRoomImdnParticipantCellBinding
|
private val binding: ChatRoomImdnParticipantCellBinding
|
||||||
) : LifecycleViewHolder(binding) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
fun bind(participantImdnState: ParticipantImdnState) {
|
fun bind(participantImdnState: ParticipantImdnState) {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
val imdnViewModel = ImdnParticipantViewModel(participantImdnState)
|
viewModel = ImdnParticipantViewModel(participantImdnState)
|
||||||
viewModel = imdnViewModel
|
|
||||||
|
binding.lifecycleOwner = viewLifecycleOwner
|
||||||
|
|
||||||
executePendingBindings()
|
executePendingBindings()
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,9 +59,9 @@ class ChatRoomCreationFragment : GenericFragment<ChatRoomCreationFragmentBinding
|
||||||
|
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
adapter = ChatRoomCreationContactsAdapter()
|
adapter = ChatRoomCreationContactsAdapter(viewLifecycleOwner)
|
||||||
adapter.groupChatEnabled = viewModel.createGroupChat.value == true
|
adapter.groupChatEnabled = viewModel.createGroupChat.value == true
|
||||||
adapter.securityEnabled.value = viewModel.isEncrypted.value == true
|
adapter.updateSecurity(viewModel.isEncrypted.value == true)
|
||||||
binding.contactsList.adapter = adapter
|
binding.contactsList.adapter = adapter
|
||||||
|
|
||||||
val layoutManager = LinearLayoutManager(activity)
|
val layoutManager = LinearLayoutManager(activity)
|
||||||
|
@ -90,7 +90,7 @@ class ChatRoomCreationFragment : GenericFragment<ChatRoomCreationFragmentBinding
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.isEncrypted.observe(viewLifecycleOwner, {
|
viewModel.isEncrypted.observe(viewLifecycleOwner, {
|
||||||
adapter.securityEnabled.value = it
|
adapter.updateSecurity(it)
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.sipContactsSelected.observe(viewLifecycleOwner, {
|
viewModel.sipContactsSelected.observe(viewLifecycleOwner, {
|
||||||
|
@ -98,7 +98,7 @@ class ChatRoomCreationFragment : GenericFragment<ChatRoomCreationFragmentBinding
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.selectedAddresses.observe(viewLifecycleOwner, {
|
viewModel.selectedAddresses.observe(viewLifecycleOwner, {
|
||||||
adapter.selectedAddresses.value = it
|
adapter.updateSelectedAddresses(it)
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.chatRoomCreatedEvent.observe(viewLifecycleOwner, {
|
viewModel.chatRoomCreatedEvent.observe(viewLifecycleOwner, {
|
||||||
|
|
|
@ -56,18 +56,33 @@ import org.linphone.databinding.ChatRoomDetailFragmentBinding
|
||||||
import org.linphone.utils.*
|
import org.linphone.utils.*
|
||||||
import org.linphone.utils.Event
|
import org.linphone.utils.Event
|
||||||
|
|
||||||
class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding>() {
|
class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, ChatMessagesListAdapter>() {
|
||||||
private lateinit var viewModel: ChatRoomViewModel
|
private lateinit var viewModel: ChatRoomViewModel
|
||||||
private lateinit var chatSendingViewModel: ChatMessageSendingViewModel
|
private lateinit var chatSendingViewModel: ChatMessageSendingViewModel
|
||||||
private lateinit var listViewModel: ChatMessagesListViewModel
|
private lateinit var listViewModel: ChatMessagesListViewModel
|
||||||
private lateinit var adapter: ChatMessagesListAdapter
|
|
||||||
private lateinit var sharedViewModel: SharedMainViewModel
|
private lateinit var sharedViewModel: SharedMainViewModel
|
||||||
|
|
||||||
|
private val observer = object : RecyclerView.AdapterDataObserver() {
|
||||||
|
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
||||||
|
if (positionStart == adapter.itemCount - 1) {
|
||||||
|
adapter.notifyItemChanged(positionStart - 1) // For grouping purposes
|
||||||
|
scrollToBottom()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var chatRoomAddress: String? = null
|
private var chatRoomAddress: String? = null
|
||||||
|
|
||||||
override fun getLayoutId(): Int {
|
override fun getLayoutId(): Int {
|
||||||
return R.layout.chat_room_detail_fragment
|
return R.layout.chat_room_detail_fragment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
binding.chatMessagesList.adapter = null
|
||||||
|
adapter.unregisterAdapterDataObserver(observer)
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
@ -98,18 +113,11 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding>() {
|
||||||
ChatMessagesListViewModelFactory(chatRoom)
|
ChatMessagesListViewModelFactory(chatRoom)
|
||||||
)[ChatMessagesListViewModel::class.java]
|
)[ChatMessagesListViewModel::class.java]
|
||||||
|
|
||||||
adapter = ChatMessagesListAdapter(listSelectionViewModel)
|
_adapter = ChatMessagesListAdapter(listSelectionViewModel, viewLifecycleOwner)
|
||||||
// SubmitList is done on a background thread
|
// SubmitList is done on a background thread
|
||||||
// We need this adapter data observer to know when to scroll
|
// We need this adapter data observer to know when to scroll
|
||||||
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
|
||||||
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
|
||||||
if (positionStart == adapter.itemCount - 1) {
|
|
||||||
adapter.notifyItemChanged(positionStart - 1) // For grouping purposes
|
|
||||||
scrollToBottom()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
binding.chatMessagesList.adapter = adapter
|
binding.chatMessagesList.adapter = adapter
|
||||||
|
adapter.registerAdapterDataObserver(observer)
|
||||||
|
|
||||||
val layoutManager = LinearLayoutManager(activity)
|
val layoutManager = LinearLayoutManager(activity)
|
||||||
layoutManager.stackFromEnd = true
|
layoutManager.stackFromEnd = true
|
||||||
|
@ -265,7 +273,7 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding>() {
|
||||||
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
|
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
|
||||||
val list = ArrayList<EventLog>()
|
val list = ArrayList<EventLog>()
|
||||||
for (index in indexesOfItemToDelete) {
|
for (index in indexesOfItemToDelete) {
|
||||||
val eventLog = adapter.getItemAt(index)
|
val eventLog = adapter.currentList[index]
|
||||||
list.add(eventLog)
|
list.add(eventLog)
|
||||||
}
|
}
|
||||||
listViewModel.deleteEventLogs(list)
|
listViewModel.deleteEventLogs(list)
|
||||||
|
|
|
@ -67,7 +67,10 @@ class GroupInfoFragment : GenericFragment<ChatRoomGroupInfoFragmentBinding>() {
|
||||||
|
|
||||||
viewModel.isEncrypted.value = sharedViewModel.createEncryptedChatRoom
|
viewModel.isEncrypted.value = sharedViewModel.createEncryptedChatRoom
|
||||||
|
|
||||||
adapter = GroupInfoParticipantsAdapter(chatRoom?.hasCapability(ChatRoomCapabilities.Encrypted.toInt()) ?: viewModel.isEncrypted.value == true)
|
adapter = GroupInfoParticipantsAdapter(
|
||||||
|
viewLifecycleOwner,
|
||||||
|
chatRoom?.hasCapability(ChatRoomCapabilities.Encrypted.toInt()) ?: viewModel.isEncrypted.value == true
|
||||||
|
)
|
||||||
binding.participants.adapter = adapter
|
binding.participants.adapter = adapter
|
||||||
|
|
||||||
val layoutManager = LinearLayoutManager(activity)
|
val layoutManager = LinearLayoutManager(activity)
|
||||||
|
|
|
@ -76,7 +76,7 @@ class ImdnFragment : GenericFragment<ChatRoomImdnFragmentBinding>() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter = ImdnAdapter()
|
adapter = ImdnAdapter(viewLifecycleOwner)
|
||||||
binding.participantsList.adapter = adapter
|
binding.participantsList.adapter = adapter
|
||||||
|
|
||||||
val layoutManager = LinearLayoutManager(activity)
|
val layoutManager = LinearLayoutManager(activity)
|
||||||
|
|
|
@ -43,14 +43,31 @@ import org.linphone.core.tools.Log
|
||||||
import org.linphone.databinding.ChatRoomMasterFragmentBinding
|
import org.linphone.databinding.ChatRoomMasterFragmentBinding
|
||||||
import org.linphone.utils.*
|
import org.linphone.utils.*
|
||||||
|
|
||||||
class MasterChatRoomsFragment : MasterFragment<ChatRoomMasterFragmentBinding>() {
|
class MasterChatRoomsFragment : MasterFragment<ChatRoomMasterFragmentBinding, ChatRoomsListAdapter>() {
|
||||||
override val dialogConfirmationMessageBeforeRemoval = R.plurals.chat_room_delete_dialog
|
override val dialogConfirmationMessageBeforeRemoval = R.plurals.chat_room_delete_dialog
|
||||||
private lateinit var listViewModel: ChatRoomsListViewModel
|
private lateinit var listViewModel: ChatRoomsListViewModel
|
||||||
private lateinit var adapter: ChatRoomsListAdapter
|
|
||||||
private lateinit var sharedViewModel: SharedMainViewModel
|
private lateinit var sharedViewModel: SharedMainViewModel
|
||||||
|
|
||||||
|
private val observer = object : RecyclerView.AdapterDataObserver() {
|
||||||
|
override fun onChanged() {
|
||||||
|
scrollToTop()
|
||||||
|
}
|
||||||
|
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
||||||
|
scrollToTop()
|
||||||
|
}
|
||||||
|
override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
|
||||||
|
scrollToTop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun getLayoutId(): Int = R.layout.chat_room_master_fragment
|
override fun getLayoutId(): Int = R.layout.chat_room_master_fragment
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
binding.chatList.adapter = null
|
||||||
|
adapter.unregisterAdapterDataObserver(observer)
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
@ -63,20 +80,10 @@ class MasterChatRoomsFragment : MasterFragment<ChatRoomMasterFragmentBinding>()
|
||||||
ViewModelProvider(this).get(SharedMainViewModel::class.java)
|
ViewModelProvider(this).get(SharedMainViewModel::class.java)
|
||||||
} ?: throw Exception("Invalid Activity")
|
} ?: throw Exception("Invalid Activity")
|
||||||
|
|
||||||
adapter = ChatRoomsListAdapter(listSelectionViewModel)
|
_adapter = ChatRoomsListAdapter(listSelectionViewModel, viewLifecycleOwner)
|
||||||
// SubmitList is done on a background thread
|
// SubmitList is done on a background thread
|
||||||
// We need this adapter data observer to know when to scroll
|
// We need this adapter data observer to know when to scroll
|
||||||
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
adapter.registerAdapterDataObserver(observer)
|
||||||
override fun onChanged() {
|
|
||||||
scrollToTop()
|
|
||||||
}
|
|
||||||
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
|
||||||
scrollToTop()
|
|
||||||
}
|
|
||||||
override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
|
|
||||||
scrollToTop()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
binding.chatList.adapter = adapter
|
binding.chatList.adapter = adapter
|
||||||
|
|
||||||
val layoutManager = LinearLayoutManager(activity)
|
val layoutManager = LinearLayoutManager(activity)
|
||||||
|
@ -100,7 +107,7 @@ class MasterChatRoomsFragment : MasterFragment<ChatRoomMasterFragmentBinding>()
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.showDeleteButton({
|
viewModel.showDeleteButton({
|
||||||
listViewModel.deleteChatRoom(adapter.getItemAt(viewHolder.adapterPosition))
|
listViewModel.deleteChatRoom(adapter.currentList[viewHolder.adapterPosition])
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}, getString(R.string.dialog_delete))
|
}, getString(R.string.dialog_delete))
|
||||||
|
|
||||||
|
@ -136,6 +143,12 @@ class MasterChatRoomsFragment : MasterFragment<ChatRoomMasterFragmentBinding>()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
adapter.toggledPositionForSelectionEvent.observe(viewLifecycleOwner, {
|
||||||
|
it.consume { position ->
|
||||||
|
listSelectionViewModel.onToggleSelect(position)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
binding.setEditClickListener {
|
binding.setEditClickListener {
|
||||||
listSelectionViewModel.isEditionEnabled.value = true
|
listSelectionViewModel.isEditionEnabled.value = true
|
||||||
}
|
}
|
||||||
|
@ -201,7 +214,7 @@ class MasterChatRoomsFragment : MasterFragment<ChatRoomMasterFragmentBinding>()
|
||||||
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
|
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
|
||||||
val list = ArrayList<ChatRoom>()
|
val list = ArrayList<ChatRoom>()
|
||||||
for (index in indexesOfItemToDelete) {
|
for (index in indexesOfItemToDelete) {
|
||||||
val chatRoom = adapter.getItemAt(index)
|
val chatRoom = adapter.currentList[index]
|
||||||
list.add(chatRoom)
|
list.add(chatRoom)
|
||||||
}
|
}
|
||||||
listViewModel.deleteChatRooms(list)
|
listViewModel.deleteChatRooms(list)
|
||||||
|
|
|
@ -40,7 +40,7 @@ import org.linphone.utils.TimestampUtils
|
||||||
|
|
||||||
class ChatMessageViewModel(
|
class ChatMessageViewModel(
|
||||||
val chatMessage: ChatMessage,
|
val chatMessage: ChatMessage,
|
||||||
private val contentListener: OnContentClickedListener? = null
|
private var contentListener: OnContentClickedListener? = null
|
||||||
) : GenericContactViewModel(chatMessage.fromAddress) {
|
) : GenericContactViewModel(chatMessage.fromAddress) {
|
||||||
val sendInProgress = MutableLiveData<Boolean>()
|
val sendInProgress = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
@ -114,6 +114,7 @@ class ChatMessageViewModel(
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
chatMessage.removeListener(listener)
|
chatMessage.removeListener(listener)
|
||||||
|
contentListener = null
|
||||||
|
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,10 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.activities.main.contact.viewmodels.ContactViewModel
|
import org.linphone.activities.main.contact.viewmodels.ContactViewModel
|
||||||
import org.linphone.activities.main.viewmodels.ListTopBarViewModel
|
import org.linphone.activities.main.viewmodels.ListTopBarViewModel
|
||||||
|
@ -34,10 +36,12 @@ import org.linphone.databinding.ContactListCellBinding
|
||||||
import org.linphone.databinding.GenericListHeaderBinding
|
import org.linphone.databinding.GenericListHeaderBinding
|
||||||
import org.linphone.utils.Event
|
import org.linphone.utils.Event
|
||||||
import org.linphone.utils.HeaderAdapter
|
import org.linphone.utils.HeaderAdapter
|
||||||
import org.linphone.utils.LifecycleListAdapter
|
import org.linphone.utils.SelectionListAdapter
|
||||||
import org.linphone.utils.LifecycleViewHolder
|
|
||||||
|
|
||||||
class ContactsListAdapter(val selectionViewModel: ListTopBarViewModel) : LifecycleListAdapter<Contact, ContactsListAdapter.ViewHolder>(ContactDiffCallback()), HeaderAdapter {
|
class ContactsListAdapter(
|
||||||
|
selectionVM: ListTopBarViewModel,
|
||||||
|
private val viewLifecycleOwner: LifecycleOwner
|
||||||
|
) : SelectionListAdapter<Contact, RecyclerView.ViewHolder>(selectionVM, ContactDiffCallback()), HeaderAdapter {
|
||||||
val selectedContactEvent: MutableLiveData<Event<Contact>> by lazy {
|
val selectedContactEvent: MutableLiveData<Event<Contact>> by lazy {
|
||||||
MutableLiveData<Event<Contact>>()
|
MutableLiveData<Event<Contact>>()
|
||||||
}
|
}
|
||||||
|
@ -47,26 +51,26 @@ class ContactsListAdapter(val selectionViewModel: ListTopBarViewModel) : Lifecyc
|
||||||
LayoutInflater.from(parent.context),
|
LayoutInflater.from(parent.context),
|
||||||
R.layout.contact_list_cell, parent, false
|
R.layout.contact_list_cell, parent, false
|
||||||
)
|
)
|
||||||
val viewHolder = ViewHolder(binding)
|
return ViewHolder(binding)
|
||||||
binding.lifecycleOwner = viewHolder
|
|
||||||
return viewHolder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
holder.bind(getItem(position))
|
(holder as ViewHolder).bind(getItem(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(
|
inner class ViewHolder(
|
||||||
private val binding: ContactListCellBinding
|
private val binding: ContactListCellBinding
|
||||||
) : LifecycleViewHolder(binding) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
fun bind(contact: Contact) {
|
fun bind(contact: Contact) {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
val contactViewModel = ContactViewModel(contact)
|
val contactViewModel = ContactViewModel(contact)
|
||||||
viewModel = contactViewModel
|
viewModel = contactViewModel
|
||||||
|
|
||||||
|
binding.lifecycleOwner = viewLifecycleOwner
|
||||||
|
|
||||||
// This is for item selection through ListTopBarFragment
|
// This is for item selection through ListTopBarFragment
|
||||||
selectionListViewModel = selectionViewModel
|
selectionListViewModel = selectionViewModel
|
||||||
selectionViewModel.isEditionEnabled.observe(this@ViewHolder, {
|
selectionViewModel.isEditionEnabled.observe(viewLifecycleOwner, {
|
||||||
position = adapterPosition
|
position = adapterPosition
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -44,10 +44,9 @@ import org.linphone.core.tools.Log
|
||||||
import org.linphone.databinding.ContactMasterFragmentBinding
|
import org.linphone.databinding.ContactMasterFragmentBinding
|
||||||
import org.linphone.utils.*
|
import org.linphone.utils.*
|
||||||
|
|
||||||
class MasterContactsFragment : MasterFragment<ContactMasterFragmentBinding>() {
|
class MasterContactsFragment : MasterFragment<ContactMasterFragmentBinding, ContactsListAdapter>() {
|
||||||
override val dialogConfirmationMessageBeforeRemoval = R.plurals.contact_delete_dialog
|
override val dialogConfirmationMessageBeforeRemoval = R.plurals.contact_delete_dialog
|
||||||
private lateinit var listViewModel: ContactsListViewModel
|
private lateinit var listViewModel: ContactsListViewModel
|
||||||
private lateinit var adapter: ContactsListAdapter
|
|
||||||
private lateinit var sharedViewModel: SharedMainViewModel
|
private lateinit var sharedViewModel: SharedMainViewModel
|
||||||
|
|
||||||
private var sipUriToAdd: String? = null
|
private var sipUriToAdd: String? = null
|
||||||
|
@ -55,6 +54,11 @@ class MasterContactsFragment : MasterFragment<ContactMasterFragmentBinding>() {
|
||||||
|
|
||||||
override fun getLayoutId(): Int = R.layout.contact_master_fragment
|
override fun getLayoutId(): Int = R.layout.contact_master_fragment
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
binding.contactsList.adapter = null
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
@ -67,7 +71,7 @@ class MasterContactsFragment : MasterFragment<ContactMasterFragmentBinding>() {
|
||||||
ViewModelProvider(this).get(SharedMainViewModel::class.java)
|
ViewModelProvider(this).get(SharedMainViewModel::class.java)
|
||||||
} ?: throw Exception("Invalid Activity")
|
} ?: throw Exception("Invalid Activity")
|
||||||
|
|
||||||
adapter = ContactsListAdapter(listSelectionViewModel)
|
_adapter = ContactsListAdapter(listSelectionViewModel, viewLifecycleOwner)
|
||||||
binding.contactsList.adapter = adapter
|
binding.contactsList.adapter = adapter
|
||||||
|
|
||||||
binding.setEditClickListener {
|
binding.setEditClickListener {
|
||||||
|
@ -100,7 +104,7 @@ class MasterContactsFragment : MasterFragment<ContactMasterFragmentBinding>() {
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.showDeleteButton({
|
viewModel.showDeleteButton({
|
||||||
listViewModel.deleteContact(adapter.getItemAt(viewHolder.adapterPosition))
|
listViewModel.deleteContact(adapter.currentList[viewHolder.adapterPosition])
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}, getString(R.string.dialog_delete))
|
}, getString(R.string.dialog_delete))
|
||||||
|
|
||||||
|
@ -211,7 +215,7 @@ class MasterContactsFragment : MasterFragment<ContactMasterFragmentBinding>() {
|
||||||
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
|
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
|
||||||
val list = ArrayList<Contact>()
|
val list = ArrayList<Contact>()
|
||||||
for (index in indexesOfItemToDelete) {
|
for (index in indexesOfItemToDelete) {
|
||||||
val contact = adapter.getItemAt(index)
|
val contact = adapter.currentList[index]
|
||||||
list.add(contact)
|
list.add(contact)
|
||||||
}
|
}
|
||||||
listViewModel.deleteContacts(list)
|
listViewModel.deleteContacts(list)
|
||||||
|
|
|
@ -29,12 +29,16 @@ import org.linphone.activities.main.viewmodels.DialogViewModel
|
||||||
import org.linphone.activities.main.viewmodels.ListTopBarViewModel
|
import org.linphone.activities.main.viewmodels.ListTopBarViewModel
|
||||||
import org.linphone.utils.AppUtils
|
import org.linphone.utils.AppUtils
|
||||||
import org.linphone.utils.DialogUtils
|
import org.linphone.utils.DialogUtils
|
||||||
|
import org.linphone.utils.SelectionListAdapter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This fragment can be inherited by all fragments that will display a list
|
* This fragment can be inherited by all fragments that will display a list
|
||||||
* where items can be selected for removal through the ListTopBarFragment
|
* where items can be selected for removal through the ListTopBarFragment
|
||||||
*/
|
*/
|
||||||
abstract class MasterFragment<T : ViewDataBinding> : GenericFragment<T>() {
|
abstract class MasterFragment<T : ViewDataBinding, U : SelectionListAdapter<*, *>> : GenericFragment<T>() {
|
||||||
|
protected var _adapter: U? = null
|
||||||
|
protected val adapter get() = _adapter!!
|
||||||
|
|
||||||
protected lateinit var listSelectionViewModel: ListTopBarViewModel
|
protected lateinit var listSelectionViewModel: ListTopBarViewModel
|
||||||
protected open val dialogConfirmationMessageBeforeRemoval: Int = R.plurals.dialog_default_delete
|
protected open val dialogConfirmationMessageBeforeRemoval: Int = R.plurals.dialog_default_delete
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,10 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
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.history.viewmodels.GroupedCallLogViewModel
|
||||||
|
@ -35,7 +37,10 @@ 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<GroupedCallLogViewModel, CallLogsListAdapter.ViewHolder>(CallLogDiffCallback()), HeaderAdapter {
|
class CallLogsListAdapter(
|
||||||
|
selectionVM: ListTopBarViewModel,
|
||||||
|
private val viewLifecycleOwner: LifecycleOwner
|
||||||
|
) : SelectionListAdapter<GroupedCallLogViewModel, RecyclerView.ViewHolder>(selectionVM, CallLogDiffCallback()), HeaderAdapter {
|
||||||
val selectedCallLogEvent: MutableLiveData<Event<GroupedCallLogViewModel>> by lazy {
|
val selectedCallLogEvent: MutableLiveData<Event<GroupedCallLogViewModel>> by lazy {
|
||||||
MutableLiveData<Event<GroupedCallLogViewModel>>()
|
MutableLiveData<Event<GroupedCallLogViewModel>>()
|
||||||
}
|
}
|
||||||
|
@ -44,31 +49,31 @@ class CallLogsListAdapter(val selectionViewModel: ListTopBarViewModel) : Lifecyc
|
||||||
MutableLiveData<Event<Address>>()
|
MutableLiveData<Event<Address>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val binding: HistoryListCellBinding = DataBindingUtil.inflate(
|
val binding: HistoryListCellBinding = DataBindingUtil.inflate(
|
||||||
LayoutInflater.from(parent.context),
|
LayoutInflater.from(parent.context),
|
||||||
R.layout.history_list_cell, parent, false
|
R.layout.history_list_cell, parent, false
|
||||||
)
|
)
|
||||||
val viewHolder = ViewHolder(binding)
|
return ViewHolder(binding)
|
||||||
binding.lifecycleOwner = viewHolder
|
|
||||||
return viewHolder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
holder.bind(getItem(position))
|
(holder as ViewHolder).bind(getItem(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(
|
inner class ViewHolder(
|
||||||
private val binding: HistoryListCellBinding
|
private val binding: HistoryListCellBinding
|
||||||
) : LifecycleViewHolder(binding) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
fun bind(callLogGroup: GroupedCallLogViewModel) {
|
fun bind(callLogGroup: GroupedCallLogViewModel) {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
val callLogViewModel = CallLogViewModel(callLogGroup.lastCallLog)
|
val callLogViewModel = CallLogViewModel(callLogGroup.lastCallLog)
|
||||||
viewModel = callLogViewModel
|
viewModel = callLogViewModel
|
||||||
|
|
||||||
|
binding.lifecycleOwner = viewLifecycleOwner
|
||||||
|
|
||||||
// This is for item selection through ListTopBarFragment
|
// This is for item selection through ListTopBarFragment
|
||||||
selectionListViewModel = selectionViewModel
|
selectionListViewModel = selectionViewModel
|
||||||
selectionViewModel.isEditionEnabled.observe(this@ViewHolder, {
|
selectionViewModel.isEditionEnabled.observe(viewLifecycleOwner, {
|
||||||
position = adapterPosition
|
position = adapterPosition
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -42,14 +42,25 @@ import org.linphone.core.tools.Log
|
||||||
import org.linphone.databinding.HistoryMasterFragmentBinding
|
import org.linphone.databinding.HistoryMasterFragmentBinding
|
||||||
import org.linphone.utils.*
|
import org.linphone.utils.*
|
||||||
|
|
||||||
class MasterCallLogsFragment : MasterFragment<HistoryMasterFragmentBinding>() {
|
class MasterCallLogsFragment : MasterFragment<HistoryMasterFragmentBinding, CallLogsListAdapter>() {
|
||||||
override val dialogConfirmationMessageBeforeRemoval = R.plurals.history_delete_dialog
|
override val dialogConfirmationMessageBeforeRemoval = R.plurals.history_delete_dialog
|
||||||
private lateinit var listViewModel: CallLogsListViewModel
|
private lateinit var listViewModel: CallLogsListViewModel
|
||||||
private lateinit var adapter: CallLogsListAdapter
|
|
||||||
private lateinit var sharedViewModel: SharedMainViewModel
|
private lateinit var sharedViewModel: SharedMainViewModel
|
||||||
|
|
||||||
|
private val observer = object : RecyclerView.AdapterDataObserver() {
|
||||||
|
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
||||||
|
scrollToTop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun getLayoutId(): Int = R.layout.history_master_fragment
|
override fun getLayoutId(): Int = R.layout.history_master_fragment
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
binding.callLogsList.adapter = null
|
||||||
|
adapter.unregisterAdapterDataObserver(observer)
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
@ -62,14 +73,10 @@ class MasterCallLogsFragment : MasterFragment<HistoryMasterFragmentBinding>() {
|
||||||
ViewModelProvider(this).get(SharedMainViewModel::class.java)
|
ViewModelProvider(this).get(SharedMainViewModel::class.java)
|
||||||
} ?: throw Exception("Invalid Activity")
|
} ?: throw Exception("Invalid Activity")
|
||||||
|
|
||||||
adapter = CallLogsListAdapter(listSelectionViewModel)
|
_adapter = CallLogsListAdapter(listSelectionViewModel, viewLifecycleOwner)
|
||||||
// SubmitList is done on a background thread
|
// SubmitList is done on a background thread
|
||||||
// We need this adapter data observer to know when to scroll
|
// We need this adapter data observer to know when to scroll
|
||||||
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
adapter.registerAdapterDataObserver(observer)
|
||||||
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
|
||||||
scrollToTop()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
binding.callLogsList.adapter = adapter
|
binding.callLogsList.adapter = adapter
|
||||||
|
|
||||||
binding.setEditClickListener {
|
binding.setEditClickListener {
|
||||||
|
@ -97,7 +104,7 @@ class MasterCallLogsFragment : MasterFragment<HistoryMasterFragmentBinding>() {
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.showDeleteButton({
|
viewModel.showDeleteButton({
|
||||||
listViewModel.deleteCallLogGroup(adapter.getItemAt(viewHolder.adapterPosition))
|
listViewModel.deleteCallLogGroup(adapter.currentList[viewHolder.adapterPosition])
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}, getString(R.string.dialog_delete))
|
}, getString(R.string.dialog_delete))
|
||||||
|
|
||||||
|
@ -194,7 +201,7 @@ class MasterCallLogsFragment : MasterFragment<HistoryMasterFragmentBinding>() {
|
||||||
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
|
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
|
||||||
val list = ArrayList<GroupedCallLogViewModel>()
|
val list = ArrayList<GroupedCallLogViewModel>()
|
||||||
for (index in indexesOfItemToDelete) {
|
for (index in indexesOfItemToDelete) {
|
||||||
val callLogGroup = adapter.getItemAt(index)
|
val callLogGroup = adapter.currentList[index]
|
||||||
list.add(callLogGroup)
|
list.add(callLogGroup)
|
||||||
}
|
}
|
||||||
listViewModel.deleteCallLogGroups(list)
|
listViewModel.deleteCallLogGroups(list)
|
||||||
|
|
|
@ -25,8 +25,10 @@ import android.view.TextureView
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.activities.main.recordings.viewmodels.RecordingViewModel
|
import org.linphone.activities.main.recordings.viewmodels.RecordingViewModel
|
||||||
import org.linphone.activities.main.viewmodels.ListTopBarViewModel
|
import org.linphone.activities.main.viewmodels.ListTopBarViewModel
|
||||||
|
@ -34,10 +36,10 @@ import org.linphone.databinding.GenericListHeaderBinding
|
||||||
import org.linphone.databinding.RecordingListCellBinding
|
import org.linphone.databinding.RecordingListCellBinding
|
||||||
import org.linphone.utils.*
|
import org.linphone.utils.*
|
||||||
|
|
||||||
class RecordingsListAdapter(val selectionViewModel: ListTopBarViewModel) : LifecycleListAdapter<RecordingViewModel, RecordingsListAdapter.ViewHolder>(
|
class RecordingsListAdapter(
|
||||||
RecordingDiffCallback()
|
selectionVM: ListTopBarViewModel,
|
||||||
), HeaderAdapter {
|
private val viewLifecycleOwner: LifecycleOwner
|
||||||
|
) : SelectionListAdapter<RecordingViewModel, RecyclerView.ViewHolder>(selectionVM, RecordingDiffCallback()), HeaderAdapter {
|
||||||
val isVideoRecordingPlayingEvent: MutableLiveData<Event<Boolean>> by lazy {
|
val isVideoRecordingPlayingEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||||
MutableLiveData<Event<Boolean>>()
|
MutableLiveData<Event<Boolean>>()
|
||||||
}
|
}
|
||||||
|
@ -48,32 +50,30 @@ class RecordingsListAdapter(val selectionViewModel: ListTopBarViewModel) : Lifec
|
||||||
videoSurface = textureView
|
videoSurface = textureView
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val binding: RecordingListCellBinding = DataBindingUtil.inflate(
|
val binding: RecordingListCellBinding = DataBindingUtil.inflate(
|
||||||
LayoutInflater.from(parent.context),
|
LayoutInflater.from(parent.context),
|
||||||
R.layout.recording_list_cell, parent, false
|
R.layout.recording_list_cell, parent, false
|
||||||
)
|
)
|
||||||
val viewHolder = ViewHolder(binding)
|
return ViewHolder(binding)
|
||||||
binding.lifecycleOwner = viewHolder
|
|
||||||
return viewHolder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
holder.bind(getItem(position))
|
(holder as ViewHolder).bind(getItem(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(
|
inner class ViewHolder(
|
||||||
private val binding: RecordingListCellBinding
|
private val binding: RecordingListCellBinding
|
||||||
) : LifecycleViewHolder(binding) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
fun bind(recording: RecordingViewModel) {
|
fun bind(recording: RecordingViewModel) {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
viewModel = recording
|
viewModel = recording
|
||||||
|
|
||||||
|
binding.lifecycleOwner = viewLifecycleOwner
|
||||||
|
|
||||||
// This is for item selection through ListTopBarFragment
|
// This is for item selection through ListTopBarFragment
|
||||||
selectionListViewModel = selectionViewModel
|
|
||||||
selectionViewModel.isEditionEnabled.observe(this@ViewHolder, {
|
|
||||||
position = adapterPosition
|
position = adapterPosition
|
||||||
})
|
selectionListViewModel = selectionViewModel
|
||||||
|
|
||||||
setClickListener {
|
setClickListener {
|
||||||
if (selectionViewModel.isEditionEnabled.value == true) {
|
if (selectionViewModel.isEditionEnabled.value == true) {
|
||||||
|
@ -81,14 +81,18 @@ class RecordingsListAdapter(val selectionViewModel: ListTopBarViewModel) : Lifec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
recording.isVideoRecordingPlayingEvent.observe(this@ViewHolder, {
|
setPlayListener {
|
||||||
it.consume { value ->
|
if (recording.isPlaying.value == true) {
|
||||||
if (value) {
|
recording.pause()
|
||||||
|
isVideoRecordingPlayingEvent.value = Event(false)
|
||||||
|
} else {
|
||||||
|
recording.play()
|
||||||
|
if (recording.isVideoAvailable()) {
|
||||||
recording.setTextureView(videoSurface)
|
recording.setTextureView(videoSurface)
|
||||||
|
isVideoRecordingPlayingEvent.value = Event(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
isVideoRecordingPlayingEvent.value = Event(value)
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
executePendingBindings()
|
executePendingBindings()
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,15 +33,19 @@ import org.linphone.activities.main.recordings.viewmodels.RecordingsViewModel
|
||||||
import org.linphone.databinding.RecordingsFragmentBinding
|
import org.linphone.databinding.RecordingsFragmentBinding
|
||||||
import org.linphone.utils.RecyclerViewHeaderDecoration
|
import org.linphone.utils.RecyclerViewHeaderDecoration
|
||||||
|
|
||||||
class RecordingsFragment : MasterFragment<RecordingsFragmentBinding>() {
|
class RecordingsFragment : MasterFragment<RecordingsFragmentBinding, RecordingsListAdapter>() {
|
||||||
private lateinit var viewModel: RecordingsViewModel
|
private lateinit var viewModel: RecordingsViewModel
|
||||||
private lateinit var adapter: RecordingsListAdapter
|
|
||||||
|
|
||||||
private var videoX: Float = 0f
|
private var videoX: Float = 0f
|
||||||
private var videoY: Float = 0f
|
private var videoY: Float = 0f
|
||||||
|
|
||||||
override fun getLayoutId(): Int = R.layout.recordings_fragment
|
override fun getLayoutId(): Int = R.layout.recordings_fragment
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
binding.recordingsList.adapter = null
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
@ -50,10 +54,7 @@ class RecordingsFragment : MasterFragment<RecordingsFragmentBinding>() {
|
||||||
viewModel = ViewModelProvider(this).get(RecordingsViewModel::class.java)
|
viewModel = ViewModelProvider(this).get(RecordingsViewModel::class.java)
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
adapter =
|
_adapter = RecordingsListAdapter(listSelectionViewModel, viewLifecycleOwner)
|
||||||
RecordingsListAdapter(
|
|
||||||
listSelectionViewModel
|
|
||||||
)
|
|
||||||
binding.recordingsList.adapter = adapter
|
binding.recordingsList.adapter = adapter
|
||||||
|
|
||||||
val layoutManager = LinearLayoutManager(activity)
|
val layoutManager = LinearLayoutManager(activity)
|
||||||
|
@ -109,7 +110,7 @@ class RecordingsFragment : MasterFragment<RecordingsFragmentBinding>() {
|
||||||
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
|
override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
|
||||||
val list = ArrayList<RecordingViewModel>()
|
val list = ArrayList<RecordingViewModel>()
|
||||||
for (index in indexesOfItemToDelete) {
|
for (index in indexesOfItemToDelete) {
|
||||||
val recording = adapter.getItemAt(index)
|
val recording = adapter.currentList[index]
|
||||||
list.add(recording)
|
list.add(recording)
|
||||||
}
|
}
|
||||||
viewModel.deleteRecordings(list)
|
viewModel.deleteRecordings(list)
|
||||||
|
|
|
@ -37,7 +37,6 @@ import org.linphone.core.AudioDevice
|
||||||
import org.linphone.core.Player
|
import org.linphone.core.Player
|
||||||
import org.linphone.core.PlayerListener
|
import org.linphone.core.PlayerListener
|
||||||
import org.linphone.core.tools.Log
|
import org.linphone.core.tools.Log
|
||||||
import org.linphone.utils.Event
|
|
||||||
import org.linphone.utils.LinphoneUtils
|
import org.linphone.utils.LinphoneUtils
|
||||||
|
|
||||||
class RecordingViewModel(val path: String) : ViewModel(), Comparable<RecordingViewModel> {
|
class RecordingViewModel(val path: String) : ViewModel(), Comparable<RecordingViewModel> {
|
||||||
|
@ -56,10 +55,6 @@ class RecordingViewModel(val path: String) : ViewModel(), Comparable<RecordingVi
|
||||||
val formattedPosition = MutableLiveData<String>()
|
val formattedPosition = MutableLiveData<String>()
|
||||||
val isPlaying = MutableLiveData<Boolean>()
|
val isPlaying = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
val isVideoRecordingPlayingEvent: MutableLiveData<Event<Boolean>> by lazy {
|
|
||||||
MutableLiveData<Event<Boolean>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val tickerChannel = ticker(1000, 1000)
|
private val tickerChannel = ticker(1000, 1000)
|
||||||
|
|
||||||
private lateinit var player: Player
|
private lateinit var player: Player
|
||||||
|
@ -68,6 +63,30 @@ class RecordingViewModel(val path: String) : ViewModel(), Comparable<RecordingVi
|
||||||
stop()
|
stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val textureViewListener = object : TextureView.SurfaceTextureListener {
|
||||||
|
override fun onSurfaceTextureSizeChanged(
|
||||||
|
surface: SurfaceTexture,
|
||||||
|
width: Int,
|
||||||
|
height: Int
|
||||||
|
) { }
|
||||||
|
|
||||||
|
override fun onSurfaceTextureUpdated(surface: SurfaceTexture) { }
|
||||||
|
|
||||||
|
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
|
||||||
|
player.setWindowId(null)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSurfaceTextureAvailable(
|
||||||
|
surface: SurfaceTexture,
|
||||||
|
width: Int,
|
||||||
|
height: Int
|
||||||
|
) {
|
||||||
|
Log.i("[Recording VM] Surface texture should be available now")
|
||||||
|
player.setWindowId(surface)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val m = RECORD_PATTERN.matcher(path)
|
val m = RECORD_PATTERN.matcher(path)
|
||||||
if (m.matches() && m.groupCount() >= 2) {
|
if (m.matches() && m.groupCount() >= 2) {
|
||||||
|
@ -84,6 +103,7 @@ class RecordingViewModel(val path: String) : ViewModel(), Comparable<RecordingVi
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
tickerChannel.cancel()
|
tickerChannel.cancel()
|
||||||
|
player.setWindowId(null)
|
||||||
if (!isClosed()) player.close()
|
if (!isClosed()) player.close()
|
||||||
player.removeListener(listener)
|
player.removeListener(listener)
|
||||||
|
|
||||||
|
@ -111,8 +131,10 @@ class RecordingViewModel(val path: String) : ViewModel(), Comparable<RecordingVi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
isVideoRecordingPlayingEvent.value = Event(player.isVideoAvailable)
|
fun isVideoAvailable(): Boolean {
|
||||||
|
return player.isVideoAvailable
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pause() {
|
fun pause() {
|
||||||
|
@ -135,28 +157,7 @@ class RecordingViewModel(val path: String) : ViewModel(), Comparable<RecordingVi
|
||||||
if (textureView.isAvailable) {
|
if (textureView.isAvailable) {
|
||||||
player.setWindowId(textureView.surfaceTexture)
|
player.setWindowId(textureView.surfaceTexture)
|
||||||
} else {
|
} else {
|
||||||
textureView.surfaceTextureListener = object : TextureView.SurfaceTextureListener {
|
textureView.surfaceTextureListener = textureViewListener
|
||||||
override fun onSurfaceTextureSizeChanged(
|
|
||||||
surface: SurfaceTexture,
|
|
||||||
width: Int,
|
|
||||||
height: Int
|
|
||||||
) { }
|
|
||||||
|
|
||||||
override fun onSurfaceTextureUpdated(surface: SurfaceTexture) { }
|
|
||||||
|
|
||||||
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSurfaceTextureAvailable(
|
|
||||||
surface: SurfaceTexture,
|
|
||||||
width: Int,
|
|
||||||
height: Int
|
|
||||||
) {
|
|
||||||
Log.i("[Recording VM] Surface texture should be available now")
|
|
||||||
player.setWindowId(textureView.surfaceTexture)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +198,6 @@ class RecordingViewModel(val path: String) : ViewModel(), Comparable<RecordingVi
|
||||||
player.seek(0)
|
player.seek(0)
|
||||||
updatePosition()
|
updatePosition()
|
||||||
player.close()
|
player.close()
|
||||||
isVideoRecordingPlayingEvent.value = Event(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isClosed(): Boolean {
|
private fun isClosed(): Boolean {
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.utils
|
|
||||||
|
|
||||||
import androidx.databinding.ViewDataBinding
|
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.LifecycleOwner
|
|
||||||
import androidx.lifecycle.LifecycleRegistry
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class allows us to use ViewHolder as lifecycle owner so items in lists can refresh when
|
|
||||||
* a live data value changes without having to notify the adapter that the item as changed.
|
|
||||||
*/
|
|
||||||
abstract class LifecycleViewHolder(viewBinding: ViewDataBinding) : RecyclerView.ViewHolder(viewBinding.root), LifecycleOwner {
|
|
||||||
private val lifecycleRegistry = LifecycleRegistry(this) // TODO FIXME leak ?
|
|
||||||
|
|
||||||
init {
|
|
||||||
lifecycleRegistry.currentState = Lifecycle.State.INITIALIZED
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getLifecycle(): Lifecycle {
|
|
||||||
return lifecycleRegistry
|
|
||||||
}
|
|
||||||
|
|
||||||
fun attach() {
|
|
||||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun detach() {
|
|
||||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,23 +21,20 @@ package org.linphone.utils
|
||||||
|
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.linphone.activities.main.viewmodels.ListTopBarViewModel
|
||||||
|
|
||||||
/**
|
abstract class SelectionListAdapter<T, VH : RecyclerView.ViewHolder>(
|
||||||
* This class prevents having to do in each adapter the viewHolder.attach/detach calls
|
selectionVM: ListTopBarViewModel,
|
||||||
* to create lifecycle events that are required for the data binding to work correctly
|
diff: DiffUtil.ItemCallback<T>
|
||||||
*/
|
) :
|
||||||
abstract class LifecycleListAdapter<T, VH : LifecycleViewHolder>(diff: DiffUtil.ItemCallback<T>) : ListAdapter<T, VH>(diff) {
|
ListAdapter<T, VH>(diff) {
|
||||||
override fun onViewAttachedToWindow(holder: VH) {
|
|
||||||
super.onViewAttachedToWindow(holder)
|
|
||||||
holder.attach()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewDetachedFromWindow(holder: VH) {
|
private var _selectionViewModel: ListTopBarViewModel? = selectionVM
|
||||||
super.onViewDetachedFromWindow(holder)
|
protected val selectionViewModel get() = _selectionViewModel!!
|
||||||
holder.detach()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getItemAt(position: Int): T {
|
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
|
||||||
return getItem(position)
|
super.onDetachedFromRecyclerView(recyclerView)
|
||||||
|
_selectionViewModel = null
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,6 +6,9 @@
|
||||||
<variable
|
<variable
|
||||||
name="clickListener"
|
name="clickListener"
|
||||||
type="android.view.View.OnClickListener"/>
|
type="android.view.View.OnClickListener"/>
|
||||||
|
<variable
|
||||||
|
name="playListener"
|
||||||
|
type="android.view.View.OnClickListener"/>
|
||||||
<variable
|
<variable
|
||||||
name="position"
|
name="position"
|
||||||
type="Integer"/>
|
type="Integer"/>
|
||||||
|
@ -28,7 +31,7 @@
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/record_play_pause"
|
android:id="@+id/record_play_pause"
|
||||||
android:onClick="@{() -> viewModel.isPlaying ? viewModel.pause() : viewModel.play()}"
|
android:onClick="@{playListener}"
|
||||||
android:selected="@{viewModel.isPlaying}"
|
android:selected="@{viewModel.isPlaying}"
|
||||||
android:contentDescription="@string/content_description_recording_toggle_play"
|
android:contentDescription="@string/content_description_recording_toggle_play"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
Loading…
Reference in a new issue