Lots of cleanups & work on contacts

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2020-01-22 16:29:06 +01:00
parent 7efb05184c
commit 4901534da7
No known key found for this signature in database
GPG Key ID: CDE0BBD2738C4CC0
40 changed files with 527 additions and 262 deletions

View File

@ -38,11 +38,11 @@ import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
import com.google.android.material.appbar.MaterialToolbar
import com.nextcloud.talk.R
import com.nextcloud.talk.controllers.CallNotificationController
import com.nextcloud.talk.controllers.ContactsController
import com.nextcloud.talk.controllers.LockedController
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
import com.nextcloud.talk.newarch.features.account.serverentry.ServerEntryView
import com.nextcloud.talk.newarch.features.contactsflow.ContactsView
import com.nextcloud.talk.newarch.features.conversationslist.ConversationsListView
import com.nextcloud.talk.newarch.local.models.UserNgEntity
import com.nextcloud.talk.utils.ConductorRemapping
@ -102,12 +102,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
@OnClick(R.id.floatingActionButton)
fun onFloatingActionButtonClick() {
val bundle = Bundle()
bundle.putBoolean(BundleKeys.KEY_NEW_CONVERSATION, true)
router?.pushController(
RouterTransaction.with(ContactsController(bundle))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
openNewConversationScreen()
}
override fun onStart() {
@ -150,7 +145,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
withContext(Dispatchers.Main) {
ConductorRemapping.remapChatController(
router!!, it.id!!,
intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN)!!, extras, false)
intent.getStringExtra(BundleKeys.KEY_CONVERSATION_TOKEN)!!, extras, false)
}
}
}
@ -164,7 +159,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
} else {
ConductorRemapping.remapChatController(
router!!, intent.getLongExtra(BundleKeys.KEY_INTERNAL_USER_ID, -1),
intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN)!!, intent.extras!!, false
intent.getStringExtra(BundleKeys.KEY_CONVERSATION_TOKEN)!!, intent.extras!!, false
)
}
}
@ -181,11 +176,8 @@ class MainActivity : BaseActivity(), ActionBarProvider {
}
private fun openNewConversationScreen() {
val bundle = Bundle()
bundle.putBoolean(BundleKeys.KEY_NEW_CONVERSATION, true)
router?.pushController(
RouterTransaction.with(ContactsController(bundle))
RouterTransaction.with(ContactsView())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)

View File

@ -46,6 +46,7 @@ import com.nextcloud.talk.models.json.signaling.settings.SignalingSettings
import com.nextcloud.talk.newarch.di.module.*
import com.nextcloud.talk.newarch.domain.di.module.UseCasesModule
import com.nextcloud.talk.newarch.features.account.di.module.AccountModule
import com.nextcloud.talk.newarch.features.contactsflow.di.module.ContactsFlowModule
import com.nextcloud.talk.newarch.features.conversationslist.di.module.ConversationsListModule
import com.nextcloud.talk.newarch.local.dao.UsersDao
import com.nextcloud.talk.newarch.local.models.UserNgEntity
@ -175,7 +176,7 @@ class NextcloudTalkApplication : Application(), LifecycleObserver, Configuration
startKoin {
androidContext(this@NextcloudTalkApplication)
androidLogger()
modules(listOf(CommunicationModule, StorageModule, NetworkModule, ConversationsListModule, ServiceModule, AccountModule, UseCasesModule))
modules(listOf(CommunicationModule, StorageModule, NetworkModule, ConversationsListModule, ServiceModule, AccountModule, UseCasesModule, ContactsFlowModule))
}
}

View File

@ -86,7 +86,7 @@ class BrowserController(args: Bundle) : BaseController(), ListingInterface, Flex
setHasOptionsMenu(true)
browserType = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_BROWSER_TYPE))
activeUser = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_USER_ENTITY))
roomToken = args.getString(BundleKeys.KEY_ROOM_TOKEN)
roomToken = args.getString(BundleKeys.KEY_CONVERSATION_TOKEN)
currentPath = "/"
if (BrowserType.DAV_BROWSER == browserType) {
@ -127,7 +127,7 @@ class BrowserController(args: Bundle) : BaseController(), ListingInterface, Flex
if (paths.size == 10 || !iterator.hasNext()) {
data = Data.Builder()
.putLong(BundleKeys.KEY_INTERNAL_USER_ID, activeUser.id!!)
.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
.putString(BundleKeys.KEY_CONVERSATION_TOKEN, roomToken)
.putStringArray(BundleKeys.KEY_FILE_PATHS, paths.toTypedArray())
.build()
shareWorker = OneTimeWorkRequest.Builder(ShareOperationWorker::class.java)

View File

@ -204,7 +204,7 @@ class CallController(args: Bundle) : BaseController() {
init {
roomId = args.getString(BundleKeys.KEY_ROOM_ID, "")
roomToken = args.getString(BundleKeys.KEY_ROOM_TOKEN, "")
roomToken = args.getString(BundleKeys.KEY_CONVERSATION_TOKEN, "")
conversationUser = args.getParcelable(BundleKeys.KEY_USER_ENTITY)
conversationPassword = args.getString(BundleKeys.KEY_CONVERSATION_PASSWORD, "")
isVoiceOnlyCall = args.getBoolean(BundleKeys.KEY_CALL_VOICE_ONLY, false)

View File

@ -172,7 +172,7 @@ class CallNotificationController(private val originalBundle: Bundle) : BaseContr
private fun proceedToCall() {
originalBundle.putString(
BundleKeys.KEY_ROOM_TOKEN,
BundleKeys.KEY_CONVERSATION_TOKEN,
currentConversation!!.token
)

View File

@ -179,7 +179,7 @@ class ChatController(args: Bundle) : BaseController(), MessagesListAdapter
this.conversationUser = args.getParcelable(BundleKeys.KEY_USER_ENTITY)
this.roomId = args.getString(BundleKeys.KEY_ROOM_ID, "")
this.roomToken = args.getString(BundleKeys.KEY_ROOM_TOKEN, "")
this.roomToken = args.getString(BundleKeys.KEY_CONVERSATION_TOKEN, "")
if (args.containsKey(BundleKeys.KEY_ACTIVE_CONVERSATION)) {
this.currentConversation = Parcels.unwrap<Conversation>(
@ -603,7 +603,7 @@ class ChatController(args: Bundle) : BaseController(), MessagesListAdapter
BundleKeys.KEY_BROWSER_TYPE, Parcels.wrap<BrowserController.BrowserType>(browserType)
)
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap<UserNgEntity>(conversationUser))
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, roomToken)
router.pushController(
RouterTransaction.with(BrowserController(bundle))
.pushChangeHandler(VerticalChangeHandler())
@ -614,7 +614,7 @@ class ChatController(args: Bundle) : BaseController(), MessagesListAdapter
private fun showConversationInfoScreen() {
val bundle = Bundle()
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, conversationUser)
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, roomToken)
router.pushController(
RouterTransaction.with(ConversationInfoController(bundle))
.pushChangeHandler(HorizontalChangeHandler())
@ -1354,7 +1354,7 @@ class ChatController(args: Bundle) : BaseController(), MessagesListAdapter
private fun getIntentForCall(isVoiceOnlyCall: Boolean): Intent? {
if (currentConversation != null) {
val bundle = Bundle()
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, roomToken)
bundle.putString(BundleKeys.KEY_ROOM_ID, roomId)
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, conversationUser)
bundle.putString(BundleKeys.KEY_CONVERSATION_PASSWORD, roomPassword)
@ -1497,7 +1497,7 @@ class ChatController(args: Bundle) : BaseController(), MessagesListAdapter
val conversationIntent = Intent(activity, MagicCallActivity::class.java)
val bundle = Bundle()
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, conversationUser)
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomOverall.ocs.data.token)
bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, roomOverall.ocs.data.token)
bundle.putString(BundleKeys.KEY_ROOM_ID, roomOverall.ocs.data.conversationId)
if (conversationUser != null) {

View File

@ -266,7 +266,7 @@ class ContactsController : BaseController,
val bundle = Bundle()
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, currentUser)
bundle.putString(
BundleKeys.KEY_ROOM_TOKEN,
BundleKeys.KEY_CONVERSATION_TOKEN,
roomOverall.ocs.data.token
)
bundle.putString(
@ -440,174 +440,7 @@ class ContactsController : BaseController,
val query = adapter!!.getFilter(String::class.java)
val retrofitBucket: RetrofitBucket = ApiUtils.getRetrofitBucketForContactsSearchFor14(currentUser!!.baseUrl, query)
val modifiedQueryMap = HashMap<String, Any>(retrofitBucket.queryMap)
modifiedQueryMap["limit"] = 50
var shareTypesList: MutableList<String> = mutableListOf()
// user
shareTypesList.add("0")
// group
shareTypesList.add("1")
// remote/circles
shareTypesList.add("7");
conversationToken?.let {
modifiedQueryMap["itemId"] = it
// emails
shareTypesList.add("4")
}
modifiedQueryMap["shareTypes[]"] = shareTypesList
ncApi.getContactsWithSearchParam(
credentials,
retrofitBucket.url, shareTypesList, modifiedQueryMap
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(3)
.`as`(AutoDispose.autoDisposable(scopeProvider))
.subscribe(object : Observer<ResponseBody> {
override fun onSubscribe(d: Disposable) {}
override fun onNext(responseBody: ResponseBody) {
var participant: Participant
val newUserItemList = ArrayList<AbstractFlexibleItem<*>>()
try {
val autocompleteOverall =
LoganSquare.parse(responseBody.string(), AutocompleteOverall::class.java)
autocompleteUsersHashSet.addAll(autocompleteOverall.ocs.data)
for (autocompleteUser in autocompleteUsersHashSet) {
participant = Participant()
participant.userId = autocompleteUser.id
participant.displayName = autocompleteUser.label
participant.source = autocompleteUser.source
var headerTitle: String?
if (autocompleteUser.source == "groups") {
headerTitle = resources?.getString(R.string.nc_groups)
} else if (autocompleteUser.source == "users") {
headerTitle = resources?.getString(R.string.nc_contacts)
} else if (autocompleteUser.source == "emails") {
headerTitle = resources?.getString(R.string.nc_emails)
} else {
headerTitle = ""
}
headerTitle as String
val genericTextHeaderItem: GenericTextHeaderItem
if (!userHeaderItems.containsKey(headerTitle)) {
genericTextHeaderItem = GenericTextHeaderItem(headerTitle)
userHeaderItems[headerTitle] = genericTextHeaderItem
}
val newContactItem = UserItem(
participant, currentUser!!,
userHeaderItems[headerTitle], activity!!
)
if (!contactItems!!.contains(newContactItem)) {
newUserItemList.add(newContactItem)
}
}
} catch (exception: Exception) {
Log.e(TAG, "Parsing response body failed while getting contacts")
}
userHeaderItems = HashMap()
contactItems!!.addAll(newUserItemList)
newUserItemList.sortWith(Comparator { o1, o2 ->
val firstName: String
val secondName: String
if (o1 is UserItem) {
firstName = o1.model.displayName
} else {
firstName = (o1 as GenericTextHeaderItem).model
}
if (o2 is UserItem) {
secondName = o2.model.displayName
} else {
secondName = (o2 as GenericTextHeaderItem).model
}
if (o1 is UserItem && o2 is UserItem) {
if ("groups" == o1.model.source && "groups" == o2.model.source) {
firstName.compareTo(secondName, ignoreCase = true)
} else if ("groups" == o1.model.source) {
-1
} else if ("groups" == o2.model.source) {
1
}
}
firstName.compareTo(secondName, ignoreCase = true)
})
contactItems!!.sortWith(Comparator { o1, o2 ->
val firstName: String
val secondName: String
if (o1 is UserItem) {
firstName = o1.model.displayName
} else {
firstName = (o1 as GenericTextHeaderItem).model
}
if (o2 is UserItem) {
secondName = o2.model.displayName
} else {
secondName = (o2 as GenericTextHeaderItem).model
}
if (o1 is UserItem && o2 is UserItem) {
if ("groups" == o1.model.source && "groups" == o2.model.source) {
firstName.compareTo(secondName, ignoreCase = true)
} else if ("groups" == o1.model.source) {
-1
} else if ("groups" == o2.model.source) {
1
}
}
firstName.compareTo(secondName, ignoreCase = true)
})
if (newUserItemList.size > 0) {
adapter!!.updateDataSet(newUserItemList)
} else {
adapter!!.filterItems()
}
if (swipeRefreshLayout != null) {
swipeRefreshLayout!!.isRefreshing = false
}
}
override fun onError(e: Throwable) {
if (swipeRefreshLayout != null) {
swipeRefreshLayout!!.isRefreshing = false
}
}
override fun onComplete() {
if (swipeRefreshLayout != null) {
swipeRefreshLayout!!.isRefreshing = false
}
alreadyFetching = false
disengageProgressBar()
}
})
}
private fun prepareViews() {

View File

@ -179,7 +179,7 @@ class ConversationInfoController(args: Bundle) : BaseController(),
get() {
if (!TextUtils.isEmpty(conversationToken) && conversationUser != null) {
val data = Data.Builder()
data.putString(BundleKeys.KEY_ROOM_TOKEN, conversationToken)
data.putString(BundleKeys.KEY_CONVERSATION_TOKEN, conversationToken)
data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, conversationUser.id!!)
return data.build()
}
@ -190,7 +190,7 @@ class ConversationInfoController(args: Bundle) : BaseController(),
init {
setHasOptionsMenu(true)
conversationUser = args.getParcelable(BundleKeys.KEY_USER_ENTITY)
conversationToken = args.getString(BundleKeys.KEY_ROOM_TOKEN)
conversationToken = args.getString(BundleKeys.KEY_CONVERSATION_TOKEN)
credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser.token)
}

View File

@ -572,7 +572,7 @@ class OperationsMenuController(args: Bundle) : BaseController() {
true, true, dismissView))
val conversationIntent = Intent(activity, MagicCallActivity::class.java)
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, conversation!!.token)
bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, conversation!!.token)
bundle.putString(BundleKeys.KEY_ROOM_ID, conversation!!.conversationId)
bundle.putString(BundleKeys.KEY_CONVERSATION_NAME,
conversation!!.displayName)
@ -604,7 +604,7 @@ class OperationsMenuController(args: Bundle) : BaseController() {
private fun initiateCall() {
eventBus.post(BottomSheetLockEvent(true, 0, true, true))
val bundle = Bundle()
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, conversation!!.token)
bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, conversation!!.token)
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, currentUser)
if (baseUrl != null && baseUrl != currentUser!!.baseUrl) {
bundle.putString(BundleKeys.KEY_MODIFIED_BASE_URL, baseUrl)

View File

@ -30,7 +30,7 @@ import com.nextcloud.talk.newarch.local.models.UserNgEntity
import com.nextcloud.talk.newarch.local.models.getCredentials
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_TOKEN
import io.reactivex.Observer
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
@ -53,7 +53,7 @@ class DeleteConversationWorker(context: Context,
override suspend fun doWork(): Result {
val data = inputData
val operationUserId = data.getLong(KEY_INTERNAL_USER_ID, -1)
val conversationToken = data.getString(KEY_ROOM_TOKEN)
val conversationToken = data.getString(KEY_CONVERSATION_TOKEN)
val operationUser: UserNgEntity? = usersRepository.getUserWithId(operationUserId)
operationUser?.let {
val credentials = it.getCredentials()

View File

@ -30,7 +30,7 @@ import com.nextcloud.talk.newarch.local.models.UserNgEntity
import com.nextcloud.talk.newarch.local.models.getCredentials
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_TOKEN
import io.reactivex.Observer
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
@ -51,7 +51,7 @@ class LeaveConversationWorker(context: Context, workerParams: WorkerParameters)
override fun doWork(): Result {
val data = inputData
val operationUserId = data.getLong(KEY_INTERNAL_USER_ID, -1)
val conversationToken = data.getString(KEY_ROOM_TOKEN)
val conversationToken = data.getString(KEY_CONVERSATION_TOKEN)
val operationUser: UserNgEntity? = usersRepository.getUserWithId(operationUserId)
if (operationUser != null) {
val credentials = operationUser.getCredentials()

View File

@ -91,7 +91,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_SIGNATURE
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_SUBJECT
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_TOKEN
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY
import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageUtils
import com.nextcloud.talk.utils.preferences.AppPreferences
@ -143,7 +143,7 @@ class NotificationWorker(
arbitraryStorageEntity = arbitraryStorageUtils.getStorageSetting(
userEntity.id!!,
"mute_calls",
intent.extras!!.getString(KEY_ROOM_TOKEN)
intent.extras!!.getString(KEY_CONVERSATION_TOKEN)
)
if (arbitraryStorageEntity != null) {
@ -153,7 +153,7 @@ class NotificationWorker(
arbitraryStorageEntity = arbitraryStorageUtils.getStorageSetting(
userEntity.id!!,
"important_conversation",
intent.extras!!.getString(KEY_ROOM_TOKEN)
intent.extras!!.getString(KEY_CONVERSATION_TOKEN)
)
if (arbitraryStorageEntity != null) {
@ -171,7 +171,7 @@ class NotificationWorker(
ncApi!!.getRoom(
credentials, ApiUtils.getRoom(
userEntity.baseUrl,
intent.extras!!.getString(KEY_ROOM_TOKEN)
intent.extras!!.getString(KEY_CONVERSATION_TOKEN)
)
)
.blockingSubscribe(object : Observer<RoomOverall?> {
@ -358,7 +358,7 @@ class NotificationWorker(
// could be an ID or a TOKEN
notificationInfo.putString(
KEY_ROOM_TOKEN,
KEY_CONVERSATION_TOKEN,
decryptedPushMessage!!.id
)
notificationInfo.putLong(
@ -681,7 +681,7 @@ class NotificationWorker(
)
} else {
bundle.putString(
KEY_ROOM_TOKEN,
KEY_CONVERSATION_TOKEN,
decryptedPushMessage!!.id
)
}
@ -696,7 +696,7 @@ class NotificationWorker(
intent.putExtras(bundle)
when (decryptedPushMessage!!.type) {
"call" -> if (!bundle.containsKey(
KEY_ROOM_TOKEN
KEY_CONVERSATION_TOKEN
)
) {
context!!.startActivity(intent)
@ -704,7 +704,7 @@ class NotificationWorker(
showNotificationForCallWithNoPing(intent)
}
"room" -> if (bundle.containsKey(
KEY_ROOM_TOKEN
KEY_CONVERSATION_TOKEN
)
) {
showNotificationWithObjectData(intent)

View File

@ -29,7 +29,7 @@ import com.nextcloud.talk.newarch.local.models.getCredentials
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FILE_PATHS
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_TOKEN
import io.reactivex.Observer
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
@ -74,7 +74,7 @@ class ShareOperationWorker(
init {
val data = workerParams.inputData
userId = data.getLong(KEY_INTERNAL_USER_ID, 0)
roomToken = data.getString(KEY_ROOM_TOKEN)
roomToken = data.getString(KEY_CONVERSATION_TOKEN)
Collections.addAll(
filesArray, *data.getStringArray(KEY_FILE_PATHS)

View File

@ -21,12 +21,16 @@
package com.nextcloud.talk.models.json.participants;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonIgnore;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.nextcloud.talk.models.json.converters.EnumParticipantFlagsConverter;
import com.nextcloud.talk.models.json.converters.EnumParticipantTypeConverter;
import org.parceler.Parcel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import lombok.Data;
@ -64,6 +68,7 @@ public class Participant {
@JsonField(name = "source")
public String source;
@JsonIgnore
public boolean selected;
@Override

View File

@ -20,10 +20,12 @@
package com.nextcloud.talk.newarch.data.repository.online
import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.conversations.RoomOverall
import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.models.json.participants.Participant
import com.nextcloud.talk.models.json.push.PushRegistrationOverall
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
@ -89,6 +91,16 @@ 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 {
val participant = Participant()
participant.userId = it.id
participant.displayName = it.label
participant.source = it.source
participant
}
}
override suspend fun registerPushWithServerForUser(user: UserNgEntity, options: Map<String, String>): PushRegistrationOverall {
return apiService.registerForPushWithServer(user.getCredentials(), ApiUtils.getUrlNextcloudPush(user.baseUrl), options)
}

View File

@ -20,6 +20,7 @@
package com.nextcloud.talk.newarch.data.source.remote
import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
import com.nextcloud.talk.models.json.conversations.RoomOverall
import com.nextcloud.talk.models.json.conversations.RoomsOverall
@ -31,6 +32,9 @@ import retrofit2.http.*
interface ApiService {
@GET
suspend fun getContacts(@Header("Authorization") authorization: String, @Url url: String, @Query("limit") limit: Int = 50, @Query("shareTypes[]") shareTypes: List<String>, @QueryMap options: Map<String, String>): AutocompleteOverall
@GET
suspend fun getCapabilities(@Url url: String): CapabilitiesOverall

View File

@ -47,9 +47,16 @@ val UseCasesModule = module {
single { createRegisterPushWithServerUseCase(get(), get()) }
single { createUnregisterPushWithProxyUseCase(get(), get()) }
single { createUnregisterPushWithServerUseCase(get(), get()) }
single { createGetContactsUseCase(get(), get()) }
factory { createChatViewModelFactory(get(), get(), get(), get(), get(), get()) }
}
fun createGetContactsUseCase(nextcloudTalkRepository: NextcloudTalkRepository,
apiErrorHandler: ApiErrorHandler
): GetContactsUseCase {
return GetContactsUseCase(nextcloudTalkRepository, apiErrorHandler)
}
fun createUnregisterPushWithServerUseCase(nextcloudTalkRepository: NextcloudTalkRepository,
apiErrorHandler: ApiErrorHandler
): UnregisterPushWithServerUseCase {

View File

@ -20,16 +20,19 @@
package com.nextcloud.talk.newarch.domain.repository.online
import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.conversations.RoomOverall
import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.models.json.participants.Participant
import com.nextcloud.talk.models.json.push.PushRegistrationOverall
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall
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 registerPushWithServerForUser(user: UserNgEntity, options: Map<String, String>): PushRegistrationOverall
suspend fun unregisterPushWithServerForUser(user: UserNgEntity): GenericOverall
suspend fun registerPushWithProxyForUser(user: UserNgEntity, options: Map<String, String>): Any

View File

@ -0,0 +1,39 @@
/*
*
* * 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.domain.usecases
import com.nextcloud.talk.models.json.participants.Participant
import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler
import com.nextcloud.talk.newarch.domain.repository.online.NextcloudTalkRepository
import com.nextcloud.talk.newarch.domain.usecases.base.UseCase
import org.koin.core.parameter.DefinitionParameters
class GetContactsUseCase constructor(
private val nextcloudTalkRepository: NextcloudTalkRepository,
apiErrorHandler: ApiErrorHandler?
) : 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])
}
}

View File

@ -42,6 +42,7 @@ abstract class UseCase<Type, in Params>(private val apiErrorHandler: ApiErrorHan
onResult.onSuccess(it)
}
} catch (e: Exception) {
onResult.onError(apiErrorHandler?.traceErrorException(e))
}
}

View File

@ -81,7 +81,7 @@ class ChatView : BaseView(), MessageHolders.ContentChecker<IMessage>, MessagesLi
setHasOptionsMenu(true)
actionBar?.show()
viewModel = viewModelProvider(factory).get(ChatViewModel::class.java)
viewModel.init(args.getParcelable(BundleKeys.KEY_USER_ENTITY)!!, args.getString(BundleKeys.KEY_ROOM_TOKEN)!!, args.getString(KEY_CONVERSATION_PASSWORD))
viewModel.init(args.getParcelable(BundleKeys.KEY_USER_ENTITY)!!, args.getString(BundleKeys.KEY_CONVERSATION_TOKEN)!!, args.getString(KEY_CONVERSATION_PASSWORD))
viewModel.apply {
conversation.observe(this@ChatView) { conversation ->
@ -344,7 +344,7 @@ class ChatView : BaseView(), MessageHolders.ContentChecker<IMessage>, MessagesLi
BundleKeys.KEY_BROWSER_TYPE, Parcels.wrap<BrowserController.BrowserType>(browserType)
)
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap<UserNgEntity>(viewModel.user))
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, it.token)
bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, it.token)
router.pushController(
RouterTransaction.with(BrowserController(bundle))
.pushChangeHandler(VerticalChangeHandler())

View File

@ -0,0 +1,72 @@
package com.nextcloud.talk.newarch.features.contactsflow
import android.content.Context
import android.view.ViewGroup
import androidx.core.view.isVisible
import coil.api.load
import com.nextcloud.talk.R
import com.nextcloud.talk.models.json.participants.Participant
import com.nextcloud.talk.newarch.local.models.getCredentials
import com.nextcloud.talk.newarch.services.GlobalService
import com.nextcloud.talk.newarch.utils.ElementPayload
import com.nextcloud.talk.newarch.utils.Images
import com.nextcloud.talk.utils.ApiUtils
import com.otaliastudios.elements.Element
import com.otaliastudios.elements.Page
import com.otaliastudios.elements.Presenter
import kotlinx.android.synthetic.main.rv_item_contact.view.*
import org.koin.core.KoinComponent
import org.koin.core.inject
open class ContactPresenter(context: Context, onElementClick: ((Page, Holder, Element<Participant>) -> Unit)?) : Presenter<Participant>(context, onElementClick), KoinComponent {
private val globalService: GlobalService by inject()
override val elementTypes: Collection<Int>
get() = listOf(0)
override fun onCreate(parent: ViewGroup, elementType: Int): Holder {
return Holder(getLayoutInflater().inflate(R.layout.rv_item_contact, parent, false))
}
override fun onBind(page: Page, holder: Holder, element: Element<Participant>, payloads: List<Any>) {
super.onBind(page, holder, element, payloads)
val participant = element.data
val user = globalService.currentUserLiveData.value
holder.itemView.checkedImageView.isVisible = element.data?.selected == true
if (!payloads.contains(ElementPayload.SELECTION_TOGGLE)) {
participant?.displayName?.let {
holder.itemView.name_text.text = it
} ?: run {
holder.itemView.name_text.text = context.getString(R.string.nc_guest)
}
when (participant?.source) {
"users" -> {
when (participant.type) {
Participant.ParticipantType.GUEST, Participant.ParticipantType.GUEST_AS_MODERATOR, Participant.ParticipantType.USER_FOLLOWING_LINK -> {
holder.itemView.avatarImageView.load(ApiUtils.getUrlForAvatarWithNameForGuests(user?.baseUrl, participant.userId, R.dimen.avatar_size)) {
user?.getCredentials()?.let { addHeader("Authorization", it) }
}
}
else -> {
holder.itemView.avatarImageView.load(ApiUtils.getUrlForAvatarWithName(user?.baseUrl, participant.userId, R.dimen.avatar_size)) {
user?.getCredentials()?.let { addHeader("Authorization", it) }
}
}
}
}
"groups", "circles" -> {
holder.itemView.avatarImageView.load(Images().getImageWithBackground(context, R.drawable.ic_people_group_white_24px))
}
"emails" -> {
holder.itemView.avatarImageView.load(Images().getImageWithBackground(context, R.drawable.ic_baseline_email_24))
}
else -> {
}
}
}
}
}

View File

@ -0,0 +1,6 @@
package com.nextcloud.talk.newarch.features.contactsflow
enum class ParticipantElementType {
PARTICIPANT,
PARTICIPANT_HEADER
}

View File

@ -1,9 +1,79 @@
package com.nextcloud.talk.newarch.features.contactsflow
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider
import com.nextcloud.talk.R
import com.nextcloud.talk.models.json.participants.Participant
import com.nextcloud.talk.newarch.conversationsList.mvp.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.uber.autodispose.lifecycle.LifecycleScopeProvider
import kotlinx.android.synthetic.main.conversations_list_view.view.*
import kotlinx.android.synthetic.main.message_state.view.*
import org.koin.android.ext.android.inject
class ContactsView : BaseView() {
class ContactsView(private val bundle: Bundle? = null) : BaseView() {
override val scopeProvider: LifecycleScopeProvider<*> = ControllerScopeProvider.from(this)
private lateinit var viewModel: ContactsViewModel
val factory: ContactsViewModelFactory by inject()
lateinit var adapter: Adapter
override fun getLayoutId(): Int {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
return R.layout.contacts_list_view
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup
): View {
actionBar?.show()
setHasOptionsMenu(true)
viewModel = viewModelProvider(factory).get(ContactsViewModel::class.java)
viewModel.conversationToken = bundle?.getString(BundleKeys.KEY_CONVERSATION_TOKEN)
val view = super.onCreateView(inflater, container)
// todo - change empty state magic
adapter = Adapter.builder(this)
.addSource(ContactsViewSource(viewModel.contactsLiveData, ParticipantElementType.PARTICIPANT.ordinal))
.addSource(ContactsHeaderSource(activity as Context, ParticipantElementType.PARTICIPANT_HEADER.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))
.addPresenter(Presenter.forErrorIndicator(activity as Context, R.layout.message_state) { view, throwable ->
view.messageStateTextView.setText(R.string.nc_oops)
view.messageStateImageView.setImageDrawable((activity as Context).getDrawable(R.drawable.ic_announcement_white_24dp))
})
.setAutoScrollMode(Adapter.AUTOSCROLL_POSITION_0, true)
.into(view.recyclerView)
view.apply {
recyclerView.initRecyclerView(LinearLayoutManager(activity), adapter, true)
}
viewModel.loadContacts()
return view
}
private fun onElementClick(page: Page, holder: Presenter.Holder, element: Element<Participant>) {
val isElementSelected = element.data?.selected == true
element.data?.selected = !isElementSelected
adapter.notifyItemChanged(holder.adapterPosition, ElementPayload.SELECTION_TOGGLE)
}
override fun getTitle(): String? {
return resources?.getString(R.string.nc_select_contacts)
}
}

View File

@ -0,0 +1,54 @@
package com.nextcloud.talk.newarch.features.contactsflow
import android.content.Context
import com.nextcloud.talk.R
import com.nextcloud.talk.models.json.participants.Participant
import com.otaliastudios.elements.Page
import com.otaliastudios.elements.Source
import com.otaliastudios.elements.extensions.HeaderSource
class ContactsHeaderSource(private val context: Context, private val elementType: Int): HeaderSource<Participant, String>() {
// Store the last header that was added, even if it belongs to a previous page.
private var lastHeader: String = ""
override fun dependsOn(source: Source<*>) = source is ContactsViewSource
override fun computeHeaders(page: Page, list: List<Participant>): List<Data<Participant, String>> {
val results = arrayListOf<Data<Participant, String>>()
for (participant in list) {
val header = when (participant.source) {
"users" -> {
context.getString(R.string.nc_contacts)
}
"groups" -> {
context.getString(R.string.nc_groups)
}
"emails" -> {
context.getString(R.string.nc_emails)
}
"circles" -> {
context.getString(R.string.nc_circles)
}
else -> {
context.getString(R.string.nc_others)
}
}
if (header != lastHeader) {
results.add(Data(participant, header))
lastHeader = header
}
}
return results
}
override fun getElementType(data: Data<Participant, String>): Int {
return elementType
}
override fun areItemsTheSame(first: Data<Participant, String>, second: Data<Participant, String>): Boolean {
return first == second
}
}

View File

@ -1,5 +1,41 @@
package com.nextcloud.talk.newarch.features.contactsflow
class ContactsViewModel {
import android.app.Application
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.nextcloud.talk.models.json.participants.Participant
import com.nextcloud.talk.newarch.conversationsList.mvp.BaseViewModel
import com.nextcloud.talk.newarch.data.model.ErrorModel
import com.nextcloud.talk.newarch.domain.usecases.GetContactsUseCase
import com.nextcloud.talk.newarch.domain.usecases.base.UseCaseResponse
import com.nextcloud.talk.newarch.features.conversationslist.ConversationsListView
import com.nextcloud.talk.newarch.services.GlobalService
import org.koin.core.parameter.parametersOf
class ContactsViewModel constructor(
application: Application,
private val getContactsUseCase: GetContactsUseCase,
val globalService: GlobalService
) : BaseViewModel<ConversationsListView>(application) {
val contactsLiveData = MutableLiveData<List<Participant>>()
val searchQuery = MutableLiveData<String?>(null)
var conversationToken: String? = null
fun loadContacts() {
getContactsUseCase.invoke(viewModelScope, parametersOf(globalService.currentUserLiveData.value, searchQuery.value, conversationToken), object :
UseCaseResponse<List<Participant>> {
override suspend fun onSuccess(result: List<Participant>) {
val sortPriority = mapOf("users" to 3, "groups" to 2, "emails" to 1, "circles" to 0)
contactsLiveData.postValue(result.sortedWith(Comparator { o1, o2 ->
sortPriority[o2.source]?.let { sortPriority[o1.source]?.compareTo(it) }
0
}))
}
override suspend fun onError(errorModel: ErrorModel?) {
// handle errors here
}
})
}
}

View File

@ -1,5 +1,20 @@
package com.nextcloud.talk.newarch.features.contactsflow
class ContactsViewModelFactory {
import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.nextcloud.talk.newarch.domain.usecases.GetContactsUseCase
import com.nextcloud.talk.newarch.services.GlobalService
class ContactsViewModelFactory constructor(
private val application: Application,
private val getContactsUseCase: GetContactsUseCase,
private val globalService: GlobalService
) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return ContactsViewModel(
application, getContactsUseCase, globalService
) as T
}
}

View File

@ -0,0 +1,54 @@
/*
*
* * 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
import androidx.lifecycle.LiveData
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.participants.Participant
import com.otaliastudios.elements.Element
import com.otaliastudios.elements.Page
import com.otaliastudios.elements.Source
import com.otaliastudios.elements.extensions.MainSource
class ContactsViewSource<T : Participant>(private val data: LiveData<List<T>>, private val elementType: Int = 0, loadingIndicatorsEnabled: Boolean = true, errorIndicatorEnabled: Boolean = true, emptyIndicatorEnabled: Boolean = true) : MainSource<T>(loadingIndicatorsEnabled, errorIndicatorEnabled, emptyIndicatorEnabled) {
override fun onPageOpened(page: Page, dependencies: List<Element<*>>) {
super.onPageOpened(page, dependencies)
if (page.previous() == null) {
postResult(page, data)
}
}
override fun dependsOn(source: Source<*>): Boolean {
return false
}
override fun areContentsTheSame(first: T, second: T): Boolean {
return first == second
}
override fun areItemsTheSame(first: T, second: T): Boolean {
return first.userId == second.userId
}
}

View File

@ -0,0 +1,26 @@
package com.nextcloud.talk.newarch.features.contactsflow.di.module
import android.app.Application
import com.nextcloud.talk.newarch.domain.usecases.GetContactsUseCase
import com.nextcloud.talk.newarch.features.contactsflow.ContactsViewModelFactory
import com.nextcloud.talk.newarch.services.GlobalService
import org.koin.android.ext.koin.androidApplication
import org.koin.dsl.module
val ContactsFlowModule = module {
factory {
createContactsViewModelFactory(
androidApplication(), get(), get()
)
}
}
fun createContactsViewModelFactory(
application: Application,
getContactsUseCase: GetContactsUseCase,
globalService: GlobalService
): ContactsViewModelFactory {
return ContactsViewModelFactory(
application, getContactsUseCase, globalService
)
}

View File

@ -45,7 +45,7 @@ import kotlinx.android.synthetic.main.rv_item_conversation_with_last_message.vie
import org.koin.core.KoinComponent
import org.koin.core.inject
open class ConversationsPresenter(context: Context, onElementClick: ((Page, Holder, Element<Conversation>) -> Unit)?, private val onElementLongClick: ((Page, Holder, Element<Conversation>) -> Unit)?) : Presenter<Conversation>(context, onElementClick), KoinComponent {
open class ConversationPresenter(context: Context, onElementClick: ((Page, Holder, Element<Conversation>) -> Unit)?, private val onElementLongClick: ((Page, Holder, Element<Conversation>) -> Unit)?) : Presenter<Conversation>(context, onElementClick), KoinComponent {
private val globalService: GlobalService by inject()
override val elementTypes: Collection<Int>
@ -159,4 +159,6 @@ open class ConversationsPresenter(context: Context, onElementClick: ((Page, Hold
}
}
}
}

View File

@ -27,6 +27,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.lifecycle.observe
import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.LayoutMode
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
@ -57,7 +58,6 @@ import com.otaliastudios.elements.Element
import com.otaliastudios.elements.Page
import com.otaliastudios.elements.Presenter
import com.uber.autodispose.lifecycle.LifecycleScopeProvider
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
import kotlinx.android.synthetic.main.conversations_list_view.view.*
import kotlinx.android.synthetic.main.message_state.view.*
import kotlinx.android.synthetic.main.search_layout.*
@ -82,7 +82,7 @@ class ConversationsListView : BaseView() {
val adapter = Adapter.builder(this)
.addSource(ConversationsListSource(viewModel.conversationsLiveData))
.addPresenter(ConversationsPresenter(activity as Context, ::onElementClick, ::onElementLongClick))
.addPresenter(ConversationPresenter(activity as Context, ::onElementClick, ::onElementLongClick))
.addPresenter(Presenter.forLoadingIndicator(activity as Context, R.layout.loading_state))
.addPresenter(AdvancedEmptyPresenter(activity as Context, R.layout.message_state, ::openNewConversationScreen))
.addPresenter(Presenter.forErrorIndicator(activity as Context, R.layout.message_state) { view, throwable ->
@ -94,7 +94,7 @@ class ConversationsListView : BaseView() {
view.apply {
recyclerView.initRecyclerView(SmoothScrollLinearLayoutManager(activity), adapter, false)
recyclerView.initRecyclerView(LinearLayoutManager(activity), adapter, true)
swipeRefreshLayoutView.setOnRefreshListener {
view.swipeRefreshLayoutView.isRefreshing = false
viewModel.loadConversations()
@ -156,7 +156,7 @@ class ConversationsListView : BaseView() {
conversation?.let { conversation ->
val bundle = Bundle()
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, user)
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, conversation.token)
bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, conversation.token)
bundle.putString(BundleKeys.KEY_ROOM_ID, conversation.conversationId)
bundle.putParcelable(BundleKeys.KEY_ACTIVE_CONVERSATION, Parcels.wrap(conversation))
ConductorRemapping.remapChatController(

View File

@ -98,7 +98,7 @@ class ShortcutService constructor(private var context: Context,
val intent = Intent(context, MainActivity::class.java)
intent.action = BundleKeys.KEY_OPEN_CONVERSATION
intent.putExtra(BundleKeys.KEY_INTERNAL_USER_ID, user.id)
intent.putExtra(BundleKeys.KEY_ROOM_TOKEN, conversation.token)
intent.putExtra(BundleKeys.KEY_CONVERSATION_TOKEN, conversation.token)
val persons = mutableListOf<Person>()
conversation.participants?.forEach {

View File

@ -0,0 +1,5 @@
package com.nextcloud.talk.newarch.utils
enum class ElementPayload {
SELECTION_TOGGLE
}

View File

@ -29,7 +29,9 @@ import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.models.RetrofitBucket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
@ -61,23 +63,41 @@ public class ApiUtils {
return url;
}
public static RetrofitBucket getRetrofitBucketForContactsSearch(String baseUrl,
@Nullable String searchQuery) {
RetrofitBucket retrofitBucket = new RetrofitBucket();
retrofitBucket.setUrl(baseUrl + ocsApiVersion + "/apps/files_sharing/api/v1/sharees");
public static String getUrlForContactsSearch(String baseUrl) {
return baseUrl + ocsApiVersion + "/core/autocomplete/get";
}
public static List<String> getShareTypesForContactsSearch() {
List<String> shareTypesList = new ArrayList<>();
// user
shareTypesList.add("0");
// group
shareTypesList.add("1");
// group
shareTypesList.add("4");
// remote/circles
shareTypesList.add("7");
return shareTypesList;
}
public static Map<String, String> getQueryMapForContactsSearch(@Nullable String searchQuery, @Nullable String conversationToken) {
Map<String, String> queryMap = new HashMap<>();
if (searchQuery == null) {
searchQuery = "";
if (searchQuery != null) {
queryMap.put("search", searchQuery);
} else {
queryMap.put("search", "");
}
queryMap.put("format", "json");
queryMap.put("search", searchQuery);
queryMap.put("itemType", "call");
retrofitBucket.setQueryMap(queryMap);
if (conversationToken != null) {
queryMap.put("itemId", conversationToken);
} else {
queryMap.put("itemId", "new");
}
return retrofitBucket;
return queryMap;
}
public static String getUrlForFilePreviewWithRemotePath(String baseUrl, String remotePath,
@ -96,13 +116,6 @@ public class ApiUtils {
return baseUrl + ocsApiVersion + "/apps/files_sharing/api/v1/shares";
}
public static RetrofitBucket getRetrofitBucketForContactsSearchFor14(String baseUrl,
@Nullable String searchQuery) {
RetrofitBucket retrofitBucket = getRetrofitBucketForContactsSearch(baseUrl, searchQuery);
retrofitBucket.setUrl(baseUrl + ocsApiVersion + "/core/autocomplete/get");
retrofitBucket.getQueryMap().put("itemId", "new");
return retrofitBucket;
}
public static String getUrlForSettingNotificationlevel(String baseUrl, String token) {
return getRoom(baseUrl, token) + "/notify";

View File

@ -163,7 +163,7 @@ object NotificationUtils {
if (conversationUser.id == notification.extras.getLong(
BundleKeys.KEY_INTERNAL_USER_ID
) && roomTokenOrId == statusBarNotification.notification.extras.getString(
BundleKeys.KEY_ROOM_TOKEN
BundleKeys.KEY_CONVERSATION_TOKEN
)
) {
return statusBarNotification
@ -196,7 +196,7 @@ object NotificationUtils {
if (conversationUser.id == notification.extras.getLong(
BundleKeys.KEY_INTERNAL_USER_ID
) && roomTokenOrId == statusBarNotification.notification.extras.getString(
BundleKeys.KEY_ROOM_TOKEN
BundleKeys.KEY_CONVERSATION_TOKEN
)
) {
notificationManager.cancel(statusBarNotification.id)

View File

@ -35,7 +35,7 @@ object BundleKeys {
val KEY_APP_ITEM_PACKAGE_NAME = "KEY_APP_ITEM_PACKAGE_NAME"
val KEY_APP_ITEM_NAME = "KEY_APP_ITEM_NAME"
val KEY_CONVERSATION_PASSWORD = "KEY_CONVERSATION_PASSWORD"
val KEY_ROOM_TOKEN = "KEY_ROOM_TOKEN"
val KEY_CONVERSATION_TOKEN = "KEY_CONVERSATION_TOKEN"
val KEY_USER_ENTITY = "KEY_USER_ENTITY"
val KEY_NEW_CONVERSATION = "KEY_NEW_CONVERSATION"
val KEY_ADD_PARTICIPANTS = "KEY_ADD_PARTICIPANTS"

View File

@ -35,7 +35,7 @@ import com.nextcloud.talk.newarch.local.models.UserNgEntity
import com.nextcloud.talk.utils.LoggingUtils.writeLogEntryToFile
import com.nextcloud.talk.utils.MagicMap
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_TOKEN
import okhttp3.OkHttpClient
import okhttp3.Request.Builder
import okhttp3.Response
@ -240,7 +240,7 @@ class MagicWebSocketInstance internal constructor(
if (shouldRefreshChat) {
val refreshChatHashMap =
HashMap<String, String?>()
refreshChatHashMap[KEY_ROOM_TOKEN] = messageHashMap["roomid"] as String?
refreshChatHashMap[KEY_CONVERSATION_TOKEN] = messageHashMap["roomid"] as String?
refreshChatHashMap[KEY_INTERNAL_USER_ID] =
java.lang.Long.toString(conversationUser.id!!)
eventBus.post(

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/rv_item_contact" />
</RelativeLayout>

View File

@ -28,15 +28,15 @@
android:layout_margin="@dimen/margin_between_elements"
android:orientation="vertical">
<ImageView
android:id="@+id/checkedImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/avatarImageView"
android:layout_width="@dimen/small_item_height"
android:layout_height="@dimen/small_item_height"
android:layout_centerVertical="true"
android:src="@drawable/ic_check_black_24dp"
android:tint="@color/colorPrimary"
android:visibility="gone" />
android:layout_marginStart="@dimen/double_margin_between_elements"
android:layout_marginEnd="@dimen/margin_between_elements"
app:shapeAppearanceOverlay="@style/circleImageView"
tools:srcCompat="@tools:sample/avatars"/>
<androidx.emoji.widget.EmojiTextView
android:id="@+id/name_text"
@ -48,13 +48,14 @@
android:ellipsize="end"
tools:text="Contact item text" />
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/avatarImageView"
app:shapeAppearanceOverlay="@style/circleImageView"
android:layout_width="@dimen/small_item_height"
android:layout_height="@dimen/small_item_height"
<ImageView
android:id="@+id/checkedImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginStart="@dimen/double_margin_between_elements"
android:layout_marginEnd="@dimen/margin_between_elements" />
android:src="@drawable/ic_check_black_24dp"
android:tint="@color/colorPrimary"
android:visibility="gone" />
</RelativeLayout>

View File

@ -180,7 +180,7 @@
conversations list</string>
<!-- Contacts -->
<string name="nc_select_contacts">Select contacts</string>
<string name="nc_select_contacts">Find participants</string>
<string name="nc_contacts_done">Done</string>
<!-- Permissions -->
@ -289,6 +289,7 @@
<string name="nc_circles">Circles</string>
<string name="nc_emails">Emails</string>
<string name="nc_participants">Participants</string>
<string name="nc_others">Others</string>
<string name="nc_owner">Owner</string>
<string name="nc_moderator">Moderator</string>