mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-21 12:39:58 +01:00
Merge pull request #4786 from nextcloud/removeOldContactsActivity
remove old ContactsActivity
This commit is contained in:
commit
0cde5aae3a
@ -126,7 +126,7 @@
|
|||||||
android:name=".account.WebViewLoginActivity"
|
android:name=".account.WebViewLoginActivity"
|
||||||
android:theme="@style/AppTheme" />
|
android:theme="@style/AppTheme" />
|
||||||
|
|
||||||
<activity android:name=".contacts.ContactsActivityCompose"
|
<activity android:name=".contacts.ContactsActivity"
|
||||||
android:theme="@style/AppTheme"/>
|
android:theme="@style/AppTheme"/>
|
||||||
|
|
||||||
<activity android:name=".conversationcreation.ConversationCreationActivity"
|
<activity android:name=".conversationcreation.ConversationCreationActivity"
|
||||||
@ -246,10 +246,6 @@
|
|||||||
android:name=".conversationinfoedit.ConversationInfoEditActivity"
|
android:name=".conversationinfoedit.ConversationInfoEditActivity"
|
||||||
android:theme="@style/AppTheme" />
|
android:theme="@style/AppTheme" />
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name=".contacts.ContactsActivity"
|
|
||||||
android:theme="@style/AppTheme" />
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".openconversations.ListOpenConversationsActivity"
|
android:name=".openconversations.ListOpenConversationsActivity"
|
||||||
android:theme="@style/AppTheme" />
|
android:theme="@style/AppTheme" />
|
||||||
|
@ -1,900 +1,83 @@
|
|||||||
/*
|
/*
|
||||||
* Nextcloud Talk - Android Client
|
* Nextcloud Talk - Android Client
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2022 Andy Scherzinger <info@andy-scherzinger.de>
|
* SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
|
||||||
* SPDX-FileCopyrightText: 2022 Marcel Hibbe <dev@mhibbe.de>
|
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
|
||||||
* SPDX-FileCopyrightText: 2017 Mario Danic <mario@lovelyhq.com>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.nextcloud.talk.contacts
|
package com.nextcloud.talk.contacts
|
||||||
|
|
||||||
import android.app.SearchManager
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.graphics.PorterDuff
|
|
||||||
import android.graphics.drawable.ColorDrawable
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.InputType
|
import androidx.activity.compose.setContent
|
||||||
import android.util.Log
|
import androidx.compose.material3.MaterialTheme
|
||||||
import android.view.Menu
|
import androidx.compose.runtime.remember
|
||||||
import android.view.MenuItem
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import android.view.View
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import android.view.inputmethod.EditorInfo
|
|
||||||
import androidx.appcompat.widget.SearchView
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
|
||||||
import androidx.core.view.MenuItemCompat
|
|
||||||
import androidx.work.Data
|
|
||||||
import androidx.work.OneTimeWorkRequest
|
|
||||||
import androidx.work.WorkInfo
|
|
||||||
import androidx.work.WorkManager
|
|
||||||
import autodagger.AutoInjector
|
import autodagger.AutoInjector
|
||||||
import com.bluelinelabs.logansquare.LoganSquare
|
|
||||||
import com.nextcloud.talk.R
|
|
||||||
import com.nextcloud.talk.activities.BaseActivity
|
import com.nextcloud.talk.activities.BaseActivity
|
||||||
import com.nextcloud.talk.adapters.items.ContactItem
|
|
||||||
import com.nextcloud.talk.adapters.items.GenericTextHeaderItem
|
|
||||||
import com.nextcloud.talk.api.NcApi
|
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||||
import com.nextcloud.talk.chat.ChatActivity
|
import com.nextcloud.talk.contacts.CompanionClass.Companion.KEY_HIDE_ALREADY_EXISTING_PARTICIPANTS
|
||||||
import com.nextcloud.talk.conversation.CreateConversationDialogFragment
|
import com.nextcloud.talk.extensions.getParcelableArrayListExtraProvider
|
||||||
import com.nextcloud.talk.data.user.model.User
|
import com.nextcloud.talk.components.SetupSystemBars
|
||||||
import com.nextcloud.talk.databinding.ActivityContactsBinding
|
|
||||||
import com.nextcloud.talk.events.EventStatus
|
|
||||||
import com.nextcloud.talk.events.OpenConversationEvent
|
|
||||||
import com.nextcloud.talk.jobs.AddParticipantsToConversation
|
|
||||||
import com.nextcloud.talk.models.RetrofitBucket
|
|
||||||
import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
|
|
||||||
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
|
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
|
||||||
import com.nextcloud.talk.models.json.conversations.ConversationEnums
|
|
||||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
|
||||||
import com.nextcloud.talk.models.json.converters.EnumActorTypeConverter
|
|
||||||
import com.nextcloud.talk.models.json.participants.Participant
|
|
||||||
import com.nextcloud.talk.openconversations.ListOpenConversationsActivity
|
|
||||||
import com.nextcloud.talk.users.UserManager
|
|
||||||
import com.nextcloud.talk.utils.ApiUtils
|
|
||||||
import com.nextcloud.talk.utils.CapabilitiesUtil
|
|
||||||
import com.nextcloud.talk.utils.SpreedFeatures
|
|
||||||
import com.nextcloud.talk.utils.UserIdUtils.getIdForUser
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys
|
import com.nextcloud.talk.utils.bundle.BundleKeys
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
|
||||||
import eu.davidea.flexibleadapter.SelectableAdapter
|
|
||||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
|
||||||
import io.reactivex.Observer
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
|
||||||
import io.reactivex.disposables.Disposable
|
|
||||||
import io.reactivex.schedulers.Schedulers
|
|
||||||
import okhttp3.ResponseBody
|
|
||||||
import org.greenrobot.eventbus.Subscribe
|
|
||||||
import org.greenrobot.eventbus.ThreadMode
|
|
||||||
import org.parceler.Parcels
|
|
||||||
import java.io.IOException
|
|
||||||
import java.util.Locale
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication::class)
|
@AutoInjector(NextcloudTalkApplication::class)
|
||||||
class ContactsActivity :
|
class ContactsActivity : BaseActivity() {
|
||||||
BaseActivity(),
|
|
||||||
SearchView.OnQueryTextListener,
|
|
||||||
FlexibleAdapter.OnItemClickListener {
|
|
||||||
private lateinit var binding: ActivityContactsBinding
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var userManager: UserManager
|
lateinit var viewModelFactory: ViewModelProvider.Factory
|
||||||
|
private lateinit var contactsViewModel: ContactsViewModel
|
||||||
@Inject
|
|
||||||
lateinit var ncApi: NcApi
|
|
||||||
|
|
||||||
private var credentials: String? = null
|
|
||||||
private var currentUser: User? = null
|
|
||||||
private var contactsQueryDisposable: Disposable? = null
|
|
||||||
private var cacheQueryDisposable: Disposable? = null
|
|
||||||
private var adapter: FlexibleAdapter<*>? = null
|
|
||||||
private var contactItems: MutableList<AbstractFlexibleItem<*>>? = null
|
|
||||||
private var layoutManager: SmoothScrollLinearLayoutManager? = null
|
|
||||||
private var searchItem: MenuItem? = null
|
|
||||||
private var searchView: SearchView? = null
|
|
||||||
private var isNewConversationView = false
|
|
||||||
private var isPublicCall = false
|
|
||||||
private var userHeaderItems: HashMap<String, GenericTextHeaderItem> = HashMap<String, GenericTextHeaderItem>()
|
|
||||||
private var alreadyFetching = false
|
|
||||||
private var doneMenuItem: MenuItem? = null
|
|
||||||
private var selectedUserIds: MutableSet<String> = HashSet()
|
|
||||||
private var selectedGroupIds: MutableSet<String> = HashSet()
|
|
||||||
private var selectedCircleIds: MutableSet<String> = HashSet()
|
|
||||||
private var selectedEmails: MutableSet<String> = HashSet()
|
|
||||||
private var existingParticipants: List<String>? = null
|
|
||||||
private var isAddingParticipantsView = false
|
|
||||||
private var conversationToken: String? = null
|
|
||||||
|
|
||||||
|
@SuppressLint("UnrememberedMutableState")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||||
|
contactsViewModel = ViewModelProvider(this, viewModelFactory)[ContactsViewModel::class.java]
|
||||||
binding = ActivityContactsBinding.inflate(layoutInflater)
|
setContent {
|
||||||
setupActionBar()
|
val isAddParticipants = intent.getBooleanExtra(BundleKeys.KEY_ADD_PARTICIPANTS, false)
|
||||||
setContentView(binding.root)
|
val hideAlreadyAddedParticipants = intent.getBooleanExtra(KEY_HIDE_ALREADY_EXISTING_PARTICIPANTS, false)
|
||||||
setupSystemColors()
|
contactsViewModel.updateIsAddParticipants(isAddParticipants)
|
||||||
|
contactsViewModel.hideAlreadyAddedParticipants(hideAlreadyAddedParticipants)
|
||||||
if (savedInstanceState != null) {
|
if (isAddParticipants) {
|
||||||
if (adapter != null) {
|
contactsViewModel.updateShareTypes(
|
||||||
adapter?.onRestoreInstanceState(savedInstanceState)
|
listOf(
|
||||||
}
|
ShareType.Group.shareType,
|
||||||
}
|
ShareType.Email.shareType,
|
||||||
|
ShareType.Circle.shareType
|
||||||
existingParticipants = ArrayList()
|
|
||||||
if (intent.hasExtra(BundleKeys.KEY_NEW_CONVERSATION)) {
|
|
||||||
// adding a new conversation, setting a flag.
|
|
||||||
isNewConversationView = true
|
|
||||||
} else if (intent.hasExtra(BundleKeys.KEY_ADD_PARTICIPANTS)) {
|
|
||||||
// adding the participants in the conversation also opens this activity, setting a flag for it.
|
|
||||||
isAddingParticipantsView = true
|
|
||||||
conversationToken = intent.getStringExtra(BundleKeys.KEY_TOKEN)
|
|
||||||
if (intent.hasExtra(BundleKeys.KEY_EXISTING_PARTICIPANTS)) {
|
|
||||||
existingParticipants = intent.getStringArrayListExtra(BundleKeys.KEY_EXISTING_PARTICIPANTS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
selectedUserIds = HashSet()
|
|
||||||
selectedGroupIds = HashSet()
|
|
||||||
selectedEmails = HashSet()
|
|
||||||
selectedCircleIds = HashSet()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
|
|
||||||
if (isNewConversationView) {
|
|
||||||
toggleConversationPrivacyLayout(!isPublicCall)
|
|
||||||
}
|
|
||||||
if (isAddingParticipantsView) {
|
|
||||||
binding.callHeaderLayout.visibility = View.GONE
|
|
||||||
binding.listOpenConversations.visibility = View.GONE
|
|
||||||
} else {
|
|
||||||
binding.listOpenConversations.setOnClickListener {
|
|
||||||
listOpenConversations()
|
|
||||||
}
|
|
||||||
binding.callHeaderLayout.setOnClickListener {
|
|
||||||
toggleCallHeader()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentUser = currentUserProvider.currentUser.blockingGet()
|
|
||||||
if (currentUser != null) {
|
|
||||||
credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token)
|
|
||||||
}
|
|
||||||
if (adapter == null) {
|
|
||||||
contactItems = ArrayList<AbstractFlexibleItem<*>>()
|
|
||||||
adapter = FlexibleAdapter(contactItems, this, false)
|
|
||||||
if (currentUser != null) {
|
|
||||||
fetchData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setupAdapter()
|
|
||||||
prepareViews()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupActionBar() {
|
|
||||||
setSupportActionBar(binding.contactsToolbar)
|
|
||||||
binding.contactsToolbar.setNavigationOnClickListener {
|
|
||||||
onBackPressedDispatcher.onBackPressed()
|
|
||||||
}
|
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
|
||||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
|
||||||
supportActionBar?.setIcon(ColorDrawable(resources!!.getColor(android.R.color.transparent, null)))
|
|
||||||
supportActionBar?.title = when {
|
|
||||||
isAddingParticipantsView -> {
|
|
||||||
resources!!.getString(R.string.nc_add_participants)
|
|
||||||
}
|
|
||||||
|
|
||||||
isNewConversationView -> {
|
|
||||||
resources!!.getString(R.string.nc_select_participants)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
resources!!.getString(R.string.nc_app_product_name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
viewThemeUtils.material.themeToolbar(binding.contactsToolbar)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSaveInstanceState(bundle: Bundle) {
|
|
||||||
super.onSaveInstanceState(bundle)
|
|
||||||
adapter?.onSaveInstanceState(bundle)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
|
||||||
super.onCreateOptionsMenu(menu)
|
|
||||||
menuInflater.inflate(R.menu.menu_contacts, menu)
|
|
||||||
searchItem = menu.findItem(R.id.action_search)
|
|
||||||
doneMenuItem = menu.findItem(R.id.contacts_selection_done)
|
|
||||||
initSearchView()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
|
||||||
super.onPrepareOptionsMenu(menu)
|
|
||||||
if (searchItem != null) {
|
|
||||||
binding.titleTextView.let {
|
|
||||||
viewThemeUtils.platform.colorToolbarMenuIcon(
|
|
||||||
it.context,
|
|
||||||
searchItem!!
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkAndHandleDoneMenuItem()
|
|
||||||
if (adapter?.hasFilter() == true) {
|
|
||||||
searchItem!!.expandActionView()
|
|
||||||
searchView!!.setQuery(adapter!!.getFilter(String::class.java) as CharSequence, false)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
|
||||||
return when (item.itemId) {
|
|
||||||
R.id.home -> {
|
|
||||||
finish()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.contacts_selection_done -> {
|
|
||||||
selectionDone()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
super.onOptionsItemSelected(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupAdapter() {
|
|
||||||
adapter?.setNotifyChangeOfUnfilteredItems(true)?.mode = SelectableAdapter.Mode.MULTI
|
|
||||||
adapter?.setStickyHeaderElevation(HEADER_ELEVATION)
|
|
||||||
?.setUnlinkAllItemsOnRemoveHeaders(true)
|
|
||||||
?.setDisplayHeadersAtStartUp(true)
|
|
||||||
?.setStickyHeaders(true)
|
|
||||||
adapter?.addListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun selectionDone() {
|
|
||||||
if (isAddingParticipantsView) {
|
|
||||||
// add participants in the view
|
|
||||||
addParticipantsToConversation()
|
|
||||||
} else {
|
|
||||||
// if there is only 1 participant, directly add him while creating room (which can only add 'one')
|
|
||||||
if (!isPublicCall && selectedCircleIds.size + selectedGroupIds.size + selectedUserIds.size == 1) {
|
|
||||||
val userId: String
|
|
||||||
var sourceType: String? = null
|
|
||||||
var roomType = "1"
|
|
||||||
when {
|
|
||||||
selectedGroupIds.size == 1 -> {
|
|
||||||
roomType = "2"
|
|
||||||
userId = selectedGroupIds.iterator().next()
|
|
||||||
}
|
|
||||||
|
|
||||||
selectedCircleIds.size == 1 -> {
|
|
||||||
roomType = "2"
|
|
||||||
sourceType = "circles"
|
|
||||||
userId = selectedCircleIds.iterator().next()
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
userId = selectedUserIds.iterator().next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
createRoom(roomType, sourceType, userId)
|
|
||||||
|
|
||||||
// if there are more participants to add, ask for roomName and add them one after another
|
|
||||||
} else {
|
|
||||||
val roomType: ConversationEnums.ConversationType = if (isPublicCall) {
|
|
||||||
ConversationEnums.ConversationType.ROOM_PUBLIC_CALL
|
|
||||||
} else {
|
|
||||||
ConversationEnums.ConversationType.ROOM_GROUP_CALL
|
|
||||||
}
|
|
||||||
val userIdsArray = ArrayList(selectedUserIds)
|
|
||||||
val groupIdsArray = ArrayList(selectedGroupIds)
|
|
||||||
val emailsArray = ArrayList(selectedEmails)
|
|
||||||
val circleIdsArray = ArrayList(selectedCircleIds)
|
|
||||||
|
|
||||||
val createConversationDialog = CreateConversationDialogFragment.newInstance(
|
|
||||||
userIdsArray,
|
|
||||||
groupIdsArray,
|
|
||||||
emailsArray,
|
|
||||||
circleIdsArray,
|
|
||||||
Parcels.wrap(roomType)
|
|
||||||
)
|
|
||||||
createConversationDialog.show(
|
|
||||||
supportFragmentManager,
|
|
||||||
TAG
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createRoom(roomType: String, sourceType: String?, userId: String) {
|
|
||||||
val apiVersion: Int = ApiUtils.getConversationApiVersion(currentUser!!, intArrayOf(ApiUtils.API_V4, 1))
|
|
||||||
val retrofitBucket: RetrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(
|
|
||||||
apiVersion,
|
|
||||||
currentUser!!.baseUrl!!,
|
|
||||||
roomType,
|
|
||||||
sourceType,
|
|
||||||
userId,
|
|
||||||
null
|
|
||||||
)
|
|
||||||
ncApi.createRoom(
|
|
||||||
credentials,
|
|
||||||
retrofitBucket.url,
|
|
||||||
retrofitBucket.queryMap
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(object : Observer<RoomOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(roomOverall: RoomOverall) {
|
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomOverall.ocs!!.data!!.token)
|
|
||||||
// bundle.putString(BundleKeys.KEY_ROOM_ID, roomOverall.ocs!!.data!!.roomId)
|
|
||||||
|
|
||||||
val chatIntent = Intent(context, ChatActivity::class.java)
|
|
||||||
chatIntent.putExtras(bundle)
|
|
||||||
chatIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
||||||
startActivity(chatIntent)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addParticipantsToConversation() {
|
|
||||||
val userIdsArray: Array<String> = selectedUserIds.toTypedArray()
|
|
||||||
val groupIdsArray: Array<String> = selectedGroupIds.toTypedArray()
|
|
||||||
val emailsArray: Array<String> = selectedEmails.toTypedArray()
|
|
||||||
val circleIdsArray: Array<String> = selectedCircleIds.toTypedArray()
|
|
||||||
val data = Data.Builder()
|
|
||||||
data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, currentUser!!.id!!)
|
|
||||||
data.putString(BundleKeys.KEY_TOKEN, conversationToken)
|
|
||||||
data.putStringArray(BundleKeys.KEY_SELECTED_USERS, userIdsArray)
|
|
||||||
data.putStringArray(BundleKeys.KEY_SELECTED_GROUPS, groupIdsArray)
|
|
||||||
data.putStringArray(BundleKeys.KEY_SELECTED_EMAILS, emailsArray)
|
|
||||||
data.putStringArray(BundleKeys.KEY_SELECTED_CIRCLES, circleIdsArray)
|
|
||||||
val addParticipantsToConversationWorker: OneTimeWorkRequest = OneTimeWorkRequest.Builder(
|
|
||||||
AddParticipantsToConversation::class.java
|
|
||||||
).setInputData(data.build()).build()
|
|
||||||
WorkManager.getInstance().enqueue(addParticipantsToConversationWorker)
|
|
||||||
|
|
||||||
WorkManager.getInstance(context).getWorkInfoByIdLiveData(addParticipantsToConversationWorker.id)
|
|
||||||
.observeForever { workInfo: WorkInfo? ->
|
|
||||||
if (workInfo != null) {
|
|
||||||
when (workInfo.state) {
|
|
||||||
WorkInfo.State.RUNNING -> {
|
|
||||||
Log.d(TAG, "running AddParticipantsToConversation")
|
|
||||||
}
|
|
||||||
|
|
||||||
WorkInfo.State.SUCCEEDED -> {
|
|
||||||
Log.d(TAG, "success AddParticipantsToConversation")
|
|
||||||
|
|
||||||
eventBus.post(
|
|
||||||
EventStatus(
|
|
||||||
getIdForUser(currentUser),
|
|
||||||
EventStatus.EventType.PARTICIPANTS_UPDATE,
|
|
||||||
true
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
contactsViewModel.getContactsFromSearchParams()
|
||||||
|
}
|
||||||
|
val colorScheme = viewThemeUtils.getColorScheme(this)
|
||||||
|
val uiState = contactsViewModel.contactsViewState.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
finish()
|
val selectedParticipants = remember {
|
||||||
}
|
intent?.getParcelableArrayListExtraProvider<AutocompleteUser>("selectedParticipants")
|
||||||
|
?: emptyList()
|
||||||
|
}.toSet().toMutableList()
|
||||||
|
contactsViewModel.updateSelectedParticipants(selectedParticipants)
|
||||||
|
|
||||||
WorkInfo.State.FAILED -> {
|
MaterialTheme(
|
||||||
Log.d(TAG, "failed AddParticipantsToConversation")
|
colorScheme = colorScheme
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initSearchView() {
|
|
||||||
val searchManager: SearchManager? = getSystemService(Context.SEARCH_SERVICE) as SearchManager?
|
|
||||||
if (searchItem != null) {
|
|
||||||
searchView = MenuItemCompat.getActionView(searchItem) as SearchView
|
|
||||||
viewThemeUtils.talk.themeSearchView(searchView!!)
|
|
||||||
searchView!!.maxWidth = Int.MAX_VALUE
|
|
||||||
searchView!!.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
|
|
||||||
var imeOptions: Int = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
|
|
||||||
if (appPreferences.isKeyboardIncognito == true) {
|
|
||||||
imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
|
|
||||||
}
|
|
||||||
searchView!!.imeOptions = imeOptions
|
|
||||||
searchView!!.queryHint = resources!!.getString(R.string.nc_search)
|
|
||||||
if (searchManager != null) {
|
|
||||||
searchView!!.setSearchableInfo(searchManager.getSearchableInfo(componentName))
|
|
||||||
}
|
|
||||||
searchView!!.setOnQueryTextListener(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fetchData() {
|
|
||||||
dispose(null)
|
|
||||||
alreadyFetching = true
|
|
||||||
userHeaderItems = HashMap()
|
|
||||||
val query = adapter!!.getFilter(String::class.java)
|
|
||||||
val retrofitBucket: RetrofitBucket =
|
|
||||||
ApiUtils.getRetrofitBucketForContactsSearchFor14(currentUser!!.baseUrl!!, query)
|
|
||||||
val modifiedQueryMap: HashMap<String, Any?> = HashMap(retrofitBucket.queryMap)
|
|
||||||
modifiedQueryMap["limit"] = CONTACTS_BATCH_SIZE
|
|
||||||
if (isAddingParticipantsView) {
|
|
||||||
modifiedQueryMap["itemId"] = conversationToken
|
|
||||||
}
|
|
||||||
val shareTypesList: ArrayList<String> = ArrayList()
|
|
||||||
// users
|
|
||||||
shareTypesList.add("0")
|
|
||||||
if (!isAddingParticipantsView) {
|
|
||||||
// groups
|
|
||||||
shareTypesList.add("1")
|
|
||||||
} else if (CapabilitiesUtil.hasSpreedFeatureCapability(
|
|
||||||
currentUser?.capabilities?.spreedCapability!!,
|
|
||||||
SpreedFeatures.INVITE_GROUPS_AND_MAILS
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
// groups
|
ContactsScreen(
|
||||||
shareTypesList.add("1")
|
contactsViewModel = contactsViewModel,
|
||||||
// emails
|
uiState = uiState.value
|
||||||
shareTypesList.add("4")
|
|
||||||
}
|
|
||||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(
|
|
||||||
currentUser?.capabilities?.spreedCapability!!,
|
|
||||||
SpreedFeatures.CIRCLES_SUPPORT
|
|
||||||
)
|
)
|
||||||
) {
|
SetupSystemBars()
|
||||||
// circles
|
|
||||||
shareTypesList.add("7")
|
|
||||||
}
|
}
|
||||||
modifiedQueryMap["shareTypes[]"] = shareTypesList
|
|
||||||
ncApi.getContactsWithSearchParam(
|
|
||||||
credentials,
|
|
||||||
retrofitBucket.url,
|
|
||||||
shareTypesList,
|
|
||||||
modifiedQueryMap
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.retry(RETRIES)
|
|
||||||
.subscribe(object : Observer<ResponseBody> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
contactsQueryDisposable = d
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
override fun onNext(responseBody: ResponseBody) {
|
}
|
||||||
// getting contacts
|
|
||||||
val newUserItemList = processAutocompleteUserList(responseBody)
|
class CompanionClass {
|
||||||
|
companion object {
|
||||||
userHeaderItems = HashMap()
|
internal val TAG = ContactsActivity::class.simpleName
|
||||||
// getting the contact list from the endpoints.
|
internal const val ROOM_TYPE_ONE_ONE = "1"
|
||||||
contactItems!!.addAll(newUserItemList)
|
const val KEY_HIDE_ALREADY_EXISTING_PARTICIPANTS: String = "KEY_HIDE_ALREADY_EXISTING_PARTICIPANTS"
|
||||||
|
|
||||||
sortUserItems(newUserItemList)
|
|
||||||
|
|
||||||
if (newUserItemList.size > 0) {
|
|
||||||
adapter?.updateDataSet(newUserItemList as List<Nothing>?)
|
|
||||||
} else {
|
|
||||||
adapter?.filterItems()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
dispose(contactsQueryDisposable)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
dispose(contactsQueryDisposable)
|
|
||||||
alreadyFetching = false
|
|
||||||
disengageProgressBar()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processAutocompleteUserList(responseBody: ResponseBody): MutableList<AbstractFlexibleItem<*>> {
|
|
||||||
try {
|
|
||||||
val autocompleteOverall: AutocompleteOverall = LoganSquare.parse(
|
|
||||||
responseBody.string(),
|
|
||||||
AutocompleteOverall::class.java
|
|
||||||
)
|
|
||||||
val autocompleteUsersList: ArrayList<AutocompleteUser> = ArrayList()
|
|
||||||
autocompleteUsersList.addAll(autocompleteOverall.ocs!!.data!!)
|
|
||||||
return processAutocompleteUserList(autocompleteUsersList)
|
|
||||||
} catch (ioe: IOException) {
|
|
||||||
Log.e(TAG, "Parsing response body failed while getting contacts", ioe)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ArrayList()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processAutocompleteUserList(
|
|
||||||
autocompleteUsersList: ArrayList<AutocompleteUser>
|
|
||||||
): MutableList<AbstractFlexibleItem<*>> {
|
|
||||||
var participant: Participant
|
|
||||||
val actorTypeConverter = EnumActorTypeConverter()
|
|
||||||
val newUserItemList: MutableList<AbstractFlexibleItem<*>> = ArrayList()
|
|
||||||
for (autocompleteUser in autocompleteUsersList) {
|
|
||||||
if (autocompleteUser.id != null &&
|
|
||||||
autocompleteUser.id != currentUser!!.userId &&
|
|
||||||
!existingParticipants!!.contains(autocompleteUser.id)
|
|
||||||
) {
|
|
||||||
participant = createParticipant(autocompleteUser, actorTypeConverter)
|
|
||||||
val headerTitle = getHeaderTitle(participant)
|
|
||||||
var genericTextHeaderItem: GenericTextHeaderItem
|
|
||||||
if (!userHeaderItems.containsKey(headerTitle)) {
|
|
||||||
genericTextHeaderItem = GenericTextHeaderItem(headerTitle, viewThemeUtils)
|
|
||||||
userHeaderItems.put(headerTitle, genericTextHeaderItem)
|
|
||||||
}
|
|
||||||
val newContactItem = ContactItem(
|
|
||||||
participant,
|
|
||||||
currentUser!!,
|
|
||||||
userHeaderItems[headerTitle],
|
|
||||||
viewThemeUtils
|
|
||||||
)
|
|
||||||
if (!contactItems!!.contains(newContactItem)) {
|
|
||||||
newUserItemList.add(newContactItem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newUserItemList
|
|
||||||
}
|
|
||||||
|
|
||||||
// this function displays the title of the contacts activity
|
|
||||||
private fun getHeaderTitle(participant: Participant): String {
|
|
||||||
return when {
|
|
||||||
participant.calculatedActorType == Participant.ActorType.GROUPS -> {
|
|
||||||
resources!!.getString(R.string.nc_groups)
|
|
||||||
}
|
|
||||||
|
|
||||||
participant.calculatedActorType == Participant.ActorType.CIRCLES -> {
|
|
||||||
resources!!.getString(R.string.nc_teams)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
participant.displayName!!.substring(0, 1).uppercase(Locale.getDefault())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createParticipant(
|
|
||||||
autocompleteUser: AutocompleteUser,
|
|
||||||
actorTypeConverter: EnumActorTypeConverter
|
|
||||||
): Participant {
|
|
||||||
val participant = Participant()
|
|
||||||
participant.actorId = autocompleteUser.id
|
|
||||||
participant.actorType = actorTypeConverter.getFromString(autocompleteUser.source)
|
|
||||||
participant.displayName = autocompleteUser.label
|
|
||||||
|
|
||||||
return participant
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("LongMethod")
|
|
||||||
private fun sortUserItems(newUserItemList: MutableList<AbstractFlexibleItem<*>>) {
|
|
||||||
newUserItemList.sortWith sort@{ o1: AbstractFlexibleItem<*>, o2: AbstractFlexibleItem<*> ->
|
|
||||||
val firstName: String = if (o1 is ContactItem) {
|
|
||||||
o1.model.displayName!!
|
|
||||||
} else {
|
|
||||||
(o1 as GenericTextHeaderItem).model
|
|
||||||
}
|
|
||||||
val secondName: String = if (o2 is ContactItem) {
|
|
||||||
o2.model.displayName!!
|
|
||||||
} else {
|
|
||||||
(o2 as GenericTextHeaderItem).model
|
|
||||||
}
|
|
||||||
if (o1 is ContactItem && o2 is ContactItem) {
|
|
||||||
val firstSource: Participant.ActorType = o1.model.actorType!!
|
|
||||||
val secondSource: Participant.ActorType = o2.model.actorType!!
|
|
||||||
if (firstSource == secondSource) {
|
|
||||||
return@sort firstName.compareTo(secondName, ignoreCase = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// First users
|
|
||||||
if (Participant.ActorType.USERS == firstSource) {
|
|
||||||
return@sort -1
|
|
||||||
} else if (Participant.ActorType.USERS == secondSource) {
|
|
||||||
return@sort 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then groups
|
|
||||||
if (Participant.ActorType.GROUPS == firstSource) {
|
|
||||||
return@sort -1
|
|
||||||
} else if (Participant.ActorType.GROUPS == secondSource) {
|
|
||||||
return@sort 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then circles
|
|
||||||
if (Participant.ActorType.CIRCLES == firstSource) {
|
|
||||||
return@sort -1
|
|
||||||
} else if (Participant.ActorType.CIRCLES == secondSource) {
|
|
||||||
return@sort 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise fall back to name sorting
|
|
||||||
return@sort firstName.compareTo(secondName, ignoreCase = true)
|
|
||||||
}
|
|
||||||
firstName.compareTo(secondName, ignoreCase = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
contactItems?.sortWith sort@{ o1: AbstractFlexibleItem<*>, o2: AbstractFlexibleItem<*> ->
|
|
||||||
val firstName: String = if (o1 is ContactItem) {
|
|
||||||
o1.model.displayName!!
|
|
||||||
} else {
|
|
||||||
(o1 as GenericTextHeaderItem).model
|
|
||||||
}
|
|
||||||
val secondName: String = if (o2 is ContactItem) {
|
|
||||||
o2.model.displayName!!
|
|
||||||
} else {
|
|
||||||
(o2 as GenericTextHeaderItem).model
|
|
||||||
}
|
|
||||||
if (o1 is ContactItem && o2 is ContactItem) {
|
|
||||||
if (Participant.ActorType.GROUPS == o1.model.actorType &&
|
|
||||||
Participant.ActorType.GROUPS == o2.model.actorType
|
|
||||||
) {
|
|
||||||
return@sort firstName.compareTo(secondName, ignoreCase = true)
|
|
||||||
} else if (Participant.ActorType.GROUPS == o1.model.actorType) {
|
|
||||||
return@sort -1
|
|
||||||
} else if (Participant.ActorType.GROUPS == o2.model.actorType) {
|
|
||||||
return@sort 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
firstName.compareTo(secondName, ignoreCase = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun prepareViews() {
|
|
||||||
layoutManager = SmoothScrollLinearLayoutManager(this)
|
|
||||||
binding.contactsRv.layoutManager = layoutManager
|
|
||||||
binding.contactsRv.setHasFixedSize(true)
|
|
||||||
binding.contactsRv.adapter = adapter
|
|
||||||
|
|
||||||
binding.listOpenConversationsImage.background?.setColorFilter(
|
|
||||||
ResourcesCompat.getColor(resources!!, R.color.colorBackgroundDarker, null),
|
|
||||||
PorterDuff.Mode.SRC_IN
|
|
||||||
)
|
|
||||||
|
|
||||||
binding.let {
|
|
||||||
viewThemeUtils.platform.colorImageViewBackgroundAndIcon(it.publicCallLink)
|
|
||||||
}
|
|
||||||
disengageProgressBar()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun disengageProgressBar() {
|
|
||||||
if (!alreadyFetching) {
|
|
||||||
binding.contactsRv.visibility = View.VISIBLE
|
|
||||||
binding.loadingContent.visibility = View.GONE
|
|
||||||
binding.root.visibility = View.VISIBLE
|
|
||||||
if (isNewConversationView) {
|
|
||||||
binding.callHeaderLayout.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun dispose(disposable: Disposable?) {
|
|
||||||
if (disposable != null && !disposable.isDisposed) {
|
|
||||||
disposable.dispose()
|
|
||||||
} else if (disposable == null) {
|
|
||||||
if (contactsQueryDisposable != null && !contactsQueryDisposable!!.isDisposed) {
|
|
||||||
contactsQueryDisposable!!.dispose()
|
|
||||||
contactsQueryDisposable = null
|
|
||||||
}
|
|
||||||
if (cacheQueryDisposable != null && !cacheQueryDisposable!!.isDisposed) {
|
|
||||||
cacheQueryDisposable!!.dispose()
|
|
||||||
cacheQueryDisposable = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
dispose(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQueryTextChange(newText: String): Boolean {
|
|
||||||
if (newText != "" && adapter?.hasNewFilter(newText) == true) {
|
|
||||||
adapter?.setFilter(newText)
|
|
||||||
fetchData()
|
|
||||||
} else if (newText == "") {
|
|
||||||
adapter?.setFilter("")
|
|
||||||
adapter?.updateDataSet(contactItems as List<Nothing>?)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQueryTextSubmit(query: String): Boolean {
|
|
||||||
return onQueryTextChange(query)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkAndHandleDoneMenuItem() {
|
|
||||||
if (adapter != null && doneMenuItem != null) {
|
|
||||||
doneMenuItem!!.isVisible =
|
|
||||||
selectedCircleIds.size + selectedEmails.size + selectedGroupIds.size + selectedUserIds.size > 0 ||
|
|
||||||
isPublicCall
|
|
||||||
} else if (doneMenuItem != null) {
|
|
||||||
doneMenuItem!!.isVisible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
|
||||||
fun onMessageEvent(openConversationEvent: OpenConversationEvent) {
|
|
||||||
val chatIntent = Intent(context, ChatActivity::class.java)
|
|
||||||
chatIntent.putExtras(openConversationEvent.bundle!!)
|
|
||||||
chatIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
||||||
startActivity(chatIntent)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onItemClick(view: View, position: Int): Boolean {
|
|
||||||
if (adapter?.getItem(position) is ContactItem) {
|
|
||||||
if (!isNewConversationView && !isAddingParticipantsView) {
|
|
||||||
createRoom(adapter?.getItem(position) as ContactItem)
|
|
||||||
} else {
|
|
||||||
updateSelection((adapter?.getItem(position) as ContactItem))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateSelection(contactItem: ContactItem) {
|
|
||||||
contactItem.model.selected = !contactItem.model.selected
|
|
||||||
updateSelectionLists(contactItem.model)
|
|
||||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(
|
|
||||||
currentUser?.capabilities?.spreedCapability!!, SpreedFeatures.LAST_ROOM_ACTIVITY
|
|
||||||
) &&
|
|
||||||
!CapabilitiesUtil.hasSpreedFeatureCapability(
|
|
||||||
currentUser?.capabilities?.spreedCapability!!, SpreedFeatures.INVITE_GROUPS_AND_MAILS
|
|
||||||
) &&
|
|
||||||
isValidGroupSelection(contactItem, contactItem.model, adapter)
|
|
||||||
) {
|
|
||||||
val currentItems: List<ContactItem> = adapter?.currentItems as List<ContactItem>
|
|
||||||
var internalParticipant: Participant
|
|
||||||
for (i in currentItems.indices) {
|
|
||||||
internalParticipant = currentItems[i].model
|
|
||||||
if (internalParticipant.calculatedActorId == contactItem.model.calculatedActorId &&
|
|
||||||
internalParticipant.calculatedActorType == Participant.ActorType.GROUPS &&
|
|
||||||
internalParticipant.selected
|
|
||||||
) {
|
|
||||||
internalParticipant.selected = false
|
|
||||||
selectedGroupIds.remove(internalParticipant.calculatedActorId!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
adapter?.notifyDataSetChanged()
|
|
||||||
checkAndHandleDoneMenuItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createRoom(contactItem: ContactItem) {
|
|
||||||
var roomType = "1"
|
|
||||||
if (Participant.ActorType.GROUPS == contactItem.model.actorType) {
|
|
||||||
roomType = "2"
|
|
||||||
}
|
|
||||||
val apiVersion: Int = ApiUtils.getConversationApiVersion(currentUser!!, intArrayOf(ApiUtils.API_V4, 1))
|
|
||||||
val retrofitBucket: RetrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(
|
|
||||||
apiVersion,
|
|
||||||
currentUser!!.baseUrl!!,
|
|
||||||
roomType,
|
|
||||||
null,
|
|
||||||
contactItem.model.calculatedActorId,
|
|
||||||
null
|
|
||||||
)
|
|
||||||
ncApi.createRoom(credentials, retrofitBucket.url, retrofitBucket.queryMap)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(object : Observer<RoomOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(roomOverall: RoomOverall) {
|
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomOverall.ocs!!.data!!.token)
|
|
||||||
// bundle.putString(BundleKeys.KEY_ROOM_ID, roomOverall.ocs!!.data!!.roomId)
|
|
||||||
|
|
||||||
val chatIntent = Intent(context, ChatActivity::class.java)
|
|
||||||
chatIntent.putExtras(bundle)
|
|
||||||
chatIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
||||||
startActivity(chatIntent)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateSelectionLists(participant: Participant) {
|
|
||||||
if (Participant.ActorType.GROUPS == participant.actorType) {
|
|
||||||
if (participant.selected) {
|
|
||||||
selectedGroupIds.add(participant.calculatedActorId!!)
|
|
||||||
} else {
|
|
||||||
selectedGroupIds.remove(participant.calculatedActorId!!)
|
|
||||||
}
|
|
||||||
} else if (Participant.ActorType.EMAILS == participant.actorType) {
|
|
||||||
if (participant.selected) {
|
|
||||||
selectedEmails.add(participant.calculatedActorId!!)
|
|
||||||
} else {
|
|
||||||
selectedEmails.remove(participant.calculatedActorId!!)
|
|
||||||
}
|
|
||||||
} else if (Participant.ActorType.CIRCLES == participant.actorType) {
|
|
||||||
if (participant.selected) {
|
|
||||||
selectedCircleIds.add(participant.calculatedActorId!!)
|
|
||||||
} else {
|
|
||||||
selectedCircleIds.remove(participant.calculatedActorId!!)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (participant.selected) {
|
|
||||||
selectedUserIds.add(participant.calculatedActorId!!)
|
|
||||||
} else {
|
|
||||||
selectedUserIds.remove(participant.calculatedActorId!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isValidGroupSelection(
|
|
||||||
contactItem: ContactItem,
|
|
||||||
participant: Participant,
|
|
||||||
adapter: FlexibleAdapter<*>?
|
|
||||||
): Boolean {
|
|
||||||
return Participant.ActorType.GROUPS == contactItem.model.actorType &&
|
|
||||||
participant.selected && adapter?.selectedItemCount!! > 1
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun listOpenConversations() {
|
|
||||||
val intent = Intent(this, ListOpenConversationsActivity::class.java)
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toggleCallHeader() {
|
|
||||||
toggleConversationPrivacyLayout(isPublicCall)
|
|
||||||
isPublicCall = !isPublicCall
|
|
||||||
enableContactForNonPublicCall()
|
|
||||||
checkAndHandleDoneMenuItem()
|
|
||||||
adapter?.notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun enableContactForNonPublicCall() {
|
|
||||||
for (i in 0 until adapter!!.itemCount) {
|
|
||||||
if (adapter?.getItem(i) is ContactItem) {
|
|
||||||
val contactItem: ContactItem = adapter?.getItem(i) as ContactItem
|
|
||||||
if (Participant.ActorType.GROUPS == contactItem.model.actorType) {
|
|
||||||
contactItem.isEnabled = !isPublicCall
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toggleConversationPrivacyLayout(showInitialLayout: Boolean) {
|
|
||||||
if (showInitialLayout) {
|
|
||||||
binding.publicConversationCreate.visibility = View.VISIBLE
|
|
||||||
binding.publicConversationInfo.visibility = View.GONE
|
|
||||||
} else {
|
|
||||||
binding.publicConversationCreate.visibility = View.GONE
|
|
||||||
binding.publicConversationInfo.visibility = View.VISIBLE
|
|
||||||
binding.listOpenConversations.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val TAG = ContactsActivity::class.simpleName
|
|
||||||
const val RETRIES: Long = 3
|
|
||||||
const val CONTACTS_BATCH_SIZE: Int = 50
|
|
||||||
const val HEADER_ELEVATION: Int = 5
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* Nextcloud Talk - Android Client
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
|
|
||||||
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.nextcloud.talk.contacts
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.activity.compose.setContent
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
||||||
import autodagger.AutoInjector
|
|
||||||
import com.nextcloud.talk.activities.BaseActivity
|
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
|
||||||
import com.nextcloud.talk.components.SetupSystemBars
|
|
||||||
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication::class)
|
|
||||||
class ContactsActivityCompose : BaseActivity() {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var viewModelFactory: ViewModelProvider.Factory
|
|
||||||
private lateinit var contactsViewModel: ContactsViewModel
|
|
||||||
|
|
||||||
@SuppressLint("UnrememberedMutableState")
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
|
||||||
contactsViewModel = ViewModelProvider(this, viewModelFactory)[ContactsViewModel::class.java]
|
|
||||||
setContent {
|
|
||||||
val isAddParticipants = intent.getBooleanExtra("isAddParticipants", false)
|
|
||||||
contactsViewModel.updateIsAddParticipants(isAddParticipants)
|
|
||||||
if (isAddParticipants) {
|
|
||||||
contactsViewModel.updateShareTypes(
|
|
||||||
listOf(
|
|
||||||
ShareType.Group.shareType,
|
|
||||||
ShareType.Email.shareType,
|
|
||||||
ShareType.Circle.shareType
|
|
||||||
)
|
|
||||||
)
|
|
||||||
contactsViewModel.getContactsFromSearchParams()
|
|
||||||
}
|
|
||||||
val colorScheme = viewThemeUtils.getColorScheme(this)
|
|
||||||
val uiState = contactsViewModel.contactsViewState.collectAsStateWithLifecycle()
|
|
||||||
val selectedParticipants = remember {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
intent.getParcelableArrayListExtra("selectedParticipants", AutocompleteUser::class.java)
|
|
||||||
?: emptyList()
|
|
||||||
} else {
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
intent.getParcelableArrayListExtra("selectedParticipants") ?: emptyList()
|
|
||||||
}
|
|
||||||
}.toSet().toMutableList()
|
|
||||||
contactsViewModel.updateSelectedParticipants(selectedParticipants)
|
|
||||||
|
|
||||||
MaterialTheme(
|
|
||||||
colorScheme = colorScheme
|
|
||||||
) {
|
|
||||||
ContactsScreen(
|
|
||||||
contactsViewModel = contactsViewModel,
|
|
||||||
uiState = uiState.value
|
|
||||||
)
|
|
||||||
SetupSystemBars()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CompanionClass {
|
|
||||||
companion object {
|
|
||||||
internal val TAG = ContactsActivityCompose::class.simpleName
|
|
||||||
internal const val ROOM_TYPE_ONE_ONE = "1"
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,7 +15,6 @@ import androidx.compose.material3.Scaffold
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.colorResource
|
import androidx.compose.ui.res.colorResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
@ -26,8 +25,6 @@ import com.nextcloud.talk.contacts.components.ConversationCreationOptions
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ContactsScreen(contactsViewModel: ContactsViewModel, uiState: ContactsUiState) {
|
fun ContactsScreen(contactsViewModel: ContactsViewModel, uiState: ContactsUiState) {
|
||||||
val context = LocalContext.current
|
|
||||||
|
|
||||||
val searchQuery by contactsViewModel.searchQuery.collectAsStateWithLifecycle()
|
val searchQuery by contactsViewModel.searchQuery.collectAsStateWithLifecycle()
|
||||||
val isSearchActive by contactsViewModel.isSearchActive.collectAsStateWithLifecycle()
|
val isSearchActive by contactsViewModel.isSearchActive.collectAsStateWithLifecycle()
|
||||||
val isAddParticipants by contactsViewModel.isAddParticipantsView.collectAsStateWithLifecycle()
|
val isAddParticipants by contactsViewModel.isAddParticipantsView.collectAsStateWithLifecycle()
|
||||||
@ -57,17 +54,17 @@ fun ContactsScreen(contactsViewModel: ContactsViewModel, uiState: ContactsUiStat
|
|||||||
},
|
},
|
||||||
content = {
|
content = {
|
||||||
Column(
|
Column(
|
||||||
Modifier.padding(it)
|
Modifier
|
||||||
|
.padding(it)
|
||||||
.background(colorResource(id = R.color.bg_default))
|
.background(colorResource(id = R.color.bg_default))
|
||||||
) {
|
) {
|
||||||
ConversationCreationOptions(
|
if (!isAddParticipants) {
|
||||||
context = context,
|
ConversationCreationOptions()
|
||||||
contactsViewModel = contactsViewModel
|
}
|
||||||
)
|
|
||||||
ContactsList(
|
ContactsList(
|
||||||
contactsUiState = uiState,
|
contactsUiState = uiState,
|
||||||
contactsViewModel = contactsViewModel,
|
contactsViewModel = contactsViewModel
|
||||||
context = context
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,8 @@ class ContactsViewModel @Inject constructor(
|
|||||||
private val _isAddParticipantsView = MutableStateFlow(false)
|
private val _isAddParticipantsView = MutableStateFlow(false)
|
||||||
val isAddParticipantsView: StateFlow<Boolean> = _isAddParticipantsView
|
val isAddParticipantsView: StateFlow<Boolean> = _isAddParticipantsView
|
||||||
|
|
||||||
|
private var hideAlreadyAddedParticipants: Boolean = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
getContactsFromSearchParams()
|
getContactsFromSearchParams()
|
||||||
}
|
}
|
||||||
@ -69,6 +71,10 @@ class ContactsViewModel @Inject constructor(
|
|||||||
_isAddParticipantsView.value = value
|
_isAddParticipantsView.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun hideAlreadyAddedParticipants(value: Boolean) {
|
||||||
|
hideAlreadyAddedParticipants = value
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("Detekt.TooGenericExceptionCaught")
|
@Suppress("Detekt.TooGenericExceptionCaught")
|
||||||
fun getContactsFromSearchParams() {
|
fun getContactsFromSearchParams() {
|
||||||
_contactsViewState.value = ContactsUiState.Loading
|
_contactsViewState.value = ContactsUiState.Loading
|
||||||
@ -78,7 +84,12 @@ class ContactsViewModel @Inject constructor(
|
|||||||
searchQuery.value,
|
searchQuery.value,
|
||||||
shareTypeList
|
shareTypeList
|
||||||
)
|
)
|
||||||
val contactsList: List<AutocompleteUser>? = contacts.ocs!!.data
|
val contactsList: MutableList<AutocompleteUser>? = contacts.ocs!!.data?.toMutableList()
|
||||||
|
|
||||||
|
if (hideAlreadyAddedParticipants) {
|
||||||
|
contactsList?.removeAll(selectedParticipants.value)
|
||||||
|
}
|
||||||
|
|
||||||
_contactsViewState.value = ContactsUiState.Success(contactsList)
|
_contactsViewState.value = ContactsUiState.Success(contactsList)
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
_contactsViewState.value = ContactsUiState.Error(exception.message ?: "")
|
_contactsViewState.value = ContactsUiState.Error(exception.message ?: "")
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
package com.nextcloud.talk.contacts.components
|
package com.nextcloud.talk.contacts.components
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
@ -18,15 +17,18 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import com.nextcloud.talk.contacts.CompanionClass
|
import com.nextcloud.talk.contacts.CompanionClass
|
||||||
import com.nextcloud.talk.contacts.ContactsUiState
|
import com.nextcloud.talk.contacts.ContactsUiState
|
||||||
import com.nextcloud.talk.contacts.ContactsViewModel
|
import com.nextcloud.talk.contacts.ContactsViewModel
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ContactsList(contactsUiState: ContactsUiState, contactsViewModel: ContactsViewModel, context: Context) {
|
fun ContactsList(contactsUiState: ContactsUiState, contactsViewModel: ContactsViewModel) {
|
||||||
|
val context = LocalContext.current
|
||||||
when (contactsUiState) {
|
when (contactsUiState) {
|
||||||
is ContactsUiState.None -> {
|
is ContactsUiState.None -> {
|
||||||
}
|
}
|
||||||
|
|
||||||
is ContactsUiState.Loading -> {
|
is ContactsUiState.Loading -> {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
@ -35,6 +37,7 @@ fun ContactsList(contactsUiState: ContactsUiState, contactsViewModel: ContactsVi
|
|||||||
CircularProgressIndicator()
|
CircularProgressIndicator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is ContactsUiState.Success -> {
|
is ContactsUiState.Success -> {
|
||||||
val contacts = contactsUiState.contacts
|
val contacts = contactsUiState.contacts
|
||||||
Log.d(CompanionClass.TAG, "Contacts:$contacts")
|
Log.d(CompanionClass.TAG, "Contacts:$contacts")
|
||||||
@ -42,6 +45,7 @@ fun ContactsList(contactsUiState: ContactsUiState, contactsViewModel: ContactsVi
|
|||||||
ContactsItem(contacts, contactsViewModel, context)
|
ContactsItem(contacts, contactsViewModel, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is ContactsUiState.Error -> {
|
is ContactsUiState.Error -> {
|
||||||
val errorMessage = contactsUiState.message
|
val errorMessage = contactsUiState.message
|
||||||
Box(
|
Box(
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
package com.nextcloud.talk.contacts.components
|
package com.nextcloud.talk.contacts.components
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@ -23,23 +22,20 @@ import androidx.compose.material.icons.automirrored.filled.List
|
|||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.nextcloud.talk.R
|
import com.nextcloud.talk.R
|
||||||
import com.nextcloud.talk.contacts.ContactsViewModel
|
|
||||||
import com.nextcloud.talk.conversationcreation.ConversationCreationActivity
|
import com.nextcloud.talk.conversationcreation.ConversationCreationActivity
|
||||||
import com.nextcloud.talk.openconversations.ListOpenConversationsActivity
|
import com.nextcloud.talk.openconversations.ListOpenConversationsActivity
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ConversationCreationOptions(context: Context, contactsViewModel: ContactsViewModel) {
|
fun ConversationCreationOptions() {
|
||||||
val isAddParticipants by contactsViewModel.isAddParticipantsView.collectAsState()
|
val context = LocalContext.current
|
||||||
if (!isAddParticipants) {
|
|
||||||
Column {
|
Column {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -93,5 +89,4 @@ fun ConversationCreationOptions(context: Context, contactsViewModel: ContactsVie
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -84,9 +84,10 @@ import com.nextcloud.talk.R
|
|||||||
import com.nextcloud.talk.activities.BaseActivity
|
import com.nextcloud.talk.activities.BaseActivity
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||||
import com.nextcloud.talk.chat.ChatActivity
|
import com.nextcloud.talk.chat.ChatActivity
|
||||||
|
import com.nextcloud.talk.contacts.ContactsActivity
|
||||||
import com.nextcloud.talk.components.SetupSystemBars
|
import com.nextcloud.talk.components.SetupSystemBars
|
||||||
import com.nextcloud.talk.contacts.ContactsActivityCompose
|
|
||||||
import com.nextcloud.talk.contacts.loadImage
|
import com.nextcloud.talk.contacts.loadImage
|
||||||
|
import com.nextcloud.talk.extensions.getParcelableArrayListExtraProvider
|
||||||
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
|
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
|
||||||
import com.nextcloud.talk.utils.CapabilitiesUtil
|
import com.nextcloud.talk.utils.CapabilitiesUtil
|
||||||
import com.nextcloud.talk.utils.PickImage
|
import com.nextcloud.talk.utils.PickImage
|
||||||
@ -163,7 +164,7 @@ fun ConversationCreationScreen(
|
|||||||
if (result.resultCode == Activity.RESULT_OK) {
|
if (result.resultCode == Activity.RESULT_OK) {
|
||||||
val data = result.data
|
val data = result.data
|
||||||
val selectedParticipants =
|
val selectedParticipants =
|
||||||
data?.getParcelableArrayListExtra<AutocompleteUser>("selectedParticipants")
|
data?.getParcelableArrayListExtraProvider<AutocompleteUser>("selectedParticipants")
|
||||||
?: emptyList()
|
?: emptyList()
|
||||||
val participants = selectedParticipants.toMutableList()
|
val participants = selectedParticipants.toMutableList()
|
||||||
conversationCreationViewModel.updateSelectedParticipants(participants)
|
conversationCreationViewModel.updateSelectedParticipants(participants)
|
||||||
@ -378,12 +379,12 @@ fun AddParticipants(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(start = 16.dp, bottom = 16.dp)
|
.padding(start = 16.dp, bottom = 16.dp)
|
||||||
.clickable {
|
.clickable {
|
||||||
val intent = Intent(context, ContactsActivityCompose::class.java)
|
val intent = Intent(context, ContactsActivity::class.java)
|
||||||
intent.putParcelableArrayListExtra(
|
intent.putParcelableArrayListExtra(
|
||||||
"selectedParticipants",
|
"selectedParticipants",
|
||||||
participants as ArrayList<AutocompleteUser>
|
participants as ArrayList<AutocompleteUser>
|
||||||
)
|
)
|
||||||
intent.putExtra("isAddParticipants", true)
|
intent.putExtra(BundleKeys.KEY_ADD_PARTICIPANTS, true)
|
||||||
intent.putExtra("isAddParticipantsEdit", true)
|
intent.putExtra("isAddParticipantsEdit", true)
|
||||||
launcher.launch(intent)
|
launcher.launch(intent)
|
||||||
},
|
},
|
||||||
@ -416,8 +417,8 @@ fun AddParticipants(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable {
|
.clickable {
|
||||||
val intent = Intent(context, ContactsActivityCompose::class.java)
|
val intent = Intent(context, ContactsActivity::class.java)
|
||||||
intent.putExtra("isAddParticipants", true)
|
intent.putExtra(BundleKeys.KEY_ADD_PARTICIPANTS, true)
|
||||||
launcher.launch(intent)
|
launcher.launch(intent)
|
||||||
},
|
},
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
@ -608,7 +609,8 @@ fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: Con
|
|||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
.padding(vertical = 8.dp),
|
.padding(vertical = 8.dp),
|
||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
package com.nextcloud.talk.conversationinfo
|
package com.nextcloud.talk.conversationinfo
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -21,6 +22,8 @@ import android.view.MenuItem
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
|
import androidx.activity.result.ActivityResult
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
@ -49,6 +52,8 @@ import com.nextcloud.talk.api.NcApi
|
|||||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||||
import com.nextcloud.talk.bottomsheet.items.BasicListItemWithImage
|
import com.nextcloud.talk.bottomsheet.items.BasicListItemWithImage
|
||||||
import com.nextcloud.talk.bottomsheet.items.listItemsWithImage
|
import com.nextcloud.talk.bottomsheet.items.listItemsWithImage
|
||||||
|
import com.nextcloud.talk.chat.ChatActivity
|
||||||
|
import com.nextcloud.talk.contacts.CompanionClass.Companion.KEY_HIDE_ALREADY_EXISTING_PARTICIPANTS
|
||||||
import com.nextcloud.talk.contacts.ContactsActivity
|
import com.nextcloud.talk.contacts.ContactsActivity
|
||||||
import com.nextcloud.talk.conversationinfo.viewmodel.ConversationInfoViewModel
|
import com.nextcloud.talk.conversationinfo.viewmodel.ConversationInfoViewModel
|
||||||
import com.nextcloud.talk.conversationinfoedit.ConversationInfoEditActivity
|
import com.nextcloud.talk.conversationinfoedit.ConversationInfoEditActivity
|
||||||
@ -56,14 +61,17 @@ import com.nextcloud.talk.data.user.model.User
|
|||||||
import com.nextcloud.talk.databinding.ActivityConversationInfoBinding
|
import com.nextcloud.talk.databinding.ActivityConversationInfoBinding
|
||||||
import com.nextcloud.talk.databinding.DialogBanParticipantBinding
|
import com.nextcloud.talk.databinding.DialogBanParticipantBinding
|
||||||
import com.nextcloud.talk.events.EventStatus
|
import com.nextcloud.talk.events.EventStatus
|
||||||
|
import com.nextcloud.talk.extensions.getParcelableArrayListExtraProvider
|
||||||
import com.nextcloud.talk.extensions.loadConversationAvatar
|
import com.nextcloud.talk.extensions.loadConversationAvatar
|
||||||
import com.nextcloud.talk.extensions.loadNoteToSelfAvatar
|
import com.nextcloud.talk.extensions.loadNoteToSelfAvatar
|
||||||
import com.nextcloud.talk.extensions.loadSystemAvatar
|
import com.nextcloud.talk.extensions.loadSystemAvatar
|
||||||
import com.nextcloud.talk.extensions.loadUserAvatar
|
import com.nextcloud.talk.extensions.loadUserAvatar
|
||||||
|
import com.nextcloud.talk.jobs.AddParticipantsToConversation
|
||||||
import com.nextcloud.talk.jobs.DeleteConversationWorker
|
import com.nextcloud.talk.jobs.DeleteConversationWorker
|
||||||
import com.nextcloud.talk.jobs.LeaveConversationWorker
|
import com.nextcloud.talk.jobs.LeaveConversationWorker
|
||||||
import com.nextcloud.talk.models.domain.ConversationModel
|
import com.nextcloud.talk.models.domain.ConversationModel
|
||||||
import com.nextcloud.talk.models.domain.converters.DomainEnumNotificationLevelConverter
|
import com.nextcloud.talk.models.domain.converters.DomainEnumNotificationLevelConverter
|
||||||
|
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
|
||||||
import com.nextcloud.talk.models.json.capabilities.SpreedCapability
|
import com.nextcloud.talk.models.json.capabilities.SpreedCapability
|
||||||
import com.nextcloud.talk.models.json.conversations.ConversationEnums
|
import com.nextcloud.talk.models.json.conversations.ConversationEnums
|
||||||
import com.nextcloud.talk.models.json.converters.EnumActorTypeConverter
|
import com.nextcloud.talk.models.json.converters.EnumActorTypeConverter
|
||||||
@ -126,12 +134,9 @@ class ConversationInfoActivity :
|
|||||||
private lateinit var conversationUser: User
|
private lateinit var conversationUser: User
|
||||||
private var hasAvatarSpacing: Boolean = false
|
private var hasAvatarSpacing: Boolean = false
|
||||||
private lateinit var credentials: String
|
private lateinit var credentials: String
|
||||||
private var roomDisposable: Disposable? = null
|
|
||||||
private var participantsDisposable: Disposable? = null
|
private var participantsDisposable: Disposable? = null
|
||||||
|
|
||||||
private var databaseStorageModule: DatabaseStorageModule? = null
|
private var databaseStorageModule: DatabaseStorageModule? = null
|
||||||
|
|
||||||
// private var conversation: Conversation? = null
|
|
||||||
private var conversation: ConversationModel? = null
|
private var conversation: ConversationModel? = null
|
||||||
|
|
||||||
private var adapter: FlexibleAdapter<ParticipantItem>? = null
|
private var adapter: FlexibleAdapter<ParticipantItem>? = null
|
||||||
@ -147,10 +152,21 @@ class ConversationInfoActivity :
|
|||||||
data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, conversationUser.id!!)
|
data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, conversationUser.id!!)
|
||||||
return data.build()
|
return data.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val addParticipantsResult = registerForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) {
|
||||||
|
executeIfResultOk(it) { intent ->
|
||||||
|
val selectedParticipants =
|
||||||
|
intent?.getParcelableArrayListExtraProvider<AutocompleteUser>("selectedParticipants")
|
||||||
|
?: emptyList()
|
||||||
|
val participants = selectedParticipants.toMutableList()
|
||||||
|
addParticipantsToConversation(participants)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||||
@ -190,7 +206,7 @@ class ConversationInfoActivity :
|
|||||||
binding.deleteConversationAction.setOnClickListener { showDeleteConversationDialog() }
|
binding.deleteConversationAction.setOnClickListener { showDeleteConversationDialog() }
|
||||||
binding.leaveConversationAction.setOnClickListener { leaveConversation() }
|
binding.leaveConversationAction.setOnClickListener { leaveConversation() }
|
||||||
binding.clearConversationHistory.setOnClickListener { showClearHistoryDialog() }
|
binding.clearConversationHistory.setOnClickListener { showClearHistoryDialog() }
|
||||||
binding.addParticipantsAction.setOnClickListener { addParticipants() }
|
binding.addParticipantsAction.setOnClickListener { selectParticipantsToAdd() }
|
||||||
binding.listBansButton.setOnClickListener { listBans() }
|
binding.listBansButton.setOnClickListener { listBans() }
|
||||||
|
|
||||||
viewModel.getRoom(conversationUser, conversationToken)
|
viewModel.getRoom(conversationUser, conversationToken)
|
||||||
@ -237,9 +253,11 @@ class ConversationInfoActivity :
|
|||||||
when (state) {
|
when (state) {
|
||||||
is ConversationInfoViewModel.SetConversationReadOnlyViewState.Success -> {
|
is ConversationInfoViewModel.SetConversationReadOnlyViewState.Success -> {
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConversationInfoViewModel.SetConversationReadOnlyViewState.Error -> {
|
is ConversationInfoViewModel.SetConversationReadOnlyViewState.Error -> {
|
||||||
Snackbar.make(binding.root, R.string.conversation_read_only_failed, Snackbar.LENGTH_LONG).show()
|
Snackbar.make(binding.root, R.string.conversation_read_only_failed, Snackbar.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConversationInfoViewModel.SetConversationReadOnlyViewState.None -> {
|
is ConversationInfoViewModel.SetConversationReadOnlyViewState.None -> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,6 +267,7 @@ class ConversationInfoActivity :
|
|||||||
when (uiState) {
|
when (uiState) {
|
||||||
is ConversationInfoViewModel.ClearChatHistoryViewState.None -> {
|
is ConversationInfoViewModel.ClearChatHistoryViewState.None -> {
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConversationInfoViewModel.ClearChatHistoryViewState.Success -> {
|
is ConversationInfoViewModel.ClearChatHistoryViewState.Success -> {
|
||||||
Snackbar.make(
|
Snackbar.make(
|
||||||
binding.root,
|
binding.root,
|
||||||
@ -256,6 +275,7 @@ class ConversationInfoActivity :
|
|||||||
Snackbar.LENGTH_LONG
|
Snackbar.LENGTH_LONG
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConversationInfoViewModel.ClearChatHistoryViewState.Error -> {
|
is ConversationInfoViewModel.ClearChatHistoryViewState.Error -> {
|
||||||
Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
|
Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
|
||||||
Log.e(TAG, "failed to clear chat history", uiState.exception)
|
Log.e(TAG, "failed to clear chat history", uiState.exception)
|
||||||
@ -319,7 +339,7 @@ class ConversationInfoActivity :
|
|||||||
fun showOptionsMenu() {
|
fun showOptionsMenu() {
|
||||||
if (::optionsMenu.isInitialized) {
|
if (::optionsMenu.isInitialized) {
|
||||||
optionsMenu.clear()
|
optionsMenu.clear()
|
||||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.AVATAR)) {
|
if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.AVATAR)) {
|
||||||
menuInflater.inflate(R.menu.menu_conversation_info, optionsMenu)
|
menuInflater.inflate(R.menu.menu_conversation_info, optionsMenu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -383,7 +403,7 @@ class ConversationInfoActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupWebinaryView() {
|
private fun setupWebinaryView() {
|
||||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.WEBINARY_LOBBY) &&
|
if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.WEBINARY_LOBBY) &&
|
||||||
webinaryRoomType(conversation!!) &&
|
webinaryRoomType(conversation!!) &&
|
||||||
ConversationUtils.canModerate(conversation!!, spreedCapabilities)
|
ConversationUtils.canModerate(conversation!!, spreedCapabilities)
|
||||||
) {
|
) {
|
||||||
@ -652,23 +672,89 @@ class ConversationInfoActivity :
|
|||||||
.commit()
|
.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addParticipants() {
|
private fun executeIfResultOk(result: ActivityResult, onResult: (intent: Intent?) -> Unit) {
|
||||||
|
if (result.resultCode == Activity.RESULT_OK) {
|
||||||
|
onResult(result.data)
|
||||||
|
} else {
|
||||||
|
Log.e(ChatActivity.TAG, "resultCode for received intent was != ok")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun selectParticipantsToAdd() {
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
val existingParticipantsId = arrayListOf<String>()
|
val existingParticipants = ArrayList<AutocompleteUser>()
|
||||||
|
|
||||||
for (userItem in userItems) {
|
for (userItem in userItems) {
|
||||||
if (userItem.model.calculatedActorType == USERS) {
|
if (userItem.model.calculatedActorType == USERS) {
|
||||||
existingParticipantsId.add(userItem.model.calculatedActorId!!)
|
val user = AutocompleteUser(
|
||||||
|
userItem.model.calculatedActorId!!,
|
||||||
|
userItem.model.displayName,
|
||||||
|
userItem.model.calculatedActorType.name.lowercase()
|
||||||
|
)
|
||||||
|
existingParticipants.add(user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bundle.putBoolean(BundleKeys.KEY_ADD_PARTICIPANTS, true)
|
bundle.putBoolean(BundleKeys.KEY_ADD_PARTICIPANTS, true)
|
||||||
bundle.putStringArrayList(BundleKeys.KEY_EXISTING_PARTICIPANTS, existingParticipantsId)
|
bundle.putParcelableArrayList("selectedParticipants", existingParticipants)
|
||||||
|
bundle.putBoolean(KEY_HIDE_ALREADY_EXISTING_PARTICIPANTS, true)
|
||||||
bundle.putString(BundleKeys.KEY_TOKEN, conversation!!.token)
|
bundle.putString(BundleKeys.KEY_TOKEN, conversation!!.token)
|
||||||
|
|
||||||
val intent = Intent(this, ContactsActivity::class.java)
|
val intent = Intent(this, ContactsActivity::class.java)
|
||||||
intent.putExtras(bundle)
|
intent.putExtras(bundle)
|
||||||
startActivity(intent)
|
|
||||||
|
addParticipantsResult.launch(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addParticipantsToConversation(participants: List<AutocompleteUser>) {
|
||||||
|
val groupIdsArray: MutableSet<String> = HashSet()
|
||||||
|
val emailIdsArray: MutableSet<String> = HashSet()
|
||||||
|
val circleIdsArray: MutableSet<String> = HashSet()
|
||||||
|
val userIdsArray: MutableSet<String> = HashSet()
|
||||||
|
|
||||||
|
participants.forEach { participant ->
|
||||||
|
when (participant.source) {
|
||||||
|
Participant.ActorType.GROUPS.name.lowercase() -> groupIdsArray.add(participant.id!!)
|
||||||
|
Participant.ActorType.EMAILS.name.lowercase() -> emailIdsArray.add(participant.id!!)
|
||||||
|
Participant.ActorType.CIRCLES.name.lowercase() -> circleIdsArray.add(participant.id!!)
|
||||||
|
else -> userIdsArray.add(participant.id!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val data = Data.Builder()
|
||||||
|
data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, conversationUser.id!!)
|
||||||
|
data.putString(BundleKeys.KEY_TOKEN, conversationToken)
|
||||||
|
data.putStringArray(BundleKeys.KEY_SELECTED_USERS, userIdsArray.toTypedArray())
|
||||||
|
data.putStringArray(BundleKeys.KEY_SELECTED_GROUPS, groupIdsArray.toTypedArray())
|
||||||
|
data.putStringArray(BundleKeys.KEY_SELECTED_EMAILS, emailIdsArray.toTypedArray())
|
||||||
|
data.putStringArray(BundleKeys.KEY_SELECTED_CIRCLES, circleIdsArray.toTypedArray())
|
||||||
|
val addParticipantsToConversationWorker: OneTimeWorkRequest = OneTimeWorkRequest.Builder(
|
||||||
|
AddParticipantsToConversation::class.java
|
||||||
|
).setInputData(data.build()).build()
|
||||||
|
WorkManager.getInstance().enqueue(addParticipantsToConversationWorker)
|
||||||
|
|
||||||
|
WorkManager.getInstance(context).getWorkInfoByIdLiveData(addParticipantsToConversationWorker.id)
|
||||||
|
.observeForever { workInfo: WorkInfo? ->
|
||||||
|
if (workInfo != null) {
|
||||||
|
when (workInfo.state) {
|
||||||
|
WorkInfo.State.RUNNING -> {
|
||||||
|
Log.d(TAG, "running AddParticipantsToConversation")
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkInfo.State.SUCCEEDED -> {
|
||||||
|
Log.d(TAG, "success AddParticipantsToConversation")
|
||||||
|
getListOfParticipants()
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkInfo.State.FAILED -> {
|
||||||
|
Log.d(TAG, "failed AddParticipantsToConversation")
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun leaveConversation() {
|
private fun leaveConversation() {
|
||||||
@ -693,6 +779,7 @@ class ConversationInfoActivity :
|
|||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkInfo.State.FAILED -> {
|
WorkInfo.State.FAILED -> {
|
||||||
val errorType = workInfo.outputData.getString("error_type")
|
val errorType = workInfo.outputData.getString("error_type")
|
||||||
if (errorType == LeaveConversationWorker.ERROR_NO_OTHER_MODERATORS_OR_OWNERS_LEFT) {
|
if (errorType == LeaveConversationWorker.ERROR_NO_OTHER_MODERATORS_OR_OWNERS_LEFT) {
|
||||||
@ -709,6 +796,7 @@ class ConversationInfoActivity :
|
|||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -769,7 +857,7 @@ class ConversationInfoActivity :
|
|||||||
|
|
||||||
setUpNotificationSettings(databaseStorageModule!!)
|
setUpNotificationSettings(databaseStorageModule!!)
|
||||||
|
|
||||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.RICH_OBJECT_LIST_MEDIA) &&
|
if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.RICH_OBJECT_LIST_MEDIA) &&
|
||||||
conversationCopy.remoteServer.isNullOrEmpty()
|
conversationCopy.remoteServer.isNullOrEmpty()
|
||||||
) {
|
) {
|
||||||
binding.sharedItemsButton.setOnClickListener { showSharedItems() }
|
binding.sharedItemsButton.setOnClickListener { showSharedItems() }
|
||||||
@ -779,7 +867,7 @@ class ConversationInfoActivity :
|
|||||||
|
|
||||||
if (ConversationUtils.canModerate(conversationCopy, spreedCapabilities)) {
|
if (ConversationUtils.canModerate(conversationCopy, spreedCapabilities)) {
|
||||||
binding.addParticipantsAction.visibility = VISIBLE
|
binding.addParticipantsAction.visibility = VISIBLE
|
||||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(
|
if (hasSpreedFeatureCapability(
|
||||||
spreedCapabilities,
|
spreedCapabilities,
|
||||||
SpreedFeatures.CLEAR_HISTORY
|
SpreedFeatures.CLEAR_HISTORY
|
||||||
) && conversationCopy.canDeleteConversation
|
) && conversationCopy.canDeleteConversation
|
||||||
@ -1011,7 +1099,7 @@ class ConversationInfoActivity :
|
|||||||
|
|
||||||
private fun initExpiringMessageOption() {
|
private fun initExpiringMessageOption() {
|
||||||
if (ConversationUtils.isParticipantOwnerOrModerator(conversation!!) &&
|
if (ConversationUtils.isParticipantOwnerOrModerator(conversation!!) &&
|
||||||
CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MESSAGE_EXPIRATION)
|
hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MESSAGE_EXPIRATION)
|
||||||
) {
|
) {
|
||||||
databaseStorageModule?.setMessageExpiration(conversation!!.messageExpiration)
|
databaseStorageModule?.setMessageExpiration(conversation!!.messageExpiration)
|
||||||
val value = databaseStorageModule!!.getString("conversation_settings_dropdown", "")
|
val value = databaseStorageModule!!.getString("conversation_settings_dropdown", "")
|
||||||
@ -1034,7 +1122,7 @@ class ConversationInfoActivity :
|
|||||||
|
|
||||||
private fun adjustNotificationLevelUI() {
|
private fun adjustNotificationLevelUI() {
|
||||||
if (conversation != null) {
|
if (conversation != null) {
|
||||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.NOTIFICATION_LEVELS)) {
|
if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.NOTIFICATION_LEVELS)) {
|
||||||
binding.notificationSettingsView.conversationInfoMessageNotificationsDropdown.isEnabled = true
|
binding.notificationSettingsView.conversationInfoMessageNotificationsDropdown.isEnabled = true
|
||||||
binding.notificationSettingsView.conversationInfoMessageNotificationsDropdown.alpha = 1.0f
|
binding.notificationSettingsView.conversationInfoMessageNotificationsDropdown.alpha = 1.0f
|
||||||
|
|
||||||
@ -1069,7 +1157,7 @@ class ConversationInfoActivity :
|
|||||||
|
|
||||||
private fun setProperNotificationValue(conversation: ConversationModel?) {
|
private fun setProperNotificationValue(conversation: ConversationModel?) {
|
||||||
if (conversation!!.type == ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) {
|
if (conversation!!.type == ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) {
|
||||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MENTION_FLAG)) {
|
if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MENTION_FLAG)) {
|
||||||
binding.notificationSettingsView.conversationInfoMessageNotificationsDropdown.setText(
|
binding.notificationSettingsView.conversationInfoMessageNotificationsDropdown.setText(
|
||||||
resources.getString(R.string.nc_notify_me_always)
|
resources.getString(R.string.nc_notify_me_always)
|
||||||
)
|
)
|
||||||
|
@ -82,7 +82,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
|
|||||||
import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager
|
import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager
|
||||||
import com.nextcloud.talk.chat.ChatActivity
|
import com.nextcloud.talk.chat.ChatActivity
|
||||||
import com.nextcloud.talk.chat.viewmodels.ChatViewModel
|
import com.nextcloud.talk.chat.viewmodels.ChatViewModel
|
||||||
import com.nextcloud.talk.contacts.ContactsActivityCompose
|
import com.nextcloud.talk.contacts.ContactsActivity
|
||||||
import com.nextcloud.talk.contacts.ContactsUiState
|
import com.nextcloud.talk.contacts.ContactsUiState
|
||||||
import com.nextcloud.talk.contacts.ContactsViewModel
|
import com.nextcloud.talk.contacts.ContactsViewModel
|
||||||
import com.nextcloud.talk.contacts.RoomUiState
|
import com.nextcloud.talk.contacts.RoomUiState
|
||||||
@ -131,7 +131,6 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_HIDE_SOURCE_ROOM
|
|||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_MSG_FLAG
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_MSG_FLAG
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_MSG_TEXT
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_MSG_TEXT
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NEW_CONVERSATION
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SCROLL_TO_NOTIFICATION_CATEGORY
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SCROLL_TO_NOTIFICATION_CATEGORY
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SHARED_TEXT
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SHARED_TEXT
|
||||||
@ -1253,8 +1252,7 @@ class ConversationsListActivity :
|
|||||||
conversation.type === ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL
|
conversation.type === ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL
|
||||||
|
|
||||||
private fun showNewConversationsScreen() {
|
private fun showNewConversationsScreen() {
|
||||||
val intent = Intent(context, ContactsActivityCompose::class.java)
|
val intent = Intent(context, ContactsActivity::class.java)
|
||||||
intent.putExtra(KEY_NEW_CONVERSATION, true)
|
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk - Android Client
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.extensions
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Parcelable
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
inline fun <reified T : Parcelable> Intent.getParcelableExtraProvider(identifierParameter: String): T? {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
this.getParcelableExtra(identifierParameter, T::class.java)
|
||||||
|
} else {
|
||||||
|
this.getParcelableExtra(identifierParameter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
inline fun <reified T : Parcelable> Intent.getParcelableArrayListExtraProvider(
|
||||||
|
identifierParameter: String
|
||||||
|
): java.util.ArrayList<T>? {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
this.getParcelableArrayListExtra(identifierParameter, T::class.java)
|
||||||
|
} else {
|
||||||
|
this.getParcelableArrayListExtra(identifierParameter)
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
<!--
|
|
||||||
~ Nextcloud Talk - Android Client
|
|
||||||
~
|
|
||||||
~ SPDX-FileCopyrightText: 2018-2024 Google LLC
|
|
||||||
~ SPDX-License-Identifier: Apache-2.0
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:autoMirrored="true"
|
|
||||||
android:viewportWidth="24.0"
|
|
||||||
android:viewportHeight="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
|
|
||||||
</vector>
|
|
@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ Nextcloud Talk - Android Client
|
|
||||||
~
|
|
||||||
~ SPDX-FileCopyrightText: Tobias Kaminsky <tobias@kaminsky.me>
|
|
||||||
~ SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
-->
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<solid android:color="#ededed" />
|
|
||||||
<corners android:radius="24dp" />
|
|
||||||
</shape>
|
|
@ -1,196 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ Nextcloud Talk - Android Client
|
|
||||||
~
|
|
||||||
~ SPDX-FileCopyrightText: 2024 Parneet Singh <gurayaparneet@gmail.com>
|
|
||||||
~ SPDX-FileCopyrightText: 2023 Marcel Hibbe <dev@mhibbe.de>
|
|
||||||
~ SPDX-FileCopyrightText: 2018 Andy Scherzinger <info@andy-scherzinger.de>
|
|
||||||
~ SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
-->
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:animateLayoutChanges="true">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
|
||||||
android:id="@+id/contacts_appbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
|
||||||
android:id="@+id/contacts_toolbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="?attr/actionBarSize"
|
|
||||||
android:background="@color/appbar"
|
|
||||||
android:theme="?attr/actionBarPopupTheme"
|
|
||||||
app:layout_scrollFlags="scroll|enterAlways"
|
|
||||||
app:navigationIconTint="@color/fontAppbar"
|
|
||||||
app:popupTheme="@style/appActionBarPopupMenu"
|
|
||||||
app:titleTextColor="@color/fontAppbar"
|
|
||||||
tools:title="@string/nc_app_product_name" />
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/call_header_layout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="@dimen/standard_margin"
|
|
||||||
android:layout_marginTop="@dimen/standard_half_margin"
|
|
||||||
android:layout_marginEnd="@dimen/standard_margin"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/contacts_appbar">
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/public_conversation_create"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/public_call_link"
|
|
||||||
android:layout_width="@dimen/avatar_size"
|
|
||||||
android:layout_height="@dimen/avatar_size"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_marginEnd="@dimen/standard_margin"
|
|
||||||
android:background="@drawable/round_bgnd"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:padding="@dimen/standard_half_padding"
|
|
||||||
android:src="@drawable/ic_add_white_24px"
|
|
||||||
app:tint="@color/white" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_toEndOf="@id/public_call_link"
|
|
||||||
android:ellipsize="middle"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:text="@string/nc_public_call"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
android:textAppearance="@style/ListItem"
|
|
||||||
tools:text="@string/nc_public_call" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/public_conversation_info"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:minHeight="@dimen/small_item_height"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="gone">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:text="@string/nc_public_call_explanation"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
|
||||||
tools:text="@string/nc_public_call_explanation" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/list_open_conversations"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="@dimen/standard_margin"
|
|
||||||
android:layout_marginTop="@dimen/standard_margin"
|
|
||||||
android:layout_marginEnd="@dimen/standard_margin"
|
|
||||||
android:layout_marginBottom="@dimen/standard_half_margin"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/call_header_layout">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/list_open_conversations_image"
|
|
||||||
android:layout_width="@dimen/avatar_size"
|
|
||||||
android:layout_height="@dimen/avatar_size"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_marginEnd="@dimen/standard_margin"
|
|
||||||
android:background="@drawable/round_bgnd"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:padding="@dimen/standard_half_padding"
|
|
||||||
android:src="@drawable/baseline_format_list_bulleted_24"
|
|
||||||
app:tint="@color/white" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_toEndOf="@id/list_open_conversations_image"
|
|
||||||
android:ellipsize="middle"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:text="@string/nc_list_open_conversations"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
android:textAppearance="@style/ListItem" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/loading_content"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_marginTop="@dimen/standard_half_margin"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/list_open_conversations"
|
|
||||||
tools:visibility="gone">
|
|
||||||
|
|
||||||
<include layout="@layout/rv_item_contact_shimmer" />
|
|
||||||
|
|
||||||
<include layout="@layout/rv_item_contact_shimmer" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<com.elyeproj.loaderviewlibrary.LoaderTextView
|
|
||||||
android:id="@+id/title_text_view"
|
|
||||||
android:layout_width="16dp"
|
|
||||||
android:layout_height="32dp"
|
|
||||||
android:layout_marginStart="72dp"
|
|
||||||
android:layout_marginTop="@dimen/standard_half_margin"
|
|
||||||
android:layout_marginEnd="@dimen/standard_margin"
|
|
||||||
android:layout_marginBottom="@dimen/standard_half_margin"
|
|
||||||
app:custom_color="@color/nc_shimmer_default_color" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1px"
|
|
||||||
android:background="?android:attr/listDivider" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<include layout="@layout/rv_item_contact_shimmer" />
|
|
||||||
|
|
||||||
<include layout="@layout/rv_item_contact_shimmer" />
|
|
||||||
|
|
||||||
<include layout="@layout/rv_item_contact_shimmer" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/list_open_conversations">
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/contacts_rv"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,55 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ Nextcloud Talk - Android Client
|
|
||||||
~
|
|
||||||
~ SPDX-FileCopyrightText: 2017-2019 Mario Danic <mario@lovelyhq.com>
|
|
||||||
~ SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
-->
|
|
||||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/fast_scroller_handle"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:alpha="0.5"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:paddingStart="6dp"
|
|
||||||
android:paddingEnd="0dp"
|
|
||||||
android:src="@drawable/fast_scroller_handle" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/fast_scroller_bubble"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:layout_marginEnd="0dp"
|
|
||||||
android:layout_toStartOf="@+id/fast_scroller_handle"
|
|
||||||
android:background="@drawable/fast_scroller_bubble"
|
|
||||||
android:gravity="start|center_vertical"
|
|
||||||
android:paddingLeft="16dp"
|
|
||||||
android:paddingRight="16dp"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
android:textColor="?android:attr/textColorPrimaryInverse"
|
|
||||||
android:textSize="38sp"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:text="A"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/fast_scroller_bar"
|
|
||||||
android:layout_width="7dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:background="@color/transparent" />
|
|
||||||
|
|
||||||
</merge>
|
|
@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ Nextcloud Talk - Android Client
|
|
||||||
~
|
|
||||||
~ SPDX-FileCopyrightText: 2017-2019 Mario Danic <mario@lovelyhq.com>
|
|
||||||
~ SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
-->
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent" android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/progress_bar"
|
|
||||||
style="@style/Widget.AppCompat.ProgressBar"
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:foregroundTint="@color/colorPrimary"
|
|
||||||
android:layout_margin="8dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_centerInParent="true" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ Nextcloud Talk - Android Client
|
|
||||||
~
|
|
||||||
~ SPDX-FileCopyrightText: 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
|
||||||
~ SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
-->
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="@dimen/standard_margin"
|
|
||||||
android:layout_marginTop="@dimen/standard_half_margin"
|
|
||||||
android:layout_marginEnd="@dimen/standard_margin"
|
|
||||||
android:layout_marginBottom="@dimen/standard_half_margin"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<com.elyeproj.loaderviewlibrary.LoaderTextView
|
|
||||||
android:id="@+id/loader_text_view"
|
|
||||||
android:layout_width="@dimen/avatar_size"
|
|
||||||
android:layout_height="@dimen/avatar_size"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_marginEnd="@dimen/standard_margin"
|
|
||||||
app:corners="100"
|
|
||||||
app:custom_color="@color/nc_shimmer_default_color" />
|
|
||||||
|
|
||||||
<com.elyeproj.loaderviewlibrary.LoaderTextView
|
|
||||||
android:id="@+id/name_text"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_toEndOf="@id/loader_text_view"
|
|
||||||
app:custom_color="@color/nc_shimmer_default_color" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
@ -1,25 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ Nextcloud Talk - Android Client
|
|
||||||
~
|
|
||||||
~ SPDX-FileCopyrightText: 2017-2018 Mario Danic <mario@lovelyhq.com>
|
|
||||||
~ SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
-->
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_search"
|
|
||||||
android:animateLayoutChanges="true"
|
|
||||||
android:icon="@drawable/ic_search_white_24dp"
|
|
||||||
android:title="@string/nc_search"
|
|
||||||
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
|
||||||
app:showAsAction="collapseActionView|ifRoom" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/contacts_selection_done"
|
|
||||||
android:title="@string/nc_contacts_done"
|
|
||||||
android:transitionName="userAvatar.transitionTag"
|
|
||||||
android:visible="false"
|
|
||||||
app:showAsAction="always" />
|
|
||||||
</menu>
|
|
@ -39,8 +39,6 @@
|
|||||||
|
|
||||||
<color name="chat_separator">#484848</color>
|
<color name="chat_separator">#484848</color>
|
||||||
|
|
||||||
<color name="colorBackgroundDarker">#2C2C2C</color>
|
|
||||||
|
|
||||||
<!-- Chat window incoming message text & informational -->
|
<!-- Chat window incoming message text & informational -->
|
||||||
<color name="bg_bottom_sheet">#121212</color>
|
<color name="bg_bottom_sheet">#121212</color>
|
||||||
<color name="bg_message_list_incoming_bubble">#2A2A2A</color>
|
<color name="bg_message_list_incoming_bubble">#2A2A2A</color>
|
||||||
|
@ -53,7 +53,6 @@
|
|||||||
<color name="call_incomingCallTextView">#E9FFFFFF</color>
|
<color name="call_incomingCallTextView">#E9FFFFFF</color>
|
||||||
<color name="grey950">#111111</color>
|
<color name="grey950">#111111</color>
|
||||||
<color name="textColorMaxContrast">#767676</color>
|
<color name="textColorMaxContrast">#767676</color>
|
||||||
<color name="colorBackgroundDarker">#DBDBDB</color>
|
|
||||||
|
|
||||||
<color name="fg_default">#666666</color>
|
<color name="fg_default">#666666</color>
|
||||||
<color name="fg_inverse">#FFFFFF</color>
|
<color name="fg_inverse">#FFFFFF</color>
|
||||||
|
@ -241,7 +241,6 @@ How to translate with transifex:
|
|||||||
<string name="nc_delete_conversation_more">If you delete the conversation, it will also be deleted for all other participants.</string>
|
<string name="nc_delete_conversation_more">If you delete the conversation, it will also be deleted for all other participants.</string>
|
||||||
|
|
||||||
<string name="nc_new_conversation">New conversation</string>
|
<string name="nc_new_conversation">New conversation</string>
|
||||||
<string name="nc_list_open_conversations">List open conversations</string>
|
|
||||||
<string name="nc_mark_as_read">Mark as read</string>
|
<string name="nc_mark_as_read">Mark as read</string>
|
||||||
<string name="nc_mark_as_unread">Mark as unread</string>
|
<string name="nc_mark_as_unread">Mark as unread</string>
|
||||||
<string name="nc_add_to_favorites">Add to favorites</string>
|
<string name="nc_add_to_favorites">Add to favorites</string>
|
||||||
@ -267,7 +266,6 @@ How to translate with transifex:
|
|||||||
<string name="nc_no_open_conversations_text">No open conversations that you can join.\nEither there are no open conversations or you already joined all of them.</string>
|
<string name="nc_no_open_conversations_text">No open conversations that you can join.\nEither there are no open conversations or you already joined all of them.</string>
|
||||||
|
|
||||||
<!-- Contacts -->
|
<!-- Contacts -->
|
||||||
<string name="nc_select_participants">Select participants</string>
|
|
||||||
<string name="nc_add_participants">Add participants</string>
|
<string name="nc_add_participants">Add participants</string>
|
||||||
<string name="nc_contacts_done">Done</string>
|
<string name="nc_contacts_done">Done</string>
|
||||||
<string name="user_avatar">User avatar</string>
|
<string name="user_avatar">User avatar</string>
|
||||||
@ -291,8 +289,6 @@ How to translate with transifex:
|
|||||||
<string name="nc_connecting_call">Connecting …</string>
|
<string name="nc_connecting_call">Connecting …</string>
|
||||||
<string name="nc_nick_guest">Guest</string>
|
<string name="nc_nick_guest">Guest</string>
|
||||||
<string name="nc_public_call_status">Public conversation</string>
|
<string name="nc_public_call_status">Public conversation</string>
|
||||||
<string name="nc_public_call">New public conversation</string>
|
|
||||||
<string name="nc_public_call_explanation">Public conversations let you invite people from outside through a specially crafted link.</string>
|
|
||||||
<string name="nc_call_timeout">No response in 45 seconds, tap to try again</string>
|
<string name="nc_call_timeout">No response in 45 seconds, tap to try again</string>
|
||||||
<string name="nc_call_reconnecting">Reconnecting …</string>
|
<string name="nc_call_reconnecting">Reconnecting …</string>
|
||||||
<string name="nc_offline">Currently offline, please check your connectivity</string>
|
<string name="nc_offline">Currently offline, please check your connectivity</string>
|
||||||
@ -481,6 +477,7 @@ How to translate with transifex:
|
|||||||
<string name="nc_teams">Teams</string>
|
<string name="nc_teams">Teams</string>
|
||||||
<string name="nc_participants">Participants</string>
|
<string name="nc_participants">Participants</string>
|
||||||
<string name="nc_participants_add">Add participants</string>
|
<string name="nc_participants_add">Add participants</string>
|
||||||
|
<string name="nc_start_group_chat">Start group chat</string>
|
||||||
|
|
||||||
<string name="nc_owner">Owner</string>
|
<string name="nc_owner">Owner</string>
|
||||||
<string name="nc_moderator">Moderator</string>
|
<string name="nc_moderator">Moderator</string>
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
DO NOT TOUCH; GENERATED BY DRONE
|
DO NOT TOUCH; GENERATED BY DRONE
|
||||||
<span class="mdl-layout-title">Lint Report: 9 errors and 100 warnings</span>
|
<span class="mdl-layout-title">Lint Report: 9 errors and 98 warnings</span>
|
||||||
|
Loading…
Reference in New Issue
Block a user