diff --git a/.idea/inspectionProfiles/ktlint.xml b/.idea/inspectionProfiles/ktlint.xml
index 27ceb5ff2..a34119a8b 100644
--- a/.idea/inspectionProfiles/ktlint.xml
+++ b/.idea/inspectionProfiles/ktlint.xml
@@ -66,6 +66,9 @@
+
+
+
diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.kt
index 018ad0f6a..36fa9a24d 100644
--- a/app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.kt
+++ b/app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.kt
@@ -194,6 +194,7 @@ class ContactItem(
}
companion object {
+ const val VIEW_TYPE = FlexibleItemViewType.CONTACT_ITEM
private const val FULLY_OPAQUE: Float = 1.0f
private const val SEMI_TRANSPARENT: Float = 0.38f
}
diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/FlexibleItemViewType.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/FlexibleItemViewType.kt
index ab966c630..656cd8d90 100644
--- a/app/src/main/java/com/nextcloud/talk/adapters/items/FlexibleItemViewType.kt
+++ b/app/src/main/java/com/nextcloud/talk/adapters/items/FlexibleItemViewType.kt
@@ -6,14 +6,13 @@
*/
package com.nextcloud.talk.adapters.items
-class FlexibleItemViewType {
- companion object {
- const val CONVERSATION_ITEM: Int = 1120391230
- const val LOAD_MORE_RESULTS_ITEM: Int = 1120391231
- const val MESSAGE_RESULT_ITEM: Int = 1120391232
- const val MESSAGES_TEXT_HEADER_ITEM: Int = 1120391233
- const val POLL_RESULT_HEADER_ITEM: Int = 1120391234
- const val POLL_RESULT_VOTER_ITEM: Int = 1120391235
- const val POLL_RESULT_VOTERS_OVERVIEW_ITEM: Int = 1120391236
- }
+object FlexibleItemViewType {
+ const val CONVERSATION_ITEM: Int = 1120391230
+ const val LOAD_MORE_RESULTS_ITEM: Int = 1120391231
+ const val MESSAGE_RESULT_ITEM: Int = 1120391232
+ const val MESSAGES_TEXT_HEADER_ITEM: Int = 1120391233
+ const val POLL_RESULT_HEADER_ITEM: Int = 1120391234
+ const val POLL_RESULT_VOTER_ITEM: Int = 1120391235
+ const val POLL_RESULT_VOTERS_OVERVIEW_ITEM: Int = 1120391236
+ const val CONTACT_ITEM: Int = 2131558687
}
diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepository.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepository.kt
index 8655b79e1..03551ebed 100644
--- a/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepository.kt
+++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepository.kt
@@ -12,6 +12,11 @@ import com.nextcloud.talk.models.json.conversations.RoomOverall
interface ContactsRepository {
suspend fun getContacts(searchQuery: String?, shareTypes: List): AutocompleteOverall
- suspend fun createRoom(roomType: String, sourceType: String, userId: String, conversationName: String?): RoomOverall
+ suspend fun createRoom(
+ roomType: String,
+ sourceType: String?,
+ userId: String,
+ conversationName: String?
+ ): RoomOverall
fun getImageUri(avatarId: String, requestBigSize: Boolean): String
}
diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt
index 6fcd27512..cb3f606bc 100644
--- a/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt
+++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt
@@ -45,7 +45,7 @@ class ContactsRepositoryImpl(
override suspend fun createRoom(
roomType: String,
- sourceType: String,
+ sourceType: String?,
userId: String,
conversationName: String?
): RoomOverall {
diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt
index 049646f05..821242883 100644
--- a/app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt
+++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt
@@ -87,7 +87,7 @@ class ContactsViewModel @Inject constructor(
}
@Suppress("Detekt.TooGenericExceptionCaught")
- fun createRoom(roomType: String, sourceType: String, userId: String, conversationName: String?) {
+ fun createRoom(roomType: String, sourceType: String?, userId: String, conversationName: String?) {
viewModelScope.launch {
try {
val room = repository.createRoom(
diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt
index ae3e4242c..af02b68e5 100644
--- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt
+++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt
@@ -70,6 +70,7 @@ import com.nextcloud.talk.account.WebViewLoginActivity
import com.nextcloud.talk.activities.BaseActivity
import com.nextcloud.talk.activities.CallActivity
import com.nextcloud.talk.activities.MainActivity
+import com.nextcloud.talk.adapters.items.ContactItem
import com.nextcloud.talk.adapters.items.ConversationItem
import com.nextcloud.talk.adapters.items.GenericTextHeaderItem
import com.nextcloud.talk.adapters.items.LoadMoreResultsItem
@@ -80,6 +81,9 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager
import com.nextcloud.talk.chat.ChatActivity
import com.nextcloud.talk.contacts.ContactsActivityCompose
+import com.nextcloud.talk.contacts.ContactsUiState
+import com.nextcloud.talk.contacts.ContactsViewModel
+import com.nextcloud.talk.contacts.RoomUiState
import com.nextcloud.talk.conversationlist.viewmodels.ConversationsListViewModel
import com.nextcloud.talk.data.network.NetworkMonitor
import com.nextcloud.talk.data.user.model.User
@@ -95,6 +99,9 @@ import com.nextcloud.talk.messagesearch.MessageSearchHelper
import com.nextcloud.talk.messagesearch.MessageSearchHelper.MessageSearchResults
import com.nextcloud.talk.models.domain.ConversationModel
import com.nextcloud.talk.models.json.conversations.ConversationEnums
+import com.nextcloud.talk.models.json.conversations.RoomsOverall
+import com.nextcloud.talk.models.json.converters.EnumActorTypeConverter
+import com.nextcloud.talk.models.json.participants.Participant
import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository
import com.nextcloud.talk.settings.SettingsActivity
import com.nextcloud.talk.ui.dialog.ChooseAccountDialogFragment
@@ -178,6 +185,9 @@ class ConversationsListActivity :
@Inject
lateinit var networkMonitor: NetworkMonitor
+ @Inject
+ lateinit var contactsViewModel: ContactsViewModel
+
lateinit var conversationsListViewModel: ConversationsListViewModel
override val appBarLayoutType: AppBarLayoutType
@@ -317,6 +327,7 @@ class ConversationsListActivity :
showSearchOrToolbar()
}
+ @Suppress("LongMethod")
private fun initObservers() {
this.lifecycleScope.launch {
networkMonitor.isOnline.onEach { isOnline ->
@@ -387,6 +398,63 @@ class ConversationsListActivity :
setConversationList(list)
}.collect()
}
+
+ lifecycleScope.launch {
+ contactsViewModel.roomViewState.onEach { state ->
+ when (state) {
+ is RoomUiState.Success -> {
+ val conversation = state.conversation
+ val bundle = Bundle()
+ bundle.putString(BundleKeys.KEY_ROOM_TOKEN, conversation?.token)
+ val chatIntent = Intent(context, ChatActivity::class.java)
+ chatIntent.putExtras(bundle)
+ chatIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ startActivity(chatIntent)
+ }
+
+ else -> {}
+ }
+ }.collect()
+ }
+
+ lifecycleScope.launch {
+ contactsViewModel.contactsViewState.onEach { state ->
+ when (state) {
+ is ContactsUiState.Success -> {
+ if (state.contacts.isNullOrEmpty()) return@onEach
+
+ val userItems: MutableList> = ArrayList()
+ val actorTypeConverter = EnumActorTypeConverter()
+ var genericTextHeaderItem: GenericTextHeaderItem
+ for (autocompleteUser in state.contacts) {
+ val headerTitle = resources!!.getString(R.string.nc_user)
+ if (!callHeaderItems.containsKey(headerTitle)) {
+ genericTextHeaderItem = GenericTextHeaderItem(headerTitle, viewThemeUtils)
+ callHeaderItems[headerTitle] = genericTextHeaderItem
+ }
+
+ val participant = Participant()
+ participant.actorId = autocompleteUser.id
+ participant.actorType = actorTypeConverter.getFromString(autocompleteUser.source)
+ participant.displayName = autocompleteUser.label
+
+ val contactItem = ContactItem(
+ participant,
+ currentUser!!,
+ callHeaderItems[headerTitle],
+ viewThemeUtils
+ )
+
+ userItems.add(contactItem)
+ }
+
+ searchableConversationItems.addAll(userItems)
+ }
+
+ else -> {}
+ }
+ }.collect()
+ }
}
private fun setConversationList(list: List) {
@@ -411,6 +479,9 @@ class ConversationsListActivity :
intArrayOf(ApiUtils.API_V4, ApiUtils.API_V3, 1)
)
fetchOpenConversations(apiVersion)
+
+ // Get users
+ fetchUsers()
}
private fun hasFilterEnabled(): Boolean {
@@ -944,40 +1015,45 @@ class ConversationsListActivity :
)
) {
val openConversationItems: MutableList> = ArrayList()
- // openConversationsQueryDisposable = ncApi.getOpenConversations(
- // credentials,
- // ApiUtils.getUrlForOpenConversations(apiVersion, currentUser!!.baseUrl!!)
- // )
- // .subscribeOn(Schedulers.io())
- // .observeOn(AndroidSchedulers.mainThread())
- // .subscribe({ (ocs): RoomsOverall ->
- // for (conversation in ocs!!.data!!) {
- // val headerTitle = resources!!.getString(R.string.openConversations)
- // var genericTextHeaderItem: GenericTextHeaderItem
- // if (!callHeaderItems.containsKey(headerTitle)) {
- // genericTextHeaderItem = GenericTextHeaderItem(headerTitle, viewThemeUtils)
- // callHeaderItems[headerTitle] = genericTextHeaderItem
- // }
- // val conversationItem = ConversationItem(
- // conversation,
- // currentUser!!,
- // this,
- // callHeaderItems[headerTitle],
- // viewThemeUtils
- // )
- // openConversationItems.add(conversationItem)
- // }
- // searchableConversationItems.addAll(openConversationItems)
- // }, { throwable: Throwable ->
- // Log.e(TAG, "fetchData - getRooms - ERROR", throwable)
- // handleHttpExceptions(throwable)
- // dispose(openConversationsQueryDisposable)
- // }) { dispose(openConversationsQueryDisposable) }
+ openConversationsQueryDisposable = ncApi.getOpenConversations(
+ credentials,
+ ApiUtils.getUrlForOpenConversations(apiVersion, currentUser!!.baseUrl!!),
+ ""
+ )
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({ (ocs): RoomsOverall ->
+ for (conversation in ocs!!.data!!) {
+ val headerTitle = resources!!.getString(R.string.openConversations)
+ var genericTextHeaderItem: GenericTextHeaderItem
+ if (!callHeaderItems.containsKey(headerTitle)) {
+ genericTextHeaderItem = GenericTextHeaderItem(headerTitle, viewThemeUtils)
+ callHeaderItems[headerTitle] = genericTextHeaderItem
+ }
+ val conversationItem = ConversationItem(
+ ConversationModel.mapToConversationModel(conversation, currentUser!!),
+ currentUser!!,
+ this,
+ callHeaderItems[headerTitle],
+ viewThemeUtils
+ )
+ openConversationItems.add(conversationItem)
+ }
+ searchableConversationItems.addAll(openConversationItems)
+ }, { throwable: Throwable ->
+ Log.e(TAG, "fetchData - getRooms - ERROR", throwable)
+ handleHttpExceptions(throwable)
+ dispose(openConversationsQueryDisposable)
+ }) { dispose(openConversationsQueryDisposable) }
} else {
Log.d(TAG, "no open conversations fetched because of missing capability")
}
}
+ private fun fetchUsers() {
+ contactsViewModel.getContactsFromSearchParams()
+ }
+
private fun handleHttpExceptions(throwable: Throwable) {
if (throwable is HttpException) {
when (throwable.code()) {
@@ -1247,6 +1323,16 @@ class ConversationsListActivity :
ConversationItem.VIEW_TYPE -> {
handleConversation((Objects.requireNonNull(item) as ConversationItem).model)
}
+
+ ContactItem.VIEW_TYPE -> {
+ val contact = item as ContactItem
+ contactsViewModel.createRoom(
+ ROOM_TYPE_ONE_ONE,
+ null,
+ contact.model.actorId!!,
+ null
+ )
+ }
}
}
return true
@@ -1923,8 +2009,8 @@ class ConversationsListActivity :
if (results.hasMore) {
adapterItems.add(LoadMoreResultsItem)
}
- // add unified search result at the end of the list
- adapter!!.addItems(adapter!!.mainItemCount + adapter!!.scrollableHeaders.size, adapterItems)
+
+ adapter!!.addItems(0, adapterItems)
binding.recyclerView?.scrollToPosition(0)
}
}
@@ -1965,7 +2051,7 @@ class ConversationsListActivity :
const val BOTTOM_SHEET_DELAY: Long = 2500
private const val KEY_SEARCH_QUERY = "ConversationsListActivity.searchQuery"
const val SEARCH_DEBOUNCE_INTERVAL_MS = 300
- const val SEARCH_MIN_CHARS = 2
+ const val SEARCH_MIN_CHARS = 1
const val HTTP_UNAUTHORIZED = 401
const val HTTP_CLIENT_UPGRADE_REQUIRED = 426
const val CLIENT_UPGRADE_MARKET_LINK = "market://details?id="
@@ -1977,5 +2063,6 @@ class ConversationsListActivity :
const val DAYS_FOR_NOTIFICATION_WARNING = 5L
const val NOTIFICATION_WARNING_DATE_NOT_SET = 0L
const val OFFSET_HEIGHT_DIVIDER: Int = 3
+ const val ROOM_TYPE_ONE_ONE = "1"
}
}
diff --git a/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositoryError.kt b/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositoryError.kt
index 1cb9b51ac..064540985 100644
--- a/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositoryError.kt
+++ b/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositoryError.kt
@@ -20,7 +20,7 @@ class FakeRepositoryError : ContactsRepository {
@Suppress("Detekt.TooGenericExceptionThrown")
override suspend fun createRoom(
roomType: String,
- sourceType: String,
+ sourceType: String?,
userId: String,
conversationName: String?
): RoomOverall {
diff --git a/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt b/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt
index f5d87d919..39037c4ce 100644
--- a/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt
+++ b/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt
@@ -19,7 +19,7 @@ class FakeRepositorySuccess : ContactsRepository {
override suspend fun createRoom(
roomType: String,
- sourceType: String,
+ sourceType: String?,
userId: String,
conversationName: String?
): RoomOverall {