mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-21 20:49:36 +01:00
Lots of cleanups & work on contacts
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
7efb05184c
commit
4901534da7
@ -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())
|
||||
)
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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])
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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 -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.nextcloud.talk.newarch.features.contactsflow
|
||||
|
||||
enum class ParticipantElementType {
|
||||
PARTICIPANT,
|
||||
PARTICIPANT_HEADER
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
)
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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(
|
||||
|
@ -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 {
|
||||
|
@ -0,0 +1,5 @@
|
||||
package com.nextcloud.talk.newarch.utils
|
||||
|
||||
enum class ElementPayload {
|
||||
SELECTION_TOGGLE
|
||||
}
|
@ -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";
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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(
|
||||
|
13
app/src/main/res/layout/contacts_list_view.xml
Normal file
13
app/src/main/res/layout/contacts_list_view.xml
Normal 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>
|
@ -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>
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user