From 6427e0bafddbfa0d730924073029e54907e17af7 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Thu, 23 Jan 2020 13:51:41 +0100 Subject: [PATCH] Lots of progress on selecting contacts Signed-off-by: Mario Danic --- .../talk/adapters/items/AdvancedUserItem.kt | 2 +- .../nextcloud/talk/adapters/items/UserItem.kt | 2 +- .../features/contactsflow/ContactPresenter.kt | 23 +++++-- .../features/contactsflow/ContactsUtils.kt | 1 + .../features/contactsflow/ContactsView.kt | 44 +++++++++++-- .../contactsflow/ContactsViewModel.kt | 16 ++++- .../contactsflow/ContactsViewSource.kt | 4 ++ .../ConversationPresenter.kt | 2 +- .../nextcloud/talk/newarch/utils/Images.kt | 6 +- .../main/res/layout/contacts_list_view.xml | 19 +++++- app/src/main/res/layout/rv_item_contact.xml | 8 +-- .../res/layout/rv_item_contact_selected.xml | 66 +++++++++++++++++++ .../main/res/layout/rv_item_conversation.xml | 2 +- .../rv_item_conversation_info_participant.xml | 2 +- app/src/main/res/layout/rv_item_mention.xml | 2 +- 15 files changed, 174 insertions(+), 25 deletions(-) create mode 100644 app/src/main/res/layout/rv_item_contact_selected.xml diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.kt index 3a55d2457..2445dd592 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.kt @@ -137,7 +137,7 @@ class AdvancedUserItem( ) : FlexibleViewHolder(view, adapter) { @JvmField - @BindView(R.id.name_text) + @BindView(R.id.participantNameTextView) var contactDisplayName: EmojiTextView? = null @JvmField @BindView(R.id.secondary_text) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.kt index 4f6b0f620..ecfd3dc34 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.kt @@ -268,7 +268,7 @@ class UserItem( var checkedImageView: ImageView? = null init { - contactDisplayName = view.findViewById(R.id.name_text) + contactDisplayName = view.findViewById(R.id.participantNameTextView) avatarImageView = view.findViewById(R.id.avatarImageView) contactMentionId = view.findViewById(R.id.secondary_text) voiceOrSimpleCallImageView = view.findViewById(R.id.voiceOrSimpleCallImageView) diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactPresenter.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactPresenter.kt index af6f511b9..2d34f8052 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactPresenter.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactPresenter.kt @@ -17,6 +17,9 @@ import com.otaliastudios.elements.Presenter import com.otaliastudios.elements.extensions.FooterSource import com.otaliastudios.elements.extensions.HeaderSource import kotlinx.android.synthetic.main.rv_item_contact.view.* +import kotlinx.android.synthetic.main.rv_item_contact.view.avatarImageView +import kotlinx.android.synthetic.main.rv_item_contact.view.participantNameTextView +import kotlinx.android.synthetic.main.rv_item_contact_selected.view.* import kotlinx.android.synthetic.main.rv_item_participant_rv_footer.view.* import kotlinx.android.synthetic.main.rv_item_title_header.view.* import org.koin.core.KoinComponent @@ -26,13 +29,16 @@ open class ContactPresenter(context: Context, onElementClick: ((Page, H private val globalService: GlobalService by inject() override val elementTypes: Collection - get() = listOf(ParticipantElementType.PARTICIPANT.ordinal, ParticipantElementType.PARTICIPANT_HEADER.ordinal, ParticipantElementType.PARTICIPANT_FOOTER.ordinal) + get() = listOf(ParticipantElementType.PARTICIPANT.ordinal, ParticipantElementType.PARTICIPANT_SELECTED.ordinal, ParticipantElementType.PARTICIPANT_HEADER.ordinal, ParticipantElementType.PARTICIPANT_FOOTER.ordinal) override fun onCreate(parent: ViewGroup, elementType: Int): Holder { return when (elementType) { ParticipantElementType.PARTICIPANT.ordinal -> { Holder(getLayoutInflater().inflate(R.layout.rv_item_contact, parent, false)) } + ParticipantElementType.PARTICIPANT_SELECTED.ordinal -> { + Holder(getLayoutInflater().inflate(R.layout.rv_item_contact_selected, parent, false)) + } ParticipantElementType.PARTICIPANT_HEADER.ordinal -> { Holder(getLayoutInflater().inflate(R.layout.rv_item_title_header, parent, false)) } @@ -45,19 +51,26 @@ open class ContactPresenter(context: Context, onElementClick: ((Page, H override fun onBind(page: Page, holder: Holder, element: Element, payloads: List) { super.onBind(page, holder, element, payloads) - if (element.type == ParticipantElementType.PARTICIPANT.ordinal) { + if (element.type == ParticipantElementType.PARTICIPANT.ordinal || element.type == ParticipantElementType.PARTICIPANT_SELECTED.ordinal) { val participant = element.data as Participant? val user = globalService.currentUserLiveData.value - holder.itemView.checkedImageView.isVisible = participant?.selected == true + holder.itemView.checkedImageView?.isVisible = participant?.selected == true if (!payloads.contains(ElementPayload.SELECTION_TOGGLE)) { participant?.displayName?.let { - holder.itemView.name_text.text = it + if (element.type == ParticipantElementType.PARTICIPANT_SELECTED.ordinal) { + holder.itemView.participantNameTextView.text = it.substringBefore(" ", it) + } else { + holder.itemView.participantNameTextView.text = it + + } } ?: run { - holder.itemView.name_text.text = context.getString(R.string.nc_guest) + holder.itemView.participantNameTextView.text = context.getString(R.string.nc_guest) } + holder.itemView.clearImageView?.load(Images().getImageWithBackground(context, R.drawable.ic_baseline_clear_24, R.color.white)) + when (participant?.source) { "users" -> { when (participant.type) { diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsUtils.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsUtils.kt index 8be89f29b..ae5f1e710 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsUtils.kt @@ -2,6 +2,7 @@ package com.nextcloud.talk.newarch.features.contactsflow enum class ParticipantElementType { PARTICIPANT, + PARTICIPANT_SELECTED, PARTICIPANT_HEADER, PARTICIPANT_FOOTER } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsView.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsView.kt index 2b25716db..d308ad027 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsView.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsView.kt @@ -5,7 +5,11 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.isVisible +import androidx.lifecycle.LiveData +import androidx.lifecycle.observe import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider import com.nextcloud.talk.R import com.nextcloud.talk.models.json.participants.Participant @@ -18,7 +22,8 @@ import com.otaliastudios.elements.Element import com.otaliastudios.elements.Page import com.otaliastudios.elements.Presenter import com.uber.autodispose.lifecycle.LifecycleScopeProvider -import kotlinx.android.synthetic.main.conversations_list_view.view.* +import kotlinx.android.synthetic.main.contacts_list_view.view.* +import kotlinx.android.synthetic.main.conversations_list_view.view.recyclerView import kotlinx.android.synthetic.main.message_state.view.* import org.koin.android.ext.android.inject @@ -27,7 +32,8 @@ class ContactsView(private val bundle: Bundle? = null) : BaseView() { private lateinit var viewModel: ContactsViewModel val factory: ContactsViewModelFactory by inject() - lateinit var adapter: Adapter + lateinit var participantsAdapter: Adapter + lateinit var selectedParticipantsAdapter: Adapter override fun getLayoutId(): Int { return R.layout.contacts_list_view } @@ -44,8 +50,8 @@ class ContactsView(private val bundle: Bundle? = null) : BaseView() { val view = super.onCreateView(inflater, container) // todo - change empty state magic - adapter = Adapter.builder(this) - .addSource(ContactsViewSource(viewModel.contactsLiveData, ParticipantElementType.PARTICIPANT.ordinal)) + participantsAdapter = Adapter.builder(this) + .addSource(ContactsViewSource(data = viewModel.contactsLiveData, elementType = ParticipantElementType.PARTICIPANT.ordinal)) .addSource(ContactsHeaderSource(activity as Context, ParticipantElementType.PARTICIPANT_HEADER.ordinal)) .addSource(ContactsFooterSource(activity as Context, ParticipantElementType.PARTICIPANT_FOOTER.ordinal)) .addPresenter(ContactPresenter(activity as Context, ::onElementClick)) @@ -58,8 +64,24 @@ class ContactsView(private val bundle: Bundle? = null) : BaseView() { .setAutoScrollMode(Adapter.AUTOSCROLL_POSITION_0, true) .into(view.recyclerView) + selectedParticipantsAdapter = Adapter.builder(this) + .addSource(ContactsViewSource(data = viewModel.selectedParticipantsLiveData, elementType = ParticipantElementType.PARTICIPANT_SELECTED.ordinal, loadingIndicatorsEnabled = false, errorIndicatorEnabled = false, emptyIndicatorEnabled = false)) + .addPresenter(ContactPresenter(activity as Context, ::onElementClick)) + .setAutoScrollMode(Adapter.AUTOSCROLL_POSITION_ANY, true) + .into(view.selectedParticipantsRecyclerView) + view.apply { - recyclerView.initRecyclerView(LinearLayoutManager(activity), adapter, true) + recyclerView.initRecyclerView(LinearLayoutManager(activity), participantsAdapter, true) + selectedParticipantsRecyclerView.initRecyclerView(LinearLayoutManager(activity, RecyclerView.HORIZONTAL, false), selectedParticipantsAdapter, true) + } + + viewModel.apply { + selectedParticipantsLiveData.observe(this@ContactsView) { participants -> + view.selectedParticipantsRecyclerView.isVisible = participants.isNotEmpty() + view.divider.isVisible = participants.isNotEmpty() + + } + } viewModel.loadContacts() @@ -71,8 +93,16 @@ class ContactsView(private val bundle: Bundle? = null) : BaseView() { if (element.data is Participant?) { val participant = element.data as Participant? val isElementSelected = participant?.selected == true - participant?.selected = !isElementSelected - adapter.notifyItemChanged(holder.adapterPosition, ElementPayload.SELECTION_TOGGLE) + participant?.let { + if (isElementSelected) { + viewModel.unselectParticipant(it) + } else { + viewModel.selectParticipant(it) + } + it.selected = !isElementSelected + participantsAdapter.notifyItemChanged(holder.adapterPosition, ElementPayload.SELECTION_TOGGLE) + + } } } diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsViewModel.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsViewModel.kt index 0b0e1e336..c7549a1c9 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsViewModel.kt @@ -1,6 +1,7 @@ package com.nextcloud.talk.newarch.features.contactsflow import android.app.Application +import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.nextcloud.talk.models.json.participants.Participant @@ -17,7 +18,10 @@ class ContactsViewModel constructor( private val getContactsUseCase: GetContactsUseCase, val globalService: GlobalService ) : BaseViewModel(application) { - val contactsLiveData = MutableLiveData>() + private val selectedParticipants = mutableListOf() + val selectedParticipantsLiveData: MutableLiveData> = MutableLiveData() + val contactsLiveData: MutableLiveData> = MutableLiveData() + private var searchQuery: String? = null var conversationToken: String? = null @@ -26,6 +30,16 @@ class ContactsViewModel constructor( loadContacts() } + fun selectParticipant(participant: Participant) { + selectedParticipants.add(participant) + selectedParticipantsLiveData.postValue(selectedParticipants) + } + + fun unselectParticipant(participant: Participant) { + selectedParticipants.remove(participant) + selectedParticipantsLiveData.postValue(selectedParticipants) + } + fun loadContacts() { getContactsUseCase.invoke(viewModelScope, parametersOf(globalService.currentUserLiveData.value, searchQuery, conversationToken), object : UseCaseResponse> { diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsViewSource.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsViewSource.kt index 07b6ba90b..c105b30e4 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsViewSource.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/contactsflow/ContactsViewSource.kt @@ -38,6 +38,10 @@ class ContactsViewSource(private val data: LiveData>, p } } + override fun getElementType(data: T): Int { + return elementType + } + override fun dependsOn(source: Source<*>): Boolean { return false } diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationPresenter.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationPresenter.kt index b7b0b09b5..923440c3e 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationPresenter.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationPresenter.kt @@ -121,7 +121,7 @@ open class ConversationPresenter(context: Context, onElementClick: ((Page, Holde ) } else { authorDisplayName = if (!TextUtils.isEmpty(conversation.lastMessage?.actorDisplayName)) { - conversation.lastMessage?.actorDisplayName!!.substringBefore(" ") + conversation.lastMessage?.actorDisplayName!!.substringBefore(" ", conversation.lastMessage?.actorDisplayName!!) } else if ("guests" == conversation.lastMessage!!.actorType) context.getString(R.string.nc_guest) else diff --git a/app/src/main/java/com/nextcloud/talk/newarch/utils/Images.kt b/app/src/main/java/com/nextcloud/talk/newarch/utils/Images.kt index 3bb4809bd..210d8d3cb 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/utils/Images.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/utils/Images.kt @@ -68,7 +68,7 @@ class Images { } } - fun getImageWithBackground(context: Context, drawableId: Int): Bitmap { + fun getImageWithBackground(context: Context, drawableId: Int, foregroundColorTint: Int? = null): Bitmap { val layers = arrayOfNulls(2) layers[0] = context.getDrawable(R.color.bg_message_list_incoming_bubble) var scale = 0.25f @@ -76,8 +76,12 @@ class Images { scale = 0.5f } layers[1] = ScaleDrawable(context.getDrawable(drawableId), Gravity.CENTER, scale, scale) + if (foregroundColorTint != null) { + layers[1]?.setTint(context.resources.getColor(foregroundColorTint)) + } layers[0]?.level = 0 layers[1]?.level = 1 + return LayerDrawable(layers).toBitmap() } diff --git a/app/src/main/res/layout/contacts_list_view.xml b/app/src/main/res/layout/contacts_list_view.xml index 13c63a736..ca309f88d 100644 --- a/app/src/main/res/layout/contacts_list_view.xml +++ b/app/src/main/res/layout/contacts_list_view.xml @@ -2,12 +2,29 @@ + android:layout_height="match_parent" + android:animateLayoutChanges="true"> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/rv_item_contact.xml b/app/src/main/res/layout/rv_item_contact.xml index 01ecd33e0..78654d3ee 100644 --- a/app/src/main/res/layout/rv_item_contact.xml +++ b/app/src/main/res/layout/rv_item_contact.xml @@ -26,20 +26,20 @@ android:layout_width="match_parent" android:layout_height="@dimen/rv_item_view_height" android:layout_margin="@dimen/margin_between_elements" - android:orientation="vertical"> + android:orientation="vertical" + android:layout_centerInParent="true"> + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/rv_item_conversation.xml b/app/src/main/res/layout/rv_item_conversation.xml index afda6fa37..ae2be9d3a 100644 --- a/app/src/main/res/layout/rv_item_conversation.xml +++ b/app/src/main/res/layout/rv_item_conversation.xml @@ -74,7 +74,7 @@ android:orientation="vertical">