mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-21 12:39:58 +01:00
Update UI for contacts
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
3c15393ba4
commit
c80b611ae9
@ -92,8 +92,8 @@ class NextcloudTalkRepositoryImpl(private val apiService: ApiService) : Nextclou
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getContactsForUser(user: UserNgEntity, searchQuery: String?, conversationToken: String?): List<Participant> {
|
||||
return apiService.getContacts(authorization = user.getCredentials(), url = ApiUtils.getUrlForContactsSearch(user.baseUrl), shareTypes = ApiUtils.getShareTypesForContactsSearch(), options = ApiUtils.getQueryMapForContactsSearch(searchQuery, conversationToken)).ocs.data.map {
|
||||
override suspend fun getContactsForUser(user: UserNgEntity, groupConversation: Boolean, searchQuery: String?, conversationToken: String?): List<Participant> {
|
||||
return apiService.getContacts(authorization = user.getCredentials(), url = ApiUtils.getUrlForContactsSearch(user.baseUrl), shareTypes = ApiUtils.getShareTypesForContactsSearch(groupConversation), options = ApiUtils.getQueryMapForContactsSearch(searchQuery, conversationToken)).ocs.data.map {
|
||||
val participant = Participant()
|
||||
participant.userId = it.id
|
||||
participant.displayName = it.label
|
||||
|
@ -33,7 +33,7 @@ import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
|
||||
import com.nextcloud.talk.newarch.local.models.UserNgEntity
|
||||
|
||||
interface NextcloudTalkRepository {
|
||||
suspend fun getContactsForUser(user: UserNgEntity, searchQuery: String?, conversationToken: String?): List<Participant>
|
||||
suspend fun getContactsForUser(user: UserNgEntity, groupConversation: Boolean, searchQuery: String?, conversationToken: String?): List<Participant>
|
||||
suspend fun registerPushWithServerForUser(user: UserNgEntity, options: Map<String, String>): PushRegistrationOverall
|
||||
suspend fun unregisterPushWithServerForUser(user: UserNgEntity): GenericOverall
|
||||
suspend fun registerPushWithProxyForUser(user: UserNgEntity, options: Map<String, String>): Any
|
||||
|
@ -34,6 +34,6 @@ class GetContactsUseCase constructor(
|
||||
) : UseCase<List<Participant>, Any?>(apiErrorHandler) {
|
||||
override suspend fun run(params: Any?): List<Participant> {
|
||||
val definitionParameters = params as DefinitionParameters
|
||||
return nextcloudTalkRepository.getContactsForUser(definitionParameters[0], definitionParameters[1], definitionParameters[2])
|
||||
return nextcloudTalkRepository.getContactsForUser(definitionParameters[0], definitionParameters[1], definitionParameters[2], definitionParameters[3])
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ open class ContactPresenter<T : Any>(context: Context, onElementClick: ((Page, H
|
||||
private val globalService: GlobalService by inject()
|
||||
|
||||
override val elementTypes: Collection<Int>
|
||||
get() = listOf(ParticipantElementType.PARTICIPANT.ordinal, ParticipantElementType.PARTICIPANT_SELECTED.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, ParticipantElementType.PARTICIPANT_NEW_GROUP.ordinal, ParticipantElementType.PARTICIPANT_JOIN_VIA_LINK.ordinal)
|
||||
|
||||
override fun onCreate(parent: ViewGroup, elementType: Int): Holder {
|
||||
return when (elementType) {
|
||||
@ -64,9 +64,13 @@ open class ContactPresenter<T : Any>(context: Context, onElementClick: ((Page, H
|
||||
ParticipantElementType.PARTICIPANT_HEADER.ordinal -> {
|
||||
Holder(getLayoutInflater().inflate(R.layout.rv_item_title_header, parent, false))
|
||||
}
|
||||
else -> {
|
||||
ParticipantElementType.PARTICIPANT_FOOTER.ordinal -> {
|
||||
Holder(getLayoutInflater().inflate(R.layout.rv_item_participant_rv_footer, parent, false))
|
||||
}
|
||||
else -> {
|
||||
// for join via link and new group
|
||||
Holder(getLayoutInflater().inflate(R.layout.rv_item_contact, parent, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,8 +124,16 @@ open class ContactPresenter<T : Any>(context: Context, onElementClick: ((Page, H
|
||||
}
|
||||
} else if (element.type == ParticipantElementType.PARTICIPANT_HEADER.ordinal) {
|
||||
holder.itemView.titleTextView.text = (element.data as HeaderSource.Data<*, *>).header.toString()
|
||||
} else {
|
||||
} else if (element.type == ParticipantElementType.PARTICIPANT_FOOTER.ordinal){
|
||||
holder.itemView.messageTextView.text = (element.data as FooterSource.Data<*, *>).footer.toString()
|
||||
} else if (element.type == ParticipantElementType.PARTICIPANT_NEW_GROUP.ordinal) {
|
||||
val pairData = element.data as Pair<*, *>
|
||||
holder.itemView.participantNameTextView.text = pairData.first as CharSequence
|
||||
holder.itemView.avatarImageView.load(Images().getImageWithBackground(context, pairData.second as Int))
|
||||
} else {
|
||||
val pairData = element.data as Pair<*, *>
|
||||
holder.itemView.participantNameTextView.text = pairData.first as CharSequence
|
||||
holder.itemView.avatarImageView.load(Images().getImageWithBackground(context, pairData.second as Int))
|
||||
}
|
||||
}
|
||||
}
|
@ -26,5 +26,7 @@ enum class ParticipantElementType {
|
||||
PARTICIPANT,
|
||||
PARTICIPANT_SELECTED,
|
||||
PARTICIPANT_HEADER,
|
||||
PARTICIPANT_FOOTER
|
||||
PARTICIPANT_FOOTER,
|
||||
PARTICIPANT_NEW_GROUP,
|
||||
PARTICIPANT_JOIN_VIA_LINK
|
||||
}
|
@ -34,14 +34,12 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.models.json.participants.Participant
|
||||
import com.nextcloud.talk.newarch.features.contactsflow.source.FixedListSource
|
||||
import com.nextcloud.talk.newarch.mvvm.BaseView
|
||||
import com.nextcloud.talk.newarch.mvvm.ext.initRecyclerView
|
||||
import com.nextcloud.talk.newarch.utils.ElementPayload
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys
|
||||
import com.otaliastudios.elements.Adapter
|
||||
import com.otaliastudios.elements.Element
|
||||
import com.otaliastudios.elements.Page
|
||||
import com.otaliastudios.elements.Presenter
|
||||
import com.otaliastudios.elements.*
|
||||
import com.uber.autodispose.lifecycle.LifecycleScopeProvider
|
||||
import kotlinx.android.synthetic.main.contacts_list_view.view.*
|
||||
import kotlinx.android.synthetic.main.conversations_list_view.view.recyclerView
|
||||
@ -59,6 +57,9 @@ class ContactsView<T : Any>(private val bundle: Bundle? = null) : BaseView() {
|
||||
return R.layout.contacts_list_view
|
||||
}
|
||||
|
||||
private val isGroupConversation = bundle?.containsKey(BundleKeys.KEY_CONVERSATION_NAME) == true
|
||||
private val hasToken = bundle?.containsKey(BundleKeys.KEY_CONVERSATION_TOKEN) == true
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup
|
||||
@ -71,9 +72,11 @@ class ContactsView<T : Any>(private val bundle: Bundle? = null) : BaseView() {
|
||||
|
||||
// todo - change empty state magic
|
||||
participantsAdapter = Adapter.builder(this)
|
||||
.addSource(FixedListSource(listOf(Pair(context.getString(R.string.nc_new_group), R.drawable.ic_people_group_white_24px)), ParticipantElementType.PARTICIPANT_NEW_GROUP.ordinal))
|
||||
//.addSource(FixedListSource(listOf(Pair(context.getString(R.string.nc_join_via_link), R.drawable.ic_link_white_24px)), ParticipantElementType.PARTICIPANT_JOIN_VIA_LINK.ordinal))
|
||||
.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))
|
||||
.addSource(ContactsViewFooterSource(activity as Context, ParticipantElementType.PARTICIPANT_FOOTER.ordinal))
|
||||
.addPresenter(ContactPresenter(activity as Context, ::onElementClick))
|
||||
.addPresenter(Presenter.forLoadingIndicator(activity as Context, R.layout.loading_state))
|
||||
.addPresenter(Presenter.forEmptyIndicator(activity as Context, R.layout.message_state))
|
||||
@ -136,7 +139,7 @@ class ContactsView<T : Any>(private val bundle: Bundle? = null) : BaseView() {
|
||||
|
||||
}
|
||||
|
||||
viewModel.initialize(bundle?.getString(BundleKeys.KEY_CONVERSATION_TOKEN))
|
||||
viewModel.initialize(bundle?.getString(BundleKeys.KEY_CONVERSATION_TOKEN), bundle?.containsKey(BundleKeys.KEY_CONVERSATION_NAME) == true)
|
||||
|
||||
return view
|
||||
}
|
||||
@ -149,26 +152,46 @@ class ContactsView<T : Any>(private val bundle: Bundle? = null) : BaseView() {
|
||||
private fun onElementClick(page: Page, holder: Presenter.Holder, element: Element<T>) {
|
||||
if (element.data is Participant?) {
|
||||
val participant = element.data as Participant?
|
||||
val isElementSelected = participant?.selected == true
|
||||
participant?.let {
|
||||
if (isElementSelected) {
|
||||
viewModel.unselectParticipant(it)
|
||||
} else {
|
||||
viewModel.selectParticipant(it)
|
||||
}
|
||||
it.selected = !isElementSelected
|
||||
if (element.type == ParticipantElementType.PARTICIPANT_SELECTED.ordinal) {
|
||||
participantsAdapter.notifyItemRangeChanged(0, participantsAdapter.itemCount, ElementPayload.SELECTION_TOGGLE)
|
||||
} else {
|
||||
participantsAdapter.notifyItemChanged(holder.adapterPosition, ElementPayload.SELECTION_TOGGLE)
|
||||
}
|
||||
|
||||
if (isGroupConversation || hasToken) {
|
||||
val isElementSelected = participant?.selected == true
|
||||
participant?.let {
|
||||
if (isElementSelected) {
|
||||
viewModel.unselectParticipant(it)
|
||||
} else {
|
||||
viewModel.selectParticipant(it)
|
||||
}
|
||||
it.selected = !isElementSelected
|
||||
if (element.type == ParticipantElementType.PARTICIPANT_SELECTED.ordinal) {
|
||||
participantsAdapter.notifyItemRangeChanged(0, participantsAdapter.itemCount, ElementPayload.SELECTION_TOGGLE)
|
||||
} else {
|
||||
participantsAdapter.notifyItemChanged(holder.adapterPosition, ElementPayload.SELECTION_TOGGLE)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
participant?.let {
|
||||
// create room etc etc
|
||||
}
|
||||
}
|
||||
} else if (element.type == ParticipantElementType.PARTICIPANT_NEW_GROUP.ordinal) {
|
||||
|
||||
} else if (element.type == ParticipantElementType.PARTICIPANT_JOIN_VIA_LINK.ordinal) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTitle(): String? {
|
||||
return resources?.getString(R.string.nc_select_contacts)
|
||||
return when {
|
||||
isGroupConversation -> {
|
||||
resources?.getString(R.string.nc_select_contacts)
|
||||
}
|
||||
hasToken -> {
|
||||
resources?.getString(R.string.nc_select_new_contacts)
|
||||
}
|
||||
else -> {
|
||||
resources?.getString(R.string.nc_select_contact)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -29,7 +29,7 @@ import com.otaliastudios.elements.Page
|
||||
import com.otaliastudios.elements.Source
|
||||
import com.otaliastudios.elements.extensions.FooterSource
|
||||
|
||||
class ContactsFooterSource(private val context: Context, private val elementType: Int) : FooterSource<Participant, String>() {
|
||||
class ContactsViewFooterSource(private val context: Context, private val elementType: Int) : FooterSource<Participant, String>() {
|
||||
private var lastAnchor: Participant? = null
|
||||
|
||||
override fun dependsOn(source: Source<*>): Boolean {
|
@ -45,11 +45,13 @@ class ContactsViewModel constructor(
|
||||
|
||||
private var searchQuery: String? = null
|
||||
private var conversationToken: String? = null
|
||||
private var groupConversation: Boolean = false
|
||||
private var initialized = false
|
||||
|
||||
fun initialize(conversationToken: String?) {
|
||||
if (!initialized || conversationToken != this.conversationToken) {
|
||||
fun initialize(conversationToken: String?, groupConversation: Boolean) {
|
||||
if (!initialized || conversationToken != this.conversationToken || groupConversation != this.groupConversation) {
|
||||
this.conversationToken = conversationToken
|
||||
this.groupConversation = groupConversation
|
||||
loadContacts()
|
||||
}
|
||||
}
|
||||
@ -70,7 +72,7 @@ class ContactsViewModel constructor(
|
||||
}
|
||||
|
||||
fun loadContacts() {
|
||||
getContactsUseCase.invoke(viewModelScope, parametersOf(globalService.currentUserLiveData.value, searchQuery, conversationToken), object :
|
||||
getContactsUseCase.invoke(viewModelScope, parametersOf(globalService.currentUserLiveData.value, groupConversation, searchQuery, conversationToken), object :
|
||||
UseCaseResponse<List<Participant>> {
|
||||
override suspend fun onSuccess(result: List<Participant>) {
|
||||
val sortPriority = mapOf("users" to 0, "groups" to 1, "emails" to 2, "circles" to 0)
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||
* *
|
||||
* * 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 com.nextcloud.talk.newarch.features.contactsflow.source
|
||||
|
||||
import com.nextcloud.talk.newarch.features.contactsflow.ContactsViewSource
|
||||
import com.otaliastudios.elements.Source
|
||||
import com.otaliastudios.elements.extensions.ListSource
|
||||
|
||||
class FixedListSource(list: List<Any>, elementType: Int) : ListSource<Any>(list, elementType) {
|
||||
override fun areContentsTheSame(first: Any, second: Any): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun <E : Any> areItemsTheSame(own: Any, dependency: Source<E>, other: E?): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun dependsOn(source: Source<*>): Boolean {
|
||||
return source is ContactsViewSource
|
||||
}
|
||||
}
|
@ -67,16 +67,18 @@ public class ApiUtils {
|
||||
return baseUrl + ocsApiVersion + "/core/autocomplete/get";
|
||||
}
|
||||
|
||||
public static List<String> getShareTypesForContactsSearch() {
|
||||
public static List<String> getShareTypesForContactsSearch(boolean groupConversation) {
|
||||
List<String> shareTypesList = new ArrayList<>();
|
||||
// user
|
||||
shareTypesList.add("0");
|
||||
// group
|
||||
shareTypesList.add("1");
|
||||
// group
|
||||
shareTypesList.add("4");
|
||||
// remote/circles
|
||||
shareTypesList.add("7");
|
||||
if (groupConversation) {
|
||||
// group
|
||||
shareTypesList.add("1");
|
||||
// email
|
||||
shareTypesList.add("4");
|
||||
// remote/circles
|
||||
shareTypesList.add("7");
|
||||
}
|
||||
|
||||
return shareTypesList;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@
|
||||
android:icon="@drawable/ic_search_white_24dp"
|
||||
android:title="@string/nc_search"
|
||||
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||
app:showAsAction="collapseActionView|always" />
|
||||
app:showAsAction="collapseActionView|ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/contacts_selection_done"
|
||||
|
@ -180,7 +180,9 @@
|
||||
conversations list</string>
|
||||
|
||||
<!-- Contacts -->
|
||||
<string name="nc_select_contact">Find participant</string>
|
||||
<string name="nc_select_contacts">Find participants</string>
|
||||
<string name="nc_select_new_contacts">Find new participants</string>
|
||||
<string name="nc_contacts_done">Done</string>
|
||||
|
||||
<!-- Permissions -->
|
||||
@ -339,4 +341,5 @@
|
||||
<string name="path_password_strike_through" translatable="false"
|
||||
tools:override="true">M3.27,4.27L19.74,20.74</string>
|
||||
<string name="nc_search_for_more">Search for more participants</string>
|
||||
<string name="nc_new_group">New group</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user