mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-21 04:29:45 +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:theme="@style/AppTheme" />
|
||||
|
||||
<activity android:name=".contacts.ContactsActivityCompose"
|
||||
<activity android:name=".contacts.ContactsActivity"
|
||||
android:theme="@style/AppTheme"/>
|
||||
|
||||
<activity android:name=".conversationcreation.ConversationCreationActivity"
|
||||
@ -246,10 +246,6 @@
|
||||
android:name=".conversationinfoedit.ConversationInfoEditActivity"
|
||||
android:theme="@style/AppTheme" />
|
||||
|
||||
<activity
|
||||
android:name=".contacts.ContactsActivity"
|
||||
android:theme="@style/AppTheme" />
|
||||
|
||||
<activity
|
||||
android:name=".openconversations.ListOpenConversationsActivity"
|
||||
android:theme="@style/AppTheme" />
|
||||
|
@ -1,900 +1,83 @@
|
||||
/*
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2022 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* SPDX-FileCopyrightText: 2022 Marcel Hibbe <dev@mhibbe.de>
|
||||
* SPDX-FileCopyrightText: 2017 Mario Danic <mario@lovelyhq.com>
|
||||
* 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.app.SearchManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.text.InputType
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
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 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.bluelinelabs.logansquare.LoganSquare
|
||||
import com.nextcloud.talk.R
|
||||
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.chat.ChatActivity
|
||||
import com.nextcloud.talk.conversation.CreateConversationDialogFragment
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
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.contacts.CompanionClass.Companion.KEY_HIDE_ALREADY_EXISTING_PARTICIPANTS
|
||||
import com.nextcloud.talk.extensions.getParcelableArrayListExtraProvider
|
||||
import com.nextcloud.talk.components.SetupSystemBars
|
||||
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 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
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class ContactsActivity :
|
||||
BaseActivity(),
|
||||
SearchView.OnQueryTextListener,
|
||||
FlexibleAdapter.OnItemClickListener {
|
||||
private lateinit var binding: ActivityContactsBinding
|
||||
class ContactsActivity : BaseActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var userManager: UserManager
|
||||
|
||||
@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
|
||||
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)
|
||||
|
||||
binding = ActivityContactsBinding.inflate(layoutInflater)
|
||||
setupActionBar()
|
||||
setContentView(binding.root)
|
||||
setupSystemColors()
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
if (adapter != null) {
|
||||
adapter?.onRestoreInstanceState(savedInstanceState)
|
||||
}
|
||||
}
|
||||
|
||||
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 = ViewModelProvider(this, viewModelFactory)[ContactsViewModel::class.java]
|
||||
setContent {
|
||||
val isAddParticipants = intent.getBooleanExtra(BundleKeys.KEY_ADD_PARTICIPANTS, false)
|
||||
val hideAlreadyAddedParticipants = intent.getBooleanExtra(KEY_HIDE_ALREADY_EXISTING_PARTICIPANTS, false)
|
||||
contactsViewModel.updateIsAddParticipants(isAddParticipants)
|
||||
contactsViewModel.hideAlreadyAddedParticipants(hideAlreadyAddedParticipants)
|
||||
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()
|
||||
|
||||
finish()
|
||||
}
|
||||
val selectedParticipants = remember {
|
||||
intent?.getParcelableArrayListExtraProvider<AutocompleteUser>("selectedParticipants")
|
||||
?: emptyList()
|
||||
}.toSet().toMutableList()
|
||||
contactsViewModel.updateSelectedParticipants(selectedParticipants)
|
||||
|
||||
WorkInfo.State.FAILED -> {
|
||||
Log.d(TAG, "failed AddParticipantsToConversation")
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme
|
||||
) {
|
||||
// groups
|
||||
shareTypesList.add("1")
|
||||
// emails
|
||||
shareTypesList.add("4")
|
||||
}
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(
|
||||
currentUser?.capabilities?.spreedCapability!!,
|
||||
SpreedFeatures.CIRCLES_SUPPORT
|
||||
ContactsScreen(
|
||||
contactsViewModel = contactsViewModel,
|
||||
uiState = uiState.value
|
||||
)
|
||||
) {
|
||||
// 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)
|
||||
|
||||
userHeaderItems = HashMap()
|
||||
// getting the contact list from the endpoints.
|
||||
contactItems!!.addAll(newUserItemList)
|
||||
|
||||
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
|
||||
SetupSystemBars()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
class CompanionClass {
|
||||
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
|
||||
internal val TAG = ContactsActivity::class.simpleName
|
||||
internal const val ROOM_TYPE_ONE_ONE = "1"
|
||||
const val KEY_HIDE_ALREADY_EXISTING_PARTICIPANTS: String = "KEY_HIDE_ALREADY_EXISTING_PARTICIPANTS"
|
||||
}
|
||||
}
|
||||
|
@ -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.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
@ -26,8 +25,6 @@ import com.nextcloud.talk.contacts.components.ConversationCreationOptions
|
||||
|
||||
@Composable
|
||||
fun ContactsScreen(contactsViewModel: ContactsViewModel, uiState: ContactsUiState) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val searchQuery by contactsViewModel.searchQuery.collectAsStateWithLifecycle()
|
||||
val isSearchActive by contactsViewModel.isSearchActive.collectAsStateWithLifecycle()
|
||||
val isAddParticipants by contactsViewModel.isAddParticipantsView.collectAsStateWithLifecycle()
|
||||
@ -57,17 +54,17 @@ fun ContactsScreen(contactsViewModel: ContactsViewModel, uiState: ContactsUiStat
|
||||
},
|
||||
content = {
|
||||
Column(
|
||||
Modifier.padding(it)
|
||||
Modifier
|
||||
.padding(it)
|
||||
.background(colorResource(id = R.color.bg_default))
|
||||
) {
|
||||
ConversationCreationOptions(
|
||||
context = context,
|
||||
contactsViewModel = contactsViewModel
|
||||
)
|
||||
if (!isAddParticipants) {
|
||||
ConversationCreationOptions()
|
||||
}
|
||||
|
||||
ContactsList(
|
||||
contactsUiState = uiState,
|
||||
contactsViewModel = contactsViewModel,
|
||||
context = context
|
||||
contactsViewModel = contactsViewModel
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ class ContactsViewModel @Inject constructor(
|
||||
private val _isAddParticipantsView = MutableStateFlow(false)
|
||||
val isAddParticipantsView: StateFlow<Boolean> = _isAddParticipantsView
|
||||
|
||||
private var hideAlreadyAddedParticipants: Boolean = false
|
||||
|
||||
init {
|
||||
getContactsFromSearchParams()
|
||||
}
|
||||
@ -69,6 +71,10 @@ class ContactsViewModel @Inject constructor(
|
||||
_isAddParticipantsView.value = value
|
||||
}
|
||||
|
||||
fun hideAlreadyAddedParticipants(value: Boolean) {
|
||||
hideAlreadyAddedParticipants = value
|
||||
}
|
||||
|
||||
@Suppress("Detekt.TooGenericExceptionCaught")
|
||||
fun getContactsFromSearchParams() {
|
||||
_contactsViewState.value = ContactsUiState.Loading
|
||||
@ -78,7 +84,12 @@ class ContactsViewModel @Inject constructor(
|
||||
searchQuery.value,
|
||||
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)
|
||||
} catch (exception: Exception) {
|
||||
_contactsViewState.value = ContactsUiState.Error(exception.message ?: "")
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
package com.nextcloud.talk.contacts.components
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@ -18,15 +17,18 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.nextcloud.talk.contacts.CompanionClass
|
||||
import com.nextcloud.talk.contacts.ContactsUiState
|
||||
import com.nextcloud.talk.contacts.ContactsViewModel
|
||||
|
||||
@Composable
|
||||
fun ContactsList(contactsUiState: ContactsUiState, contactsViewModel: ContactsViewModel, context: Context) {
|
||||
fun ContactsList(contactsUiState: ContactsUiState, contactsViewModel: ContactsViewModel) {
|
||||
val context = LocalContext.current
|
||||
when (contactsUiState) {
|
||||
is ContactsUiState.None -> {
|
||||
}
|
||||
|
||||
is ContactsUiState.Loading -> {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
@ -35,6 +37,7 @@ fun ContactsList(contactsUiState: ContactsUiState, contactsViewModel: ContactsVi
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
}
|
||||
|
||||
is ContactsUiState.Success -> {
|
||||
val contacts = contactsUiState.contacts
|
||||
Log.d(CompanionClass.TAG, "Contacts:$contacts")
|
||||
@ -42,6 +45,7 @@ fun ContactsList(contactsUiState: ContactsUiState, contactsViewModel: ContactsVi
|
||||
ContactsItem(contacts, contactsViewModel, context)
|
||||
}
|
||||
}
|
||||
|
||||
is ContactsUiState.Error -> {
|
||||
val errorMessage = contactsUiState.message
|
||||
Box(
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
package com.nextcloud.talk.contacts.components
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.compose.foundation.clickable
|
||||
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.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.contacts.ContactsViewModel
|
||||
import com.nextcloud.talk.conversationcreation.ConversationCreationActivity
|
||||
import com.nextcloud.talk.openconversations.ListOpenConversationsActivity
|
||||
|
||||
@Composable
|
||||
fun ConversationCreationOptions(context: Context, contactsViewModel: ContactsViewModel) {
|
||||
val isAddParticipants by contactsViewModel.isAddParticipantsView.collectAsState()
|
||||
if (!isAddParticipants) {
|
||||
fun ConversationCreationOptions() {
|
||||
val context = LocalContext.current
|
||||
Column {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
@ -94,4 +90,3 @@ 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.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.chat.ChatActivity
|
||||
import com.nextcloud.talk.contacts.ContactsActivity
|
||||
import com.nextcloud.talk.components.SetupSystemBars
|
||||
import com.nextcloud.talk.contacts.ContactsActivityCompose
|
||||
import com.nextcloud.talk.contacts.loadImage
|
||||
import com.nextcloud.talk.extensions.getParcelableArrayListExtraProvider
|
||||
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
|
||||
import com.nextcloud.talk.utils.CapabilitiesUtil
|
||||
import com.nextcloud.talk.utils.PickImage
|
||||
@ -163,7 +164,7 @@ fun ConversationCreationScreen(
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
val data = result.data
|
||||
val selectedParticipants =
|
||||
data?.getParcelableArrayListExtra<AutocompleteUser>("selectedParticipants")
|
||||
data?.getParcelableArrayListExtraProvider<AutocompleteUser>("selectedParticipants")
|
||||
?: emptyList()
|
||||
val participants = selectedParticipants.toMutableList()
|
||||
conversationCreationViewModel.updateSelectedParticipants(participants)
|
||||
@ -378,12 +379,12 @@ fun AddParticipants(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, bottom = 16.dp)
|
||||
.clickable {
|
||||
val intent = Intent(context, ContactsActivityCompose::class.java)
|
||||
val intent = Intent(context, ContactsActivity::class.java)
|
||||
intent.putParcelableArrayListExtra(
|
||||
"selectedParticipants",
|
||||
participants as ArrayList<AutocompleteUser>
|
||||
)
|
||||
intent.putExtra("isAddParticipants", true)
|
||||
intent.putExtra(BundleKeys.KEY_ADD_PARTICIPANTS, true)
|
||||
intent.putExtra("isAddParticipantsEdit", true)
|
||||
launcher.launch(intent)
|
||||
},
|
||||
@ -416,8 +417,8 @@ fun AddParticipants(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
val intent = Intent(context, ContactsActivityCompose::class.java)
|
||||
intent.putExtra("isAddParticipants", true)
|
||||
val intent = Intent(context, ContactsActivity::class.java)
|
||||
intent.putExtra(BundleKeys.KEY_ADD_PARTICIPANTS, true)
|
||||
launcher.launch(intent)
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
@ -608,7 +609,8 @@ fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: Con
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
|
@ -11,6 +11,7 @@
|
||||
package com.nextcloud.talk.conversationinfo
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
@ -21,6 +22,8 @@ import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import androidx.activity.result.ActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
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.bottomsheet.items.BasicListItemWithImage
|
||||
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.conversationinfo.viewmodel.ConversationInfoViewModel
|
||||
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.DialogBanParticipantBinding
|
||||
import com.nextcloud.talk.events.EventStatus
|
||||
import com.nextcloud.talk.extensions.getParcelableArrayListExtraProvider
|
||||
import com.nextcloud.talk.extensions.loadConversationAvatar
|
||||
import com.nextcloud.talk.extensions.loadNoteToSelfAvatar
|
||||
import com.nextcloud.talk.extensions.loadSystemAvatar
|
||||
import com.nextcloud.talk.extensions.loadUserAvatar
|
||||
import com.nextcloud.talk.jobs.AddParticipantsToConversation
|
||||
import com.nextcloud.talk.jobs.DeleteConversationWorker
|
||||
import com.nextcloud.talk.jobs.LeaveConversationWorker
|
||||
import com.nextcloud.talk.models.domain.ConversationModel
|
||||
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.conversations.ConversationEnums
|
||||
import com.nextcloud.talk.models.json.converters.EnumActorTypeConverter
|
||||
@ -126,12 +134,9 @@ class ConversationInfoActivity :
|
||||
private lateinit var conversationUser: User
|
||||
private var hasAvatarSpacing: Boolean = false
|
||||
private lateinit var credentials: String
|
||||
private var roomDisposable: Disposable? = null
|
||||
private var participantsDisposable: Disposable? = null
|
||||
|
||||
private var databaseStorageModule: DatabaseStorageModule? = null
|
||||
|
||||
// private var conversation: Conversation? = null
|
||||
private var conversation: ConversationModel? = null
|
||||
|
||||
private var adapter: FlexibleAdapter<ParticipantItem>? = null
|
||||
@ -147,10 +152,21 @@ class ConversationInfoActivity :
|
||||
data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, conversationUser.id!!)
|
||||
return data.build()
|
||||
}
|
||||
|
||||
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?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||
@ -190,7 +206,7 @@ class ConversationInfoActivity :
|
||||
binding.deleteConversationAction.setOnClickListener { showDeleteConversationDialog() }
|
||||
binding.leaveConversationAction.setOnClickListener { leaveConversation() }
|
||||
binding.clearConversationHistory.setOnClickListener { showClearHistoryDialog() }
|
||||
binding.addParticipantsAction.setOnClickListener { addParticipants() }
|
||||
binding.addParticipantsAction.setOnClickListener { selectParticipantsToAdd() }
|
||||
binding.listBansButton.setOnClickListener { listBans() }
|
||||
|
||||
viewModel.getRoom(conversationUser, conversationToken)
|
||||
@ -237,9 +253,11 @@ class ConversationInfoActivity :
|
||||
when (state) {
|
||||
is ConversationInfoViewModel.SetConversationReadOnlyViewState.Success -> {
|
||||
}
|
||||
|
||||
is ConversationInfoViewModel.SetConversationReadOnlyViewState.Error -> {
|
||||
Snackbar.make(binding.root, R.string.conversation_read_only_failed, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
is ConversationInfoViewModel.SetConversationReadOnlyViewState.None -> {
|
||||
}
|
||||
}
|
||||
@ -249,6 +267,7 @@ class ConversationInfoActivity :
|
||||
when (uiState) {
|
||||
is ConversationInfoViewModel.ClearChatHistoryViewState.None -> {
|
||||
}
|
||||
|
||||
is ConversationInfoViewModel.ClearChatHistoryViewState.Success -> {
|
||||
Snackbar.make(
|
||||
binding.root,
|
||||
@ -256,6 +275,7 @@ class ConversationInfoActivity :
|
||||
Snackbar.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
|
||||
is ConversationInfoViewModel.ClearChatHistoryViewState.Error -> {
|
||||
Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
|
||||
Log.e(TAG, "failed to clear chat history", uiState.exception)
|
||||
@ -319,7 +339,7 @@ class ConversationInfoActivity :
|
||||
fun showOptionsMenu() {
|
||||
if (::optionsMenu.isInitialized) {
|
||||
optionsMenu.clear()
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.AVATAR)) {
|
||||
if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.AVATAR)) {
|
||||
menuInflater.inflate(R.menu.menu_conversation_info, optionsMenu)
|
||||
}
|
||||
}
|
||||
@ -383,7 +403,7 @@ class ConversationInfoActivity :
|
||||
}
|
||||
|
||||
private fun setupWebinaryView() {
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.WEBINARY_LOBBY) &&
|
||||
if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.WEBINARY_LOBBY) &&
|
||||
webinaryRoomType(conversation!!) &&
|
||||
ConversationUtils.canModerate(conversation!!, spreedCapabilities)
|
||||
) {
|
||||
@ -652,23 +672,89 @@ class ConversationInfoActivity :
|
||||
.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 existingParticipantsId = arrayListOf<String>()
|
||||
val existingParticipants = ArrayList<AutocompleteUser>()
|
||||
|
||||
for (userItem in userItems) {
|
||||
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.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)
|
||||
|
||||
val intent = Intent(this, ContactsActivity::class.java)
|
||||
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() {
|
||||
@ -693,6 +779,7 @@ class ConversationInfoActivity :
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
WorkInfo.State.FAILED -> {
|
||||
val errorType = workInfo.outputData.getString("error_type")
|
||||
if (errorType == LeaveConversationWorker.ERROR_NO_OTHER_MODERATORS_OR_OWNERS_LEFT) {
|
||||
@ -709,6 +796,7 @@ class ConversationInfoActivity :
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
@ -769,7 +857,7 @@ class ConversationInfoActivity :
|
||||
|
||||
setUpNotificationSettings(databaseStorageModule!!)
|
||||
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.RICH_OBJECT_LIST_MEDIA) &&
|
||||
if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.RICH_OBJECT_LIST_MEDIA) &&
|
||||
conversationCopy.remoteServer.isNullOrEmpty()
|
||||
) {
|
||||
binding.sharedItemsButton.setOnClickListener { showSharedItems() }
|
||||
@ -779,7 +867,7 @@ class ConversationInfoActivity :
|
||||
|
||||
if (ConversationUtils.canModerate(conversationCopy, spreedCapabilities)) {
|
||||
binding.addParticipantsAction.visibility = VISIBLE
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(
|
||||
if (hasSpreedFeatureCapability(
|
||||
spreedCapabilities,
|
||||
SpreedFeatures.CLEAR_HISTORY
|
||||
) && conversationCopy.canDeleteConversation
|
||||
@ -1011,7 +1099,7 @@ class ConversationInfoActivity :
|
||||
|
||||
private fun initExpiringMessageOption() {
|
||||
if (ConversationUtils.isParticipantOwnerOrModerator(conversation!!) &&
|
||||
CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MESSAGE_EXPIRATION)
|
||||
hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MESSAGE_EXPIRATION)
|
||||
) {
|
||||
databaseStorageModule?.setMessageExpiration(conversation!!.messageExpiration)
|
||||
val value = databaseStorageModule!!.getString("conversation_settings_dropdown", "")
|
||||
@ -1034,7 +1122,7 @@ class ConversationInfoActivity :
|
||||
|
||||
private fun adjustNotificationLevelUI() {
|
||||
if (conversation != null) {
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.NOTIFICATION_LEVELS)) {
|
||||
if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.NOTIFICATION_LEVELS)) {
|
||||
binding.notificationSettingsView.conversationInfoMessageNotificationsDropdown.isEnabled = true
|
||||
binding.notificationSettingsView.conversationInfoMessageNotificationsDropdown.alpha = 1.0f
|
||||
|
||||
@ -1069,7 +1157,7 @@ class ConversationInfoActivity :
|
||||
|
||||
private fun setProperNotificationValue(conversation: ConversationModel?) {
|
||||
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(
|
||||
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.chat.ChatActivity
|
||||
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.ContactsViewModel
|
||||
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_TEXT
|
||||
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_SCROLL_TO_NOTIFICATION_CATEGORY
|
||||
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
|
||||
|
||||
private fun showNewConversationsScreen() {
|
||||
val intent = Intent(context, ContactsActivityCompose::class.java)
|
||||
intent.putExtra(KEY_NEW_CONVERSATION, true)
|
||||
val intent = Intent(context, ContactsActivity::class.java)
|
||||
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="colorBackgroundDarker">#2C2C2C</color>
|
||||
|
||||
<!-- Chat window incoming message text & informational -->
|
||||
<color name="bg_bottom_sheet">#121212</color>
|
||||
<color name="bg_message_list_incoming_bubble">#2A2A2A</color>
|
||||
|
@ -53,7 +53,6 @@
|
||||
<color name="call_incomingCallTextView">#E9FFFFFF</color>
|
||||
<color name="grey950">#111111</color>
|
||||
<color name="textColorMaxContrast">#767676</color>
|
||||
<color name="colorBackgroundDarker">#DBDBDB</color>
|
||||
|
||||
<color name="fg_default">#666666</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_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_unread">Mark as unread</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>
|
||||
|
||||
<!-- Contacts -->
|
||||
<string name="nc_select_participants">Select participants</string>
|
||||
<string name="nc_add_participants">Add participants</string>
|
||||
<string name="nc_contacts_done">Done</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_nick_guest">Guest</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_reconnecting">Reconnecting …</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_participants">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_moderator">Moderator</string>
|
||||
|
@ -1,2 +1,2 @@
|
||||
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